chxavfilestore.cpp

来自「著名的 helix realplayer 基于手机 symbian 系统的 播放」· C++ 代码 · 共 1,202 行 · 第 1/3 页

CPP
1,202
字号
/************************************************************************
 * chxavfilestore.cpp
 * ------------------
 *
 * Synopsis:
 * simple file system abstraction for manipulating files and folders;
 * maintains 'root' (relative to true filesystem) 'current' folder
 * state
 *
 * root path is stored in full form, e.g.: c:\real\media\
 * folder is stored in relative form, fully specified, e.g.:
 *	\	    = root
 *	\music\     = subfolder music
 *
 * the term 'item' (as used in this class) refers to a file or folder
 * that is in the current entry list; the entry list contains a list
 * of files and folders within the current folder
 *
 * Target:
 * Symbian OS
 *
 *
 * (c) 1995-2003 RealNetworks, Inc. Patents pending. All rights reserved.
 *
 ************************************************************************/

// Symbian includes...
#include <coeutils.h>
#include <eikfutil.h>
#include <f32file.h> // TSwitch, CFileMan

// Helix includes...

// Include from this project...
#include "chxavfilestore.h"
#include "chxavdirectoryreader.h"
#include "chxavfileutil.h"
#include "chxavutil.h"
#include "chxavmisc.h"
#include "chxavstringutils.h"
#include "hxsym_leaveutil.h"
#include "hxsym_debug.h"


CHXAvFileStore::CHXAvFileStore()
: m_pFullPath(0)
, m_bNeedRefresh(true)
, m_pFileMan(0)
, m_pObserver(0)
, m_cbFileOp(0)
, m_suspendRefreshSem(0)
, m_bHaveOutstandingFileSystemEvent(false)
{
}

CHXAvFileStore::~CHXAvFileStore()
{
    HX_DELETE(m_pFullPath);
    HX_DELETE(m_pFileMan);
#if defined(ASYNC_COPYMOVE)
    CancelAsyncFileOp();
#endif
    m_apaLsSess.Close();
}

////////////////////////////////////////////////////////////
//
void CHXAvFileStore::ConstructL(const TDesC& root,
                             const TDesC& path,
                             bool bAutoCreateRoot)
{
    m_apaLsSess.Connect();
    m_fsWatcher.ConstructL();

     // set callback for receiving fs event notifications
    m_fsWatcher.SetEventActionL
	(
	MakeCommand(this, &CHXAvFileStore::OnFileSystemEvent)
	);


#if defined(ASYNC_COPYMOVE)
    // active object to run on asynch completion of file op
    m_pFileOpCompletion =
	new (ELeave) CHXAvActiveDisp<CHXAvFileStore>(this,
				    &CHXAvFileStore::OnFileOpAsyncComplete,
				    &CHXAvFileStore::OnFileOpAsyncCancel);
    CActiveScheduler::Add(m_pFileOpCompletion.raw_ptr());
#endif

    // create, fill out and activate the listbox
    SetRootL(root, bAutoCreateRoot);
    SetCurrentPathL(path);
    RefreshEntryInfoL();

    RFs& fs = CCoeEnv::Static()->FsSession();
    m_pFileMan = CFileMan::NewL(fs, this /*observer*/);
}

////////////////////////////////////////////////////////////
// paths can be provided as relative to root (e.g., /media/myfolder/foo.rm)
// or absolute ('e:/videos/)
//
// this decides which and returns a fully specified path with drive
//
//
TFileName* CHXAvFileStore::AllocFullPathL(const TDesC& path,
                                       const TDesC& name,
                                       CHXAvFile::NameType type)
{
    TFileName* pPath = 0;
    TInt idxDrive = CHXAvFile::GetDriveIndex(path);
    if(-1 != idxDrive)
    {
        // path has a drive; it is absolute
        pPath = CHXAvFile::AllocFileNameL(path, name, type);
    }
    else
    {
        // path is relative
        pPath = CHXAvFile::AllocFileNameL(GetRoot(), path, CHXAvFile::ntFolder);
        CHXAvFile::AppendPath(*pPath, name, type);
    }


    return pPath;
}

//////////////////////////////////////////////////////////////
// return true if fullPathChild is path to file or folder immediately
// under current path
bool CHXAvFileStore::IsImmediateChild(const TDesC& fullPathChild)
{
    TPtrC ptrFolder = CHXAvFile::GetParentFolder(fullPathChild);
    return (0 == ptrFolder.CompareF(*m_pFullPath));
}

//////////////////////////////////////////////////////////////
// return true if fullPathParent is a parent of the current
//
bool CHXAvFileStore::IsParent(const TDesC& fullPathParent)
{
    return  CHXAvFile::IsSubPath(fullPathParent, *m_pFullPath);
}

////////////////////////////////////////////////////////////
// return true if the destination path matches the
// path for the given item within the current path
//
// pathDest         - relative or absolute path
// idxItem          - item in current path
//
bool CHXAvFileStore::IsSamePathL(const TDesC& pathDest, TInt idxItem)
{
    bool bIsSame = false;

    // form "pathdest" + "name associated with item in current path"
    TFileName* pSrcPath = AllocFullPathL(idxItem);
    AUTO_PUSH_POP_DEL(pSrcPath);

    TFileName* pDestPath = AllocFullTargetPathL(pathDest, idxItem);
    AUTO_PUSH_POP_DEL(pDestPath);
    bIsSame = ( pSrcPath->CompareF(*pDestPath) == 0 );

    return bIsSame;
}

////////////////////////////////////////////////////////////
// called when fs watcher detects an event
void CHXAvFileStore::OnFileSystemEvent()
{
    DPRINTF(SYMP_FILE, ("FileStore::OnFileSystemEvent(): suspend count = %ld\n", m_suspendRefreshSem));

    // flag that entry list is out of data
    m_bNeedRefresh = true;

    if(m_suspendRefreshSem > 0)
    {
       // keep track of fact that we got file system event while locked; we'll defer
       // notifying observer until we become unlocked
       m_bHaveOutstandingFileSystemEvent = true;
    }
    else
    {
        m_bHaveOutstandingFileSystemEvent = false;
        m_eventHandler.Execute();
    }
   
}


////////////////////////////////////////////////////////////
// path must be fully qualified absolute root path, e.g., something like:
//
// 'e:\realnetworks\media\'
// 'c:\media\'
//
// * trailing slash required
// * drive letter required
//
// can be called more than once
//
void CHXAvFileStore::SetRootL(const TDesC& path, bool bAutoCreateRoot)
{
    RFs& fs = CCoeEnv::Static()->FsSession();

    TInt idxDrive = CHXAvFile::GetDriveIndex(path);

    if(idxDrive == -1 || !CHXAvFile::HasFolderSuffix(path))
    {
        // caller should ensure path suffix and valid drive
        HXSYM_LEAVE(KErrBadName);
    }

    TInt errExist = KErrPathNotFound;
    if( bAutoCreateRoot )
    {
        TRAP(errExist, BaflUtils::EnsurePathExistsL(fs, path));
    }
    else if(BaflUtils::PathExists(fs, path))
    {
        errExist = KErrNone;
    }

    // make sure root is valid by now
    HXSYM_LEAVE_IF_ERR(errExist);  // drive doesn't exist?

    TFileName* pFullPath = new (ELeave) TFileName;
    AUTO_PUSH_POP_DEL(pFullPath);
    HXSYM_LEAVE_IF_ERR(CHXAvFile::GetFullPath(fs, path, *pFullPath));
    m_root.Set(*pFullPath, 0, 0);

    UpdateFullPathL();
    HX_ASSERT(CHXAvFile::HasFolderSuffix(m_root.FullName()));

    // watch for fs events; this resets watch path if we were watching previously
    if( m_root.FullName().Length() > 3 )
    {
	m_fsWatcher.SetWatchPathL(m_root.FullName());
    }
    else
    {
        //
        // specifying a root drive path like 'c:\' fails for some reason so watch
        // everything in this case
        //
        m_fsWatcher.SetWatchPathL(KNullDesC);
    }
    m_fsWatcher.SetNotifyType(TNotifyType(ENotifyDir | ENotifyFile | ENotifyEntry));
    m_fsWatcher.StartWatching();

    m_bNeedRefresh = true;
}



////////////////////////////////////////////
// path             -  relative to current root path;
//                     leading and trailing path delimiter is optional
//
//
void CHXAvFileStore::SetCurrentPathL(const TDesC& path)
{
    // we want to make sure it looks like '/folder/'
    m_curPath.SetLength(0);
    CHXAvFile::AppendPath(m_curPath, path, CHXAvFile::ntFolder);

    DPRINTF(SYMP_FILE, ("FileStore::SetCurrentPathL(): current path '%s'\n", dbg::CharPtr(path)()));

    TInt err = EikFileUtils::CheckFolder(UpdateFullPathL());
    HXSYM_LEAVE_IF_ERR(err); // leave if path not found
    
    m_bNeedRefresh = true;
    HX_ASSERT(CHXAvFile::HasFolderPrefix(m_curPath));
    HX_ASSERT(CHXAvFile::HasFolderSuffix(m_curPath));
}

////////////////////////////////////////////////////////////
// make sure full path refers to current folder
const TDesC& CHXAvFileStore::UpdateFullPathL()
{
    // alloc fully qualified folder base path
    if(!m_pFullPath)
    {
	m_pFullPath = CHXAvFile::AllocFileNameL(m_root.FullName(), m_curPath, CHXAvFile::ntFolder);
    }
    else
    {
	m_pFullPath->Copy(m_root.FullName());
	CHXAvFile::AppendPath(*m_pFullPath, m_curPath, CHXAvFile::ntFolder);
    }

    return *m_pFullPath;
}

////////////////////////////////////////////
// count files (not folders) in the in the
// current entries list
TInt CHXAvFileStore::GetCurrentFolderFileCount() const
{
    TInt itemCount = m_entryInfo.Nelements();
    TInt fileCount = 0;
    for(TInt idx = 0; idx < itemCount; ++idx)
    {
	if(!m_entryInfo[idx].m_entry.IsDir())
	{
	    ++fileCount;
	}
    }
    return fileCount;
}


////////////////////////////////////////////////////
// add relevant file entries to list info
//
void CHXAvFileStore::RefreshEntryInfoHelper(const CDir* pFiles, bool bIncludeFolders)
{
    HX_ASSERT(pFiles != 0);

    TInt count = pFiles->Count();
    for( TInt idx = 0; idx < count; ++idx )
    {
	const TEntry& entry = (*pFiles)[idx];

	// don't add special (system, hidden) files
	if(!CHXAvUtil::ShouldHideFromUser(entry)) //XXXLCM 'filter policy'
	{

	    // note: entry.iName is stripped, e.g., 'folder'
	    if(entry.IsDir() && bIncludeFolders)
	    {
	        // add directory
	        CHXAvUtil::Append(m_entryInfo, CHXAvFile::FileInfo(entry, CHXAvFile::ftFolder));
	    }
	    else
	    {
	        // only add filetypes that we can play(e.g., 'file.rm')
	        TFileName* pPath = CHXAvFile::AllocFileNameL(GetFullPath(),
						          entry.iName);
	        AUTO_PUSH_POP_DEL(pPath);

	        CHXAvFile::FileType type = CHXAvFile::GetFileType(*pPath);
	        if (CHXAvFile::IsNanoPlayerFileType(type)) //XXXLCM 'filter policy'
                {
		    CHXAvUtil::Append(m_entryInfo, CHXAvFile::FileInfo(entry, type));
                }

	    }
        }
    }
}


// for RefreshSuspenderL
void CHXAvFileStore::CleanupSuspendRefresh(TAny* p)
{
    CHXAvFileStore* pFs = reinterpret_cast<CHXAvFileStore*>(p);
    pFs->SuspendRefresh(false);
}

////////////////////////////////////////////////////////////
//
// Call with 'true' to temporarily prevent file and dir list updates as
// well as filesystem event notifications being forwarded. This
// 'locks' the file and dir entry lists so that any indexes associated with
// current lists that are held by client remain valid.
//
// Useful in cases where you are holding on to an index while, say,
// waiting for user input before acting on the index.
//
// An alternative is to use CopyEntriesL()
//
void CHXAvFileStore::SuspendRefresh(bool bSuspend)
{
    if( bSuspend )
    {
        ++m_suspendRefreshSem;
    }
    else
    {
        --m_suspendRefreshSem;
    }
    DPRINTF(SYMP_FILE, ("FileStore::SuspendRefresh('%s'): suspend count = %d\n", dbg::Bool(bSuspend), m_suspendRefreshSem));
    HX_ASSERT(m_suspendRefreshSem >= 0); // calls must be balanced
    
    if(0 == m_suspendRefreshSem)
    {
        DPRINTF(SYMP_FILE, ("FileStore::SuspendRefresh(): exiting suspend\n"));
        // we are no longer suspended; now we can forward deferred filesystem
        // event notifications to observes
        if( m_bHaveOutstandingFileSystemEvent )
        {
            DPRINTF(SYMP_FILE, ("FileStore::SuspendRefresh(): sending deferred file system event notification\n"));
            OnFileSystemEvent();
        }  
    }
}


////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?