📄 engine.cpp
字号:
_LIT(KBackupRegistrationFileName,"backup_registration.xml");
_LIT(KIniFileName,"SignedApp_0x20000462.ini");
_LIT(KExtensionGif,".gif");
_LIT(KExtensionWav,".wav");
_LIT(KExtension3gp,".3gp");
_LIT(KExtensionAvi,".avi");
void CAppEngine::BuildDirectoryListL(const TDesC& aPath)
//
// Get a list of the files and folders within the indicated folder
//
{
TParse parse;
parse.Set(KWildCardName,&aPath,NULL);
CDir *dirList;
User::LeaveIfError(iFs.GetDir(parse.FullName(),KEntryAttNormal|KEntryAttReadOnly|
KEntryAttHidden|KEntryAttSystem|KEntryAttDir,0,dirList));
// ensure some part of the app takes ownership of the dirList before we can leave later on
CleanupStack::PushL(dirList);
// create a new container to store the entries
RArray<TFolderEntry>* folderEntryList=new(ELeave)RArray<TFolderEntry>(8);
// not only do we need to ensure we delete the actual allocated Rarray
CleanupDeletePushL(folderEntryList);
// but we also have to ensure we call Close() before the delete to release any resources
CleanupClosePushL(*folderEntryList);
TInt i,count;
// see which of the original categories still remain - so we dont assign entries to
// categories that have now been deleted.
TAppCategoryIds existingIds[EAppCategoryLastItem];
for (i=0;i<EAppCategoryLastItem;i++)
existingIds[i]=EAppCategoryUnfiled;
count=CategoryListCount();
for (i=0;i<count;i++)
{
TInt catId=CategoryListAt(i).iCategoryId;
if (catId<EAppCategoryLastItem)
existingIds[catId]=(TAppCategoryIds)catId;
}
// add a set of entries to our new container
TFolderEntry entry;
count=dirList->Count();
for (i=0;i<count;i++)
{
// dont list our backup_registration or INI files = stop user causing possible issues
// if they attempt to delete them.
if (!(*dirList)[i].iName.CompareF(KBackupRegistrationFileName))
continue;
if (!(*dirList)[i].iName.CompareF(KIniFileName))
continue;
// construct a new entry
entry.Construct((*dirList)[i]);
// assign to default categories....
parse.Set(entry.EntryName(),&aPath,NULL);
if (!parse.Ext().CompareF(KExtensionGif))
entry.UpdateCategory(existingIds[EAppCategoryImage]);
if (!parse.Ext().CompareF(KExtensionWav))
entry.UpdateCategory(existingIds[EAppCategorySound]);
if (!parse.Ext().CompareF(KExtension3gp))
entry.UpdateCategory(existingIds[EAppCategoryVideo]);
if (!parse.Ext().CompareF(KExtensionAvi))
entry.UpdateCategory(existingIds[EAppCategoryVideo]);
// add to the new list of entries
folderEntryList->AppendL(entry);
}
// we need an index onto the entries to perform efficient processing
CArrayFixFlat<TInt>* index=BuildIndexL(folderEntryList,iCurrentCategory);
// now sort the array of TInts dependant on the content they refer to, in the current
// mode + ascending/descending order
TKeyEntryList key(folderEntryList,iSortType,iSortOrder);
index->Sort(key);
// replace any existing list with the new list
if (iFolderEntryList)
{
iFolderEntryList->Close();
delete(iFolderEntryList);
}
iFolderEntryList=folderEntryList;
// firstly the Cleanup stack item that calls close()
CleanupStack::Pop(folderEntryList);
// then the cleanup stack item that deletes the actual object
CleanupStack::Pop(folderEntryList);
// replace the index
delete(iFolderEntryIndex);
iFolderEntryIndex=index;
// we have a new list, display from the top, if there is a top item
iCurrentEntry=0;
LimitCurrentEntryVal();
// update the path our entries exist within now all constructed
iPath=aPath;
// whilst it may have been tempting to perform this immedately after the end of the loop above
// it is very important to match Push/Pops on the cleanup stack, so we simply defer to here
CleanupStack::PopAndDestroy(dirList);
// Perform a self test to verify our internal structure is still self consistent
__TEST_INVARIANT;
}
void CAppEngine::UpdateCurrentEntryL(const TFolderEntry& aUpdate)
//
// The current entry is being updated. Apply the changes. Update the index as appropriate.
// The expectation is that upon completion of this function the UI will return to a list view.
//
{
TFolderEntry& curEntry=EntryListAt(iFolderEntryIndex->At(iCurrentEntry));
TParse srcName;
srcName.Set(curEntry.EntryName(),&iPath,NULL);
TBool sortReqd=EFalse;
if (curEntry.EntryName()!=aUpdate.EntryName())
{ // names being changed
TParse destName;
destName.Set(aUpdate.EntryName(),&iPath,NULL);
// attempt to rename the file on disk
User::LeaveIfError(iFs.Rename(srcName.FullName(),destName.FullName()));
// now update the internal representation
curEntry.UpdateName(aUpdate.EntryName());
// whilst not strictly true in all circumstances, in majority of cases it is requried
// so we ignore a possible optimization here
sortReqd=ETrue;
}
if (curEntry.EntryModified()!=aUpdate.EntryModified())
{ // file last modification date being updated
User::LeaveIfError(iFs.SetModified(srcName.FullName(),aUpdate.EntryModified()));
// update the internal representation
curEntry.UpdateModified(aUpdate.EntryModified());
// modification dates only involved in EFolderEntrySortByModified sorts
// so we can optimize quite easily.
if (iSortType==EFolderEntrySortByModified)
sortReqd=ETrue;
}
if (curEntry.EntryCategory()!=aUpdate.EntryCategory())
{
// firstly update the category associated with the current item
TInt oldCategory=curEntry.EntryCategory();
curEntry.UpdateCategory(aUpdate.EntryCategory());
if (iCurrentCategory==oldCategory)
{ // the index shows items from the categry weve just left, remove our entry
iFolderEntryIndex->Delete(iCurrentEntry);
// ensure we are still referencing a valid entry within the index
LimitCurrentEntryVal();
}
// in our model it is not possible to move an entry from outside our category to within the
// current category - as its not possible to select such an item within the UI..
}
if (sortReqd)
SortEntries(iSortType,iSortOrder);
// Perform a self test to verify our internal structure is still self consistent
__TEST_INVARIANT;
}
void CAppEngine::AddEntryL(const TDesC& aName,const TInt aCategoryId)
//
// Add a new entry to the list of entries we know about
//
{
// firstly check that the category we propose the entry be added to still exists.
TInt catId=aCategoryId;
TInt i;
TInt count=CategoryListCount();
for (i=0;i<count;i++)
{
if (CategoryListAt(i).iCategoryId==catId)
break;
}
if (i==count) // the proposed category is missing, place in the unfiled category
catId=EAppCategoryUnfiled;
// create the new TFolderEntry, obtaining required info from the file stored on disk
TFolderEntry entry;
TEntry fileEntry;
User::LeaveIfError(iFs.Entry(aName,fileEntry));
entry.Construct(fileEntry);
// update the entry category to propsed one
entry.UpdateCategory(catId);
// now attempt to add the entry to our list of entries.
// firstly check to see if weve already got the same named entry in our list
count=EntryListCount();
for (i=0;i<count;i++)
{
TFolderEntry& existing=EntryListAt(i);
if (!entry.EntryName().CompareF(existing.EntryName()))
break;
}
if (i==count)
{ // cant find the entry - append this one
iFolderEntryList->AppendL(entry);
if (iCurrentCategory==EAppCategoryAll || iCurrentCategory==catId)
{ // we want to be able to see the entry as its in the currently chosen users list
// the index of the entry weve appended will be the value 'count'.
// since we always append to the iFolderEntryList, none of the other index values have
// to change.
TRAPD(err,
TKeyEntryList key(iFolderEntryList,iSortType,iSortOrder);
iCurrentEntry=iFolderEntryIndex->InsertIsqAllowDuplicatesL(count,key);
);
if (err!=KErrNone)
{ // roll back, remove the entry from the primary list
iFolderEntryList->Remove(count);
User::Leave(err);
}
}
}
else
{ // see if the entry currently displayed in the index, if so move hlight to that entry
TInt index=i;
count=iFolderEntryIndex->Count();
for (i=0;i<count;i++)
{
if (iFolderEntryIndex->At(i)==index)
{ // entry represented by 'index' is being displayed to the user...
iCurrentEntry=i;
break;
}
}
}
// Perform a self test to verify our internal structure is still self consistent
__TEST_INVARIANT;
}
TInt CAppEngine::EntryCount() const
//
// Report the number of entries visible to the UI = number of entries in our filtered list
//
{
return(iFolderEntryIndex->Count());
}
const TFolderEntry& CAppEngine::Entry(const TInt aIndex) const
//
// Report the aIndex'th entry visible to the UI.
//
{
return(EntryListAt(iFolderEntryIndex->At(aIndex)));
}
const TFolderEntry& CAppEngine::CurrentEntry() const
//
// Return the current TFolderEntry as visible to the UI
//
{
return(EntryListAt(iFolderEntryIndex->At(iCurrentEntry)));
}
void CAppEngine::LimitCurrentEntryVal()
// Limit the iCurrentEntry value so its within the valid range. Set to -1 if no entries left.
{
if (iCurrentEntry>=iFolderEntryIndex->Count())
iCurrentEntry--;
}
void CAppEngine::SetCurrentEntry(const TInt aIndex)
//
// Set the current entry to the aIndex'th entry visible to the UI.
// Note that its entirely possible for aIndex to be -ve (-1), e.g. if no
// entries in the currently filtered list.
//
{
__ASSERT_DEBUG(aIndex<iFolderEntryIndex->Count(),Panic(10));
iCurrentEntry=aIndex;
}
void CAppEngine::EntryFullName(TDes& aName)
// Report the full name of the currently selected entry
{
TParse parse;
parse.Set(CurrentEntry().EntryName(),&iPath,NULL);
aName=parse.FullName();
}
void CAppEngine::DeleteCurrentEntryL()
//
// Delete the current entry.
// i) remove from disk, ii) remove from internal representation of disk entry, iii) from index
//
{
// remove the file from the file store
TFileName name;
EntryFullName(name);
TInt err=iFs.Delete(name);
if (err!=KErrNotFound)
User::LeaveIfError(err);
// remove the entry from our list of all entries
TInt index=iFolderEntryIndex->At(iCurrentEntry);
iFolderEntryList->Remove(index);
// remove the entry from the index + adjust all index values so they take into account
// the fact that the iFolderEntryList contains one less entry. Any entries after the
// 'index' th entry have moved up the list.
iFolderEntryIndex->Delete(iCurrentEntry);
const TInt count=EntryCount();
for (TInt i=0;i<count;i++)
{
TInt val=iFolderEntryIndex->At(i);
if (val>=index)
(*iFolderEntryIndex)[i]=val-1;
}
// as an alternative to the above index updating we could have chosen to rebuild the entire
// index, however the above is significantly more efficient + no OOM to contend with.
// limit the current entry index to the existing entries
LimitCurrentEntryVal();
// Perform a self test to verify our internal structure is still self consistent
__TEST_INVARIANT;
}
void CAppEngine::SortEntries(const TFolderEntrySortType aSortType,const TFolderEntrySortOrder aOrder)
//
// Sort the current entries in the index into specified order
// The engine design explitly ensures that we can sort entries without leaving being possible. This
// is to ensure we can handle any UI rollback that may be required.
//
// We also track the current entry so when the UI displays the newly sorted list the selected item
// remains the same.
//
{
// as an optimization we could check to see if only the aOrder is varying. If so we can
// generate the sorted list by simply swapping all entries in our index - which is much faster
// than actually performing a sort. That is not implmented at this time.
// we want to track where the current entry has got to so when we return to the list view
// the hlight remains on the item that was changed...
TInt whichEntry=iFolderEntryIndex->At(iCurrentEntry);
TKeyEntryList key(iFolderEntryList,aSortType,aOrder);
iFolderEntryIndex->Sort(key);
iSortType=aSortType;
iSortOrder=aOrder;
// scan the index to locate the original entry, so we can determine the new iCurrentEntry
const TInt count=EntryCount();
for (TInt i=0;i<count;i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -