--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mpx/collectionframework/collectionengine/src/mpxcollectionclientcontext.cpp Thu Dec 17 08:55:47 2009 +0200
@@ -0,0 +1,2613 @@
+/*
+* 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 "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: Maintains sessions to paths
+*
+*/
+
+#include <badesca.h>
+#include <mpxcollectionpath.h>
+#include <mpxclientlist.h>
+#include <mpxcollectionplugin.h>
+#include <mpxcollectionpath.h>
+#include <mpxcollectionframeworkdefs.h>
+#include <mpxcollectioncommanddefs.h>
+#include <mpxcommonframeworkdefs.h>
+#include <mpxcmn.h>
+#include <mpxmedia.h>
+#include <mpxmediaarray.h>
+#include <mpxmediageneraldefs.h>
+#include <mpxmediacontainerdefs.h>
+#include <mpxmessagegeneraldefs.h>
+#include <mpxmessagecontainerdefs.h>
+#include <mpxcollectionmessage.h>
+#include <mpxcollectionmessagedefs.h>
+#include <mpxcommandgeneraldefs.h>
+#include <mpxcollectionopenlresultdef.h>
+#include <mpxcommand.h>
+#include <mpxlog.h>
+#include <mpxsubscription.h>
+#include "mpxcollectionengineobserver.h"
+#include "mpxcollectionpluginhandler.h"
+#include "mpxcollectionengine.h"
+#include "mpxcollectioncache.h"
+#include "mpxcollectionclientcontext.h"
+
+// ----------------------------------------------------------------------------
+// Helper. Sets next open mode on path
+// ----------------------------------------------------------------------------
+//
+LOCAL_C void SetPathOpenMode(CMPXCollectionPath& aPath, TInt aMode)
+ {
+ TMPXOpenMode mode=static_cast<TMPXOpenMode>(aMode);
+ if (aPath.Levels())
+ {
+ aPath.Set(mode == EMPXOpenDefault ? aPath.OpenPreviousMode() : mode);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Helper. Returns whether next open mode is the same as previous open
+// request
+// ----------------------------------------------------------------------------
+//
+LOCAL_C TBool OpenModeValid(const CMPXCollectionPath& aPath)
+ {
+ TMPXOpenMode next=aPath.OpenNextMode();
+ return (aPath.OpenPreviousMode() == next) || (next == EMPXOpenDefault);
+ }
+
+// ============================ MEMBER FUNCTIONS ==============================
+
+// ----------------------------------------------------------------------------
+// Two-phased constructor.
+// ----------------------------------------------------------------------------
+//
+CMPXCollectionClientContext* CMPXCollectionClientContext::NewL(
+ CMPXCollectionEngine& aEngine,
+ CMPXCollectionCache& aCache,
+ const TUid& aModeId)
+ {
+ CMPXCollectionClientContext* p =
+ new(ELeave) CMPXCollectionClientContext(aEngine, aCache, aModeId);
+ CleanupStack::PushL(p);
+ p->ConstructL();
+ CleanupStack::Pop(p);
+ return p;
+ }
+
+// ----------------------------------------------------------------------------
+// C++ constructor.
+// ----------------------------------------------------------------------------
+//
+CMPXCollectionClientContext::CMPXCollectionClientContext(
+ CMPXCollectionEngine& aEngine,
+ CMPXCollectionCache& aCache,
+ const TUid& aModeId)
+ : iModeId(aModeId),iFocusItemId(KMPXInvalidItemId),
+ iEngine(aEngine),iCache(aCache)
+ {
+ }
+
+// ----------------------------------------------------------------------------
+// 2nd phase constructor.
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::ConstructL()
+ {
+ iClientList = CMPXClientList::NewL();
+ iBrowsePath = CMPXCollectionPath::NewL();
+ iMedia = CMPXMedia::NewL(); // empty media
+ // initialize to null uid
+ for (TInt index = 0; index < EContextCount; ++index)
+ {
+ iPluginUids.AppendL(KNullUid);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Destructor
+// ----------------------------------------------------------------------------
+//
+CMPXCollectionClientContext::~CMPXCollectionClientContext()
+ {
+ MPX_DEBUG2("CMPXCollectionClientContext::~CMPXCollectionClientContext %08x",
+ this);
+
+ // Release all plugins this context has references on, this could result in the
+ // plugin(s) being unloaded.
+ for (TInt index = 0; index < EContextCount; ++index)
+ {
+ if (iPluginUids[index] != KNullUid)
+ {
+ iEngine.ReleasePlugin(iPluginUids[index]);
+ }
+ }
+
+ delete iClientList;
+ delete iBrowsePath;
+ delete iMediaPath;
+ delete iMedia;
+ delete iFilter;
+ iPluginUids.Close();
+ iUids.Close();
+ }
+
+// ----------------------------------------------------------------------------
+// Open collection by path
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::OpenL(
+ CMPXCollectionPath* aPath,
+ TInt aMode,
+ MMPXCollectionEngineObserver* aCallback)
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 1 <--");
+ MPX_ASSERT(aPath);
+ if (aPath->Levels() > 0)
+ {
+ // Increment the plugin reference count
+ CMPXCollectionPlugin*plugin = iEngine.ResolvePluginL(*aPath);
+ if (!plugin)
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 1 bad path plugin");
+ User::Leave(KErrArgument);
+ }
+
+ iEngine.CleanupPluginPushL(plugin);
+
+ // Ownership of aPath transferred
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 1 Add task");
+ plugin->AddTaskL(EMcsOpenPath, aCallback, this,
+ aMode, NULL, plugin, aPath);
+
+ // Pop the plugin
+ iEngine.PluginPop();
+ }
+ else
+ { // Go back to root level
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL restarting path");
+ iIndex=0;
+ iFocusItemId = KMPXInvalidItemId;
+ InitL(aCallback);
+ }
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 1 -->");
+ }
+
+// ----------------------------------------------------------------------------
+// Open collection by index
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::OpenL(
+ TInt aIndex,
+ TInt aMode,
+ const TArray<TMPXAttribute>& aAttrs,
+ MMPXCollectionEngineObserver* aCallback)
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 2 <--");
+ if (iBrowsePath->Levels()<=0)
+ {
+ User::Leave(KErrNotReady);
+ }
+ if (aIndex<0 || aIndex>=iBrowsePath->Count())
+ {
+ User::Leave(KErrArgument);
+ }
+ iBrowsePath->Set(aIndex);
+ // plugin not resolved yet
+ if (iPluginUids[EContextBrowse] == KNullUid)
+ {
+ // Increment the new plugin reference count, decrement the old.
+ // No need to push/release the plugin it is stored in a member
+ // variable and will be released when that is overwritten.
+ ResolvePluginL(*iBrowsePath, iPluginUids[EContextBrowse]);
+ }
+
+ if (iPluginUids[EContextBrowse] == KNullUid)
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 2 bad plugin");
+ User::Leave(KErrNotReady);
+ }
+
+ // add request to the queue
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 2 Add task");
+ iBrowsePath->SetL(aAttrs);
+ LoadedPlugin(EContextBrowse)->AddTaskL(EMcsOpenIndex, aCallback, this,
+ aIndex, NULL, (TAny*)aMode);
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 2 -->");
+ }
+
+// ----------------------------------------------------------------------------
+// Open collection by uids
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::OpenL(
+ const TArray<TUid>& aUids,
+ TInt aMode,
+ MMPXCollectionEngineObserver* aCallback)
+ {
+ // Update path for open request
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 3 <---");
+ SetPathOpenMode(*iBrowsePath,aMode);
+ if (!MPXUser::CompareOrderedUidArrays(iUids.Array(), aUids))
+ { // the same context
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 3 return Open");
+ aCallback->HandleOpen(iMedia, iIndex, ETrue, iMediaType);
+ }
+ else
+ { // go back to root level
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 3 Going to Root");
+ iUids.Reset();
+ ::CopyArrayL(aUids, iUids);
+ iIndex=0;
+ iFocusItemId = KMPXInvalidItemId;
+ InitL(aCallback);
+ }
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 3 --->");
+ }
+
+// ----------------------------------------------------------------------------
+// Request current content of browse context
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::OpenL(
+ TInt aMode,
+ MMPXCollectionEngineObserver* aCallback)
+ {
+ // Update path for open request
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 4 <---");
+ SetPathOpenMode(*iBrowsePath,aMode);
+ if (iPluginUids[EContextBrowse] == KNullUid)
+ {// No plug-in has been resolved
+ if (iBrowsePath->Levels() == 0)
+ //
+ // Open called at root level: just need to list the plug-ins,
+ // no need to resolve any plugin. Open request doesn't apply
+ // at this level
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 4 InitL()");
+ iIndex=0;
+ iFocusItemId = KMPXInvalidItemId;
+ InitL(aCallback);
+ }
+ else if (OpenModeValid(*iBrowsePath) && !iPathUpdated)
+ //
+ // The existing media is still valid (no change
+ // in the request for entries
+ //
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 4 return media");
+ aCallback->HandleOpen(iMedia,
+ iIndex, ETrue,
+ iMediaType);
+ }
+ else // Open mode has changed and open NOT called at root level
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 4 add task different open mode");
+ ResolvePluginL(*iBrowsePath, iPluginUids[EContextBrowse]); // Find a plug-in
+ if (iPluginUids[EContextBrowse] != KNullUid)
+ {
+ LoadedPlugin(EContextBrowse)->AddTaskL(EMcsOpen, aCallback, this);
+ }
+ }
+ }
+ else
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 4 add task");
+ LoadedPlugin(EContextBrowse)->AddTaskL(EMcsOpen, aCallback,this);
+ }
+ MPX_DEBUG1("CMPXCollectionClientContext::OpenL 4 --->");
+ }
+
+// ----------------------------------------------------------------------------
+// Media request by collection path
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::BackL(
+ MMPXCollectionEngineObserver* aCallback)
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::BackL()");
+ if (iPluginUids[EContextBrowse]==KNullUid)
+ {
+ User::Leave(KErrNotReady);
+ }
+
+ MPX_DEBUG1("CMPXCollectionClientContext::BackL() -- Add task");
+ LoadedPlugin(EContextBrowse)->AddTaskL(EMcsBack, aCallback, this);
+ }
+
+// ----------------------------------------------------------------------------
+// MediaL command
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::MediaL(
+ const CMPXCommand& aCmd,
+ MMPXCollectionEngineObserver* aCallback)
+ {
+ CMPXCollectionPath* path =
+ aCmd.ValueCObjectL<CMPXCollectionPath>(KMPXCommandGeneralTargetIds);
+ CleanupStack::PushL(path);
+
+ // Increment the plugin reference count
+ CMPXCollectionPlugin*plugin = iEngine.ResolvePluginL(*path);
+ if (!plugin)
+ {
+ User::Leave(KErrArgument);
+ }
+
+ iEngine.CleanupPluginPushL(plugin);
+
+ CMPXCommand* cmd = CMPXCommand::NewL(aCmd); // make a copy
+ CleanupStack::PushL(cmd);
+
+ plugin->AddTaskL(EMcsMediaByPath, aCallback, this,
+ 0, NULL, plugin, cmd, path);
+
+ CleanupStack::Pop(cmd); // Ownership transferred to the task queue
+ iEngine.PluginPop(); // Pop the plugin
+ CleanupStack::Pop(path);// Ownership transferred to the task queue
+ }
+
+// ----------------------------------------------------------------------------
+// Add a media
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::AddL(const CMPXMedia& aMedia)
+ {
+ DoUpdateMediaL( EMcsAddItem, aMedia );
+ }
+
+// ----------------------------------------------------------------------------
+// Remove a media
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::RemoveL(const CMPXMedia& aMedia)
+ {
+ DoUpdateMediaL( EMcsRemoveItem, aMedia );
+ }
+
+// ----------------------------------------------------------------------------
+// Update a media
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::SetL(const CMPXMedia& aMedia)
+ {
+ DoUpdateMediaL( EMcsSetMedia, aMedia );
+ }
+
+// ----------------------------------------------------------------------------
+// Remove media by path
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::RemoveL(
+ CMPXCollectionPath* aPath,
+ MMPXCollectionEngineObserver* aCallback)
+ {
+ TInt id(aPath->Id(CMPXCollectionPath::ECollectionUid));
+
+ // Increment the plugin reference count
+ CMPXCollectionPlugin* plugin = iEngine.ResolvePluginL(TUid::Uid(id));
+ if (!plugin)
+ {
+ User::Leave(KErrArgument);
+ }
+
+ iEngine.CleanupPluginPushL(plugin);
+
+ // Ownership of aPath transferred
+ plugin->AddTaskL(EMcsRemovePath, aCallback, this, 0, NULL, plugin, aPath);
+
+ iEngine.PluginPop();
+ }
+
+// ----------------------------------------------------------------------------
+// Return current plugin id
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TUid CMPXCollectionClientContext::PluginId() const
+ {
+ return iPluginUids[EContextBrowse];
+ }
+
+// ----------------------------------------------------------------------------
+// Handle async request from client
+// ----------------------------------------------------------------------------
+//
+EXPORT_C const CMPXCollectionPath& CMPXCollectionClientContext::Path() const
+ {
+ return *iBrowsePath;
+ }
+
+// ----------------------------------------------------------------------------
+// Cancel request
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::CancelRequest(
+ MMPXCollectionEngineObserver* aCallback)
+ {
+ MPX_DEBUG3("CMPXCollectionClientContext::CancelRequest, this %08x, aCallback %08x",
+ this, aCallback);
+ iEngine.RemoveTask(aCallback);
+ }
+
+// ----------------------------------------------------------------------------
+// Add a client
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::AddClientL(
+ TThreadId aId,
+ CMPXMessageQueue* aMsgQueue)
+ {
+ iClientList->AddClientL(aId, aMsgQueue);
+ }
+
+// ----------------------------------------------------------------------------
+// Remove a client
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::RemoveClient(
+ const CMPXMessageQueue& aMsgQueue)
+ {
+ MPX_DEBUG2("CMPXCollectionClientContext::RemoveClient with the message queue 0x%08x",
+ &aMsgQueue);
+ TInt index(iClientList->Find(aMsgQueue));
+ if (KErrNotFound != index)
+ {
+ iClientList->RemoveClient(index);
+ }
+ if (!iClientList->ClientCount())
+ {
+ iEngine.RemoveContext(*this);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Gets the supported capabilities of the current browse plugin
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TCollectionCapability CMPXCollectionClientContext::GetCapabilities()
+ {
+ TCollectionCapability cap(0);
+ if (iPluginUids[EContextBrowse]!=KNullUid)
+ {
+ LoadedPlugin(EContextBrowse)->GetCapabilities();
+ }
+ return cap;
+ }
+
+// ----------------------------------------------------------------------------
+// Find all aSync
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::FindAllL(
+ const CMPXMedia& aMedia,
+ CBufBase* aBuf,
+ MMPXCollectionEngineObserver* aCallback)
+ {
+ CMPXCollectionPlugin* plugin(NULL); // Not owned
+
+ // Increment the plugin reference count
+ ResolvePluginL(aMedia, plugin);
+ if (!plugin)
+ {
+ User::Leave(KErrNotFound); // found nothing
+ }
+
+ iEngine.CleanupPluginPushL(plugin);
+
+ // Add the task
+ CMPXMedia* media = CMPXMedia::NewL(aMedia);
+ CleanupStack::PushL(media);
+ plugin->AddTaskL(EMcsFindAll, aCallback, this, 0, aBuf, plugin, media);
+ CleanupStack::Pop(media); // Ownership transferred
+
+ iEngine.PluginPop();
+ }
+
+// ----------------------------------------------------------------------------
+// Find all sync
+// ----------------------------------------------------------------------------
+//
+EXPORT_C CMPXMedia* CMPXCollectionClientContext::FindAllSyncL(
+ const CMPXMedia& aMedia,
+ const CBufBase& aBuf)
+ {
+ CMPXCollectionPlugin* plugin(NULL); // Not owned
+
+ // Increment the plugin reference count
+ ResolvePluginL(aMedia, plugin);
+ iEngine.CleanupPluginPushL(plugin);
+
+ CMPXMedia* result(NULL);
+ FindAllL(aMedia, aBuf, *plugin, &result, ETrue);
+
+ // Synchronous call, safe to release the plugin
+ CleanupStack::PopAndDestroy(); // plugin
+ return result;
+ }
+
+// ----------------------------------------------------------------------------
+// Set filter
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::SetFilterL(const CMPXFilter* aFilter)
+ {
+ delete iFilter;
+ iFilter = NULL;
+ iFilter = aFilter ? CMPXFilter::NewL(*aFilter) : NULL;
+ }
+
+// ----------------------------------------------------------------------------
+// Returns filter
+// ----------------------------------------------------------------------------
+//
+EXPORT_C const CMPXFilter* CMPXCollectionClientContext::Filter() const
+ {
+ return iFilter;
+ }
+
+// ----------------------------------------------------------------------------
+// Handle a command
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::CommandL(
+ TMPXCollectionCommand aCmd,
+ TInt aData)
+ {
+ switch( aCmd )
+ {
+ case EMcCmdRemoveAll:
+ case EMcCmdReCreateDB: // fall through
+ case EMcCmdDbCorrupted: // fall through
+ {
+ TUid uid = TUid::Uid(aData);
+
+ // Increment the plugin reference count
+ CMPXCollectionPlugin* plugin = iEngine.ResolvePluginL( uid );
+ iEngine.CleanupPluginPushL(plugin);
+
+ if( plugin )
+ {
+ // The trap is needed to keep the plugin reference count in sync
+ plugin->CommandL(aCmd);
+ }
+
+ CleanupStack::PopAndDestroy(); // plugin
+ break;
+ }
+ case EMcCmdSelect:
+ if (iBrowsePath->Levels()<=0)
+ {
+ User::Leave(KErrNotReady);
+ }
+ if (aData<0 || aData>=iBrowsePath->Count())
+ {
+ User::Leave(KErrArgument);
+ }
+ iBrowsePath->Set(aData);
+ iClientList->SendMsgL(
+ TMPXCollectionMessage(TMPXCollectionMessage::EFocusChanged,
+ aData, aData));
+ iIndex = aData; // iIndex will always be up to date
+ iFocusItemId = iBrowsePath->Id();
+ break;
+ case EMcCmdCollectionInit:
+ case EMcCmdCollectionResyn:
+ {
+ TUid uid = TUid::Uid(aData);
+ // Increment the plugin reference count
+ CMPXCollectionPlugin* plugin = iEngine.ResolvePluginL(uid);
+ if( !plugin )
+ {
+ User::Leave(KErrArgument);
+ }
+
+ iEngine.CleanupPluginPushL(plugin);
+
+ plugin->AddTaskL(EMcsCommand, NULL, this, aCmd, NULL, plugin);
+
+ iEngine.PluginPop();
+ break;
+ }
+ default:
+ {
+ User::Leave(KErrNotSupported);
+ break;
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Handle a command
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXCollectionClientContext::CommandL(
+ const CMPXCommand& aCmd,
+ MMPXCollectionEngineObserver* aCallback,
+ const CMPXMessageQueue& aMsgQueue)
+ {
+ // Use the plugin id defined by the command object,
+ // or the browse context if collection id not defined
+ CMPXCollectionPlugin* plugin = NULL;
+ if (aCmd.IsSupported(KMPXCommandGeneralCollectionId))
+ {
+ TInt data = aCmd.ValueTObjectL<TInt>(KMPXCommandGeneralCollectionId);
+
+ // Increment the plugin reference count
+ plugin = iEngine.ResolvePluginL(TUid::Uid(data));
+ }
+ if (!plugin && iPluginUids[EContextBrowse]!=KNullUid)
+ {
+ plugin = LoadedPlugin(EContextBrowse);
+
+ // Increment the plugin reference count manually
+ iEngine.UsePlugin(plugin->Uid());
+ }
+ iEngine.CleanupPluginPushL(plugin);
+
+ TBool async(ETrue); // by default command is asynchronous
+ if (aCmd.IsSupported(KMPXCommandGeneralDoSync))
+ { // check if command is sync
+ async=!(aCmd.ValueTObjectL<TBool>(KMPXCommandGeneralDoSync));
+ }
+
+ if (async)
+ { // Async, cmd ownership transferred
+ if (!plugin)
+ {
+ User::Leave(KErrNotReady);
+ }
+
+ CMPXCommand* cmd = CMPXCommand::NewL(aCmd);
+ CleanupStack::PushL(cmd);
+ plugin->AddTaskL(EMcsCommandExt, aCallback, this, 0,
+ NULL, plugin, cmd);
+ CleanupStack::Pop(cmd);
+
+ // Async, the plugin pointer passed through the task queue
+ iEngine.PluginPop();
+ }
+ else
+ {
+ DoHandleSyncCommandL(aCmd, aMsgQueue, plugin);
+ CleanupStack::PopAndDestroy(); // plugin
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Find a shareable client
+// ----------------------------------------------------------------------------
+//
+TBool CMPXCollectionClientContext::HasShareableClient(
+ TThreadId aId)
+ {
+ TBool ret(EFalse);
+ if (iModeId != KMcModePlaylist)
+ {
+ if (iClientList->IsClient(aId) ) // Just look for same thread
+ {
+ ret = ETrue;
+ }
+ }
+ return ret;
+ }
+
+// ----------------------------------------------------------------------------
+// Notifies all clients of events
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::NotifyL( TMPXCollectionBroadCastMsg aMsg,
+ TInt aData )
+ {
+ iClientList->SendMsgL(
+ TMPXCollectionMessage(TMPXCollectionMessage::EBroadcastEvent,
+ aMsg,aData));
+ }
+
+const TUid& CMPXCollectionClientContext::ModeId() const
+ {
+ return iModeId;
+ }
+
+// ----------------------------------------------------------------------------
+// Initialises from file. iFile is not owned here
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::OpenL()
+ {
+ if (iPathUpdated)
+ {
+ ReOpenL();
+ }
+ else
+ {
+ CMPXCollectionPlugin* plugin = LoadedPlugin(EContextBrowse);
+ MPX_ASSERT(plugin);
+ plugin->CompleteTask();
+ if (plugin->Callback())
+ {
+ plugin->Callback()->HandleOpen(iMedia,
+ iIndex, ETrue,iMediaType);
+ plugin->SetCallback( NULL ); // Reset current observer
+ plugin->SetObserver(iEngine);
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Cancels all outstanding calls (tasks): plug-in should only have one
+// outstanding so that is canceled; the tasks are deleted and removed from the
+// queue
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::BackL()
+ {
+ TInt d=iBrowsePath->Levels();
+ if(d>1)
+ {
+ iPathUpdated = EFalse;
+ // remove last item - the actual item selected
+ iBrowsePath->Back();
+ // preserve focus, since we're rebuilding this level
+ iIndex=iBrowsePath->Index();
+ iFocusItemId = iBrowsePath->Id();
+ ReOpenL();
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Re-open current level
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::ReOpenL()
+ {
+ // remove last item - go to the container which contained the item
+ if (iBrowsePath->Levels())
+ {
+ iBrowsePath->Back();
+ }
+ if (iBrowsePath->Levels() == 0)
+ {
+ //Plugin must be resolved ealier
+ CMPXCollectionPlugin* plugin = LoadedPlugin(EContextBrowse);
+ plugin->CompleteTask();
+ InitL(plugin->Callback());
+ }
+ else
+ {
+ DoPluginOpenL();
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Retrieve media info based on a find criteria
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::FindAllL(
+ const CMPXMedia& aMedia,
+ const CBufBase& aBuf,
+ CMPXCollectionPlugin& aPlugin,
+ CMPXMedia** aResult /*= NULL*/,
+ TBool aSync /*= EFalse*/)
+ {
+ // Find critera and return attributes
+ //
+ RArray<TMPXAttribute> attrs;
+ CleanupClosePushL(attrs);
+ ::CreateFromBufferL(aBuf, attrs);
+
+ // Do the query
+ if (!aSync)
+ {
+ aPlugin.SetObserver(*this);
+ aPlugin.FindAllL(aMedia,attrs.Array());
+ }
+ else
+ {
+ *aResult = aPlugin.FindAllSyncL(aMedia,attrs.Array());
+ }
+ CleanupStack::PopAndDestroy( &attrs );
+ }
+
+// ----------------------------------------------------------------------------
+// CMPXCollectionClientContext::HandleMessage
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::HandleMessage(
+ CMPXMessage* aMsg,
+ TInt aError)
+ {
+ MPX_FUNC_EX("CMPXCollectionClientContext::HandleMessage");
+ DoHandleMessage(aMsg, aError, ETrue);
+ }
+
+// ----------------------------------------------------------------------------
+// CMPXCollectionClientContext::HandleMessage
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::DoHandleMessage(
+ CMPXMessage* aMsg,
+ TInt aError,
+ TBool aNotifyOthers)
+ {
+ MPX_DEBUG3("-->CMPXCollectionClientContext::HandleMessage this %08x, %d", this, aNotifyOthers);
+ if (!aMsg)
+ {
+ iClientList->SendMsg(aMsg, aError);
+ if (aNotifyOthers)
+ {
+ iEngine.NotifyChange(*this, aMsg, aError);
+ }
+ }
+ else
+ {
+ if (aMsg->IsSupported(KMPXMessageGeneralId))
+ {
+ if (aMsg->IsSupported(KMPXMessageArrayContents))
+ {
+ TBool pathUpdated(EFalse);
+ const CMPXMessageArray* messageArray =
+ aMsg->Value<CMPXMessageArray>(KMPXMessageArrayContents);
+ if (messageArray)
+ {
+ TInt count = messageArray->Count();
+
+ MPX_DEBUG2("%d messages:", count);
+
+ for (TInt i=0; i<count; i++)
+ {
+ const CMPXMessage* message =(*messageArray)[i];
+ if (message)
+ {
+ TRAP_IGNORE(DoHandleMessageL(*message, KErrNone));
+ pathUpdated |=iPathUpdated;
+ }
+ }
+ iPathUpdated = pathUpdated;
+ }
+ // Notify other context, collection is changed.
+ // Send the batched version
+ //
+ if (aNotifyOthers)
+ {
+ iEngine.NotifyChange(*this,
+ const_cast<CMPXMessage*>(aMsg),
+ aError);
+ }
+ }
+ else
+ {
+ TRAP_IGNORE(DoHandleMessageL(*aMsg, aError));
+
+ // Notify other context, collection is changed.
+ if (aNotifyOthers)
+ {
+ iEngine.NotifyChange(*this, aMsg, aError);
+ }
+ }
+
+ // Broadcast change messages to the clients to handle
+ //
+ if( iModeId == KMcModePlaylist )
+ {
+ // Playlist should not be handling msgs during refresh
+ if( !iEngine.IsRefreshing() )
+ {
+ iClientList->SendMsg( aMsg, aError );
+ }
+ }
+ else
+ {
+ // Other modes receive msg all the time
+ iClientList->SendMsg( aMsg, aError );
+ }
+
+ // Batched collection change messages and only send this once
+ // Path changed isn't sent to the UI during refresh
+ //
+ if (iPathUpdated)
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::DoHandleMessageL detected path changed");
+ MPX_DEBUG_PATH(*iBrowsePath);
+ // notify clients to refresh
+ TRAP_IGNORE(iClientList->SendMsgL(
+ TMPXCollectionMessage(TMPXCollectionMessage::EPathChanged,
+ EMcPathChangedByCollectionChange)));
+ }
+ }
+ }
+
+ MPX_DEBUG3("<--CMPXCollectionClientContext::HandleMessage this %08x, %d", this, aNotifyOthers);
+ }
+
+// ----------------------------------------------------------------------------
+// Handle collection item change message
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::DoHandleMessageL(
+ const CMPXMessage& aMsg,
+ TInt /*aError*/)
+ {
+ MPX_DEBUG2("-->CMPXCollectionClientContext::DoHandleMessageL this %08x", this);
+ TInt browseLevels = iBrowsePath->Levels(); // browse depth
+
+ if (aMsg.ValueTObjectL<TMPXMessageId>(KMPXMessageGeneralId)==
+ KMPXMessageIdItemChanged)
+ {
+ if (!aMsg.IsSupported(KMPXMessageCollectionId) ||
+ !aMsg.IsSupported(KMPXMessageChangeEventType) ||
+ !aMsg.IsSupported(KMPXMessageMediaGeneralCategory) ||
+ !aMsg.IsSupported(KMPXMessageMediaGeneralId))
+ {
+ User::Leave(KErrArgument);
+ }
+
+ TUid collectionId = aMsg.ValueTObjectL<TUid>(KMPXMessageCollectionId);
+
+ TMPXChangeEventType changeType =
+ aMsg.ValueTObjectL<TMPXChangeEventType>(KMPXMessageChangeEventType);
+
+ TMPXGeneralCategory category =
+ aMsg.ValueTObjectL<TMPXGeneralCategory>(KMPXMessageMediaGeneralCategory);
+
+ TMPXItemId itemId = aMsg.ValueTObjectL<TMPXItemId>(KMPXMessageMediaGeneralId);
+
+ TMPXItemId deprecatedId(0);
+ if (aMsg.IsSupported(KMPXMessageMediaDeprecatedId))
+ {
+ deprecatedId = aMsg.ValueTObjectL<TMPXItemId>(KMPXMessageMediaDeprecatedId);
+ }
+
+ MPX_DEBUG5("CMPXCollectionClientContext::DoHandleMessageL colId %08x, id %d, deprecatedId %d, type %d",
+ collectionId.iUid, itemId.iId1, deprecatedId.iId1, changeType);
+
+
+ if(!iEngine.IsRefreshing())
+ {
+ // Invalidate path
+ TInt pct = KErrNotFound; // path change type
+ if (changeType == EMPXItemInserted && category != EMPXPlaylist)
+ {
+ pct = CMPXCollectionPath ::EAdded;
+ }
+ else if (changeType == EMPXItemModified && category != EMPXPlaylist)
+ {
+ pct = CMPXCollectionPath ::EModified;
+ }
+ else if (changeType == EMPXItemDeleted)
+ {
+ pct = CMPXCollectionPath ::EDeleted;
+ }
+ else if ((changeType == EMPXItemInserted || changeType == EMPXItemModified) &&
+ category == EMPXPlaylist)
+ {
+ pct = CMPXCollectionPath ::EGroupModified;
+ }
+ if( changeType == EMPXItemModified && category == EMPXCollection )
+ {
+ // Overwrite previous type
+ pct = CMPXCollectionPath ::EGroupModified;
+ }
+
+ if (KErrNotFound != pct)
+ { // update browse path
+ CMPXCollectionPath::TMPXCollectionPathChange ct =
+ static_cast<CMPXCollectionPath::TMPXCollectionPathChange>(pct);
+ TInt pUpdated(CMPXCollectionPath::EPathUnchanged);
+
+ // If browse context and browse context is being modified
+ //
+ if (iModeId != KMcModePlaylist && browseLevels &&
+ iBrowsePath->Id(0) == collectionId.iUid )
+ { // check the browse path
+ TInt tmpIndex(0);
+
+ pUpdated = iBrowsePath->HandleChange(
+ collectionId, itemId, deprecatedId, ct,
+ tmpIndex);
+
+ // Take the updated selection index only if it was affected
+ // We need to store the TMPXItemId for iIndex because
+ // a previous collection change would have removed the
+ // top level of the collection path
+ //
+ iPathUpdated = iPathUpdated ||
+ (pUpdated != CMPXCollectionPath::EPathUnchanged);
+ if( pUpdated )
+ {
+ // Only update the selection index if the itemid that
+ // was modified is equal to the one selected
+ //
+ // OR take in the index if clipped the collection path
+ // (pUpdated == KPathClipped )
+ //
+ if( pUpdated == CMPXCollectionPath::EPathClipped )
+ {
+ iIndex = tmpIndex;
+ iFocusItemId = KMPXInvalidItemId;
+ }
+ else if( iFocusItemId.ApproxEqual(itemId ) &&
+ ( iFocusItemId != KMPXInvalidItemId ) )
+ {
+ // Also make sure the index that came back from
+ // checking the collection path isn't -1
+ //
+ // The only case where the selected item will shift
+ // is when we are deleting that item. updaing the item or adding
+ // an item to the current path should not move the focus to another
+ // item
+ //
+ if( tmpIndex != -1 && changeType == EMPXItemDeleted)
+ {
+ if( tmpIndex == iBrowsePath->Count()-1 )
+ {
+ // Last item, focus on previous
+ iIndex = tmpIndex-1;
+ iFocusItemId = iBrowsePath->IdOfIndex( tmpIndex-1 );
+ }
+ else
+ {
+ // Not last, focus on next
+ iFocusItemId = iBrowsePath->IdOfIndex( tmpIndex+1 );
+ }
+ }
+ }
+ else if( iFocusItemId.ApproxEqual( deprecatedId ) &&
+ changeType == EMPXItemModified )
+ {
+ // If we are modifying the item id of an item currently in focus
+ // We move the focus to the new item id
+ //
+ iFocusItemId = itemId;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // do nothing
+ }
+ MPX_DEBUG2("<--CMPXCollectionClientContext::DoHandleMessageL this %08x", this);
+ }
+
+// ----------------------------------------------------------------------------
+// Handle open event
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::HandleOpen(
+ CMPXMedia* aMedia,
+ TInt aErr)
+ {
+ MPX_FUNC("CMPXCollectionClientContext::HandleOpen with media returned");
+ CMPXCollectionPlugin* plugin = LoadedPlugin(EContextBrowse);
+ MPX_ASSERT(plugin);
+
+ // Callback and Task Completion
+ //
+ MMPXCollectionEngineObserver* callback(NULL);
+ TBool openTask(EFalse);
+ TInt task = plugin->Task();
+ if( task == EMcsOpen || task == EMcsOpenPath ||
+ task == EMcsBack || task == EMcsOpenIndex )
+ {
+ callback = plugin->Callback();
+ openTask = ETrue;
+ }
+
+ // Cachable flag
+ //
+ TBool cache(EFalse);
+ if( iBrowsePath &&
+ iBrowsePath->Levels() >= 1 )
+ {
+ TMPXItemId id(iBrowsePath->Id(CMPXCollectionPath::ECollectionUid) );
+ cache = iEngine.PluginCacheable( TUid::Uid( id ) );
+ }
+
+ TRAPD(err, DoHandleOpenL(aMedia, NULL, callback, aErr, cache, openTask));
+ if (err && openTask)
+ {
+ HandleError(*plugin, err);
+ }
+ else if( openTask )
+ {
+ plugin->CompleteTask();
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Handle open event
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::HandleOpen(
+ CMPXMedia* aMedia,
+ const CMPXCollectionPath* aPath,
+ TInt aErr)
+ {
+ MPX_FUNC("CMPXCollectionClientContext::HandleOpen with media returned");
+ CMPXCollectionPlugin* plugin = LoadedPlugin(EContextBrowse);
+ MPX_ASSERT(plugin);
+
+ // Callback and Task Completion
+ //
+ MMPXCollectionEngineObserver* p(NULL);
+ TBool openTask(EFalse);
+ TInt task = plugin->Task();
+ if( task == EMcsOpen || task == EMcsOpenPath ||
+ task == EMcsBack || task == EMcsOpenIndex )
+ {
+ p = plugin->Callback();
+ openTask = ETrue;
+ }
+
+ // Cachable flag
+ //
+ TBool cache(EFalse);
+ if( iBrowsePath &&
+ iBrowsePath->Levels() >= 1 )
+ {
+ TMPXItemId id(iBrowsePath->Id(CMPXCollectionPath::ECollectionUid) );
+ cache = iEngine.PluginCacheable( TUid::Uid( id ) );
+ }
+
+ // Handle OpenL for Media
+ //
+ TRAPD(err, DoHandleOpenL(aMedia, aPath, p, aErr, cache, openTask));
+ if (err && openTask)
+ {
+ HandleError(*plugin, err);
+ }
+ else if( openTask )
+ {
+ plugin->CompleteTask();
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Handle open event
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::DoHandleOpenL(
+ CMPXMedia* aMedia,
+ const CMPXCollectionPath* aPath,
+ MMPXCollectionEngineObserver* aCallback,
+ TInt aErr,
+ TBool aAddToCache,
+ TBool aOpenTask )
+ {
+ MPX_FUNC("CMPXCollectionClientContext::DoHandleOpen with media returned");
+
+ // Make sure if we are updating the results the paths are aligned!
+ //
+ TBool openUpdate(EFalse);
+ if( !aOpenTask )
+ {
+ openUpdate = ETrue;
+ iCacheMedia = ETrue;
+ if( aPath &&
+ aPath->Levels() != iBrowsePath->Levels() )
+ {
+ User::Leave( KErrArgument );
+ }
+ }
+
+ // Add to cache
+ //
+ if ( iBrowsePath->Levels() && aAddToCache && aMedia && iCacheMedia )
+ {
+ // manage the priority
+ CMPXCollectionCache::TCachePriority priority(CMPXCollectionCache::EPriorityNormal);
+ if ((1 == iBrowsePath->Levels()) ||
+ ((2 == iBrowsePath->Levels()) && ((iBrowsePath->Id(1)).iId1 == 0)))
+ {
+ priority = CMPXCollectionCache::EPriorityHigh;
+ }
+
+ if( !aOpenTask )
+ {
+ // Update the current browse path
+ //
+ CMPXCollectionPath* container = iBrowsePath->ContainerPathL();
+ CleanupStack::PushL( container );
+
+ // Add the data to the generic cache and get the latest copy
+ //
+ aMedia = AddToCache( *container,
+ aMedia->Attributes(),
+ *aMedia,
+ ETrue,
+ priority);
+ CleanupStack::PopAndDestroy( container );
+ }
+ else
+ {
+ AddToCache( *iBrowsePath,
+ aMedia->Attributes(),
+ *aMedia,
+ ETrue,
+ priority);
+ }
+ }
+
+ // Current client context browse path media
+ //
+ iMediaType = KMPXCollectionEntries;
+ if (iMedia != aMedia)
+ { // new media
+ delete iMedia;
+ iMedia = NULL;
+ if (aMedia)
+ {
+ iMedia = CMPXMedia::NewL(*aMedia);
+ }
+ }
+
+ TInt n(0);
+ if (aMedia && KErrNone == aErr)
+ { // Update the path
+ RArray<TInt> selectionIndicies;
+ CleanupClosePushL( selectionIndicies );
+
+ if (aPath)
+ { // Update path from aPath
+ if ( aMedia->IsSupported (KMPXCollectionOpenLAllResultRange))
+ {
+ iBrowsePath->Back ();
+ RArray<TMPXItemId> ids;
+ CleanupClosePushL (ids);
+ RArray<TMPXOpenDataBlock> datablocks;
+ CleanupClosePushL (datablocks);
+ // De-serialize from global data, would be good to have global arrays
+ //
+ const TDesC
+ & buf = aMedia->ValueText (KMPXCollectionOpenLAllResultRange);
+ CBufBase* buffer(NULL);
+ MPXUser::CreateBufferL ( buf, buffer);
+ CleanupStack::PushL ( buffer);
+ ::CreateFromBufferL ( *buffer, datablocks);
+ CleanupStack::PopAndDestroy ( buffer);
+
+ if ( aMedia->IsSupported (KMPXMediaArrayContents))
+ {
+ const CMPXMediaArray
+ * mediaArray = aMedia->Value<CMPXMediaArray> (KMPXMediaArrayContents);
+ User::LeaveIfNull (const_cast<CMPXMediaArray*>(mediaArray));
+ TInt dataCount = mediaArray->Count ();
+ TInt rangeCount = datablocks.Count ();
+ for (TInt index = 0; index < dataCount; ++index)
+ {
+ CMPXMedia* media = mediaArray->AtL(index);
+
+ //Check range
+ TBool validItem(EFalse);
+ MPX_ASSERT(rangeCount > 0);
+ for (TInt rangeIndex = 0; rangeIndex < rangeCount; ++rangeIndex)
+ {
+ TInt offset = datablocks[rangeIndex].iOffset;
+ TInt size = datablocks[rangeIndex].iSize;
+ if ( (index >= offset) && (index < offset + size))
+ {
+ validItem = ETrue;
+ break;
+ }
+ }
+
+ if (validItem)
+ {
+ const TMPXItemId
+ id = media->ValueTObjectL<TMPXItemId> (KMPXMediaGeneralId);
+ ids.AppendL (id);
+ }
+ else
+ {
+ ids.AppendL (KMPXInvalidItemId);
+ }
+ }
+ iBrowsePath->AppendL (ids.Array ());
+ }
+ CleanupStack::PopAndDestroy (&datablocks);
+ CleanupStack::PopAndDestroy (&ids);
+ }
+ else
+ {
+ delete iBrowsePath;
+ iBrowsePath = NULL;
+ iBrowsePath = CMPXCollectionPath::NewL ( *aPath);
+ }
+ }
+ else
+ { // Update path from media
+ RArray<TMPXItemId> ids;
+ CleanupClosePushL(ids);
+ if( aMedia->IsSupported(KMPXMediaArrayContents) )
+ {
+ const CMPXMediaArray* mediaArray=aMedia->Value<CMPXMediaArray>(
+ KMPXMediaArrayContents);
+ User::LeaveIfNull(const_cast<CMPXMediaArray*>(mediaArray));
+ n=mediaArray->Count();
+ for (TInt i=0;i<n;++i)
+ {
+ CMPXMedia* media=mediaArray->AtL(i);
+ const TMPXItemId id=media->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId);
+ ids.AppendL(id);
+
+ // Try to look for the selection that we want
+ if( iFocusItemId == id )
+ {
+ selectionIndicies.AppendL( i );
+ }
+ }
+ }
+
+ iBrowsePath->AppendL(ids.Array());
+ CleanupStack::PopAndDestroy(&ids);
+ }
+
+ // List of items
+ const TArray<TMPXItemId>& items = iBrowsePath->Items();
+
+ // OpenL Media has been updated, update the itemid
+ // based on the current index
+ if( openUpdate )
+ {
+ // Check if we have item id first
+ //
+ if( iFocusItemId != KMPXInvalidItemId )
+ {
+ TInt index = iBrowsePath->IndexOfId( iFocusItemId );
+ if( index != KErrNotFound )
+ {
+ iIndex = index;
+ }
+ }
+
+ // Then update based on index
+ if( iIndex >=0 && iIndex < iBrowsePath->Count() )
+ {
+ iBrowsePath->Set(iIndex);
+ iFocusItemId = iBrowsePath->Id();
+ }
+ }
+ else if( aMedia->IsSupported( KMPXCollectionOpenLResultRange ) )
+ {
+ TMPXOpenDataBlock data =
+ aMedia->ValueTObjectL<TMPXOpenDataBlock>(KMPXCollectionOpenLResultRange);
+ if( iBrowsePath->Count() &&
+ iIndex >= 0 &&
+ iIndex < iBrowsePath->Count() )
+ {
+ // If all blank items then we don't change index yet
+ // Wait until we have re-opened the partial data
+ if( data.iOffset != KErrNotFound )
+ {
+ // Not supported, stay with current focus
+ iBrowsePath->Set(iIndex);
+ iFocusItemId = iBrowsePath->Id();
+ }
+ }
+ }
+ // If this selection appears more than once, then we have to find
+ // the closest matching index to what we had before
+ //
+ //
+ else if( selectionIndicies.Count() > 1 &&
+ iFocusItemId != KMPXInvalidItemId )
+ {
+ TInt best(selectionIndicies[0]);
+ TInt idAppearance( selectionIndicies.Count() );
+ for( TInt i=0; i<idAppearance; ++i )
+ {
+ if( Abs(selectionIndicies[i]-iIndex) <= Abs(best-iIndex) )
+ {
+ best = selectionIndicies[i];
+ }
+ }
+ iIndex = best;
+ iBrowsePath->Set(iIndex);
+ }
+ // Always set by item id if we have it
+ // This is needed if an item was added to the current browse level
+ // We still want to select the item we were previously at
+ //
+ else if( iFocusItemId != KMPXInvalidItemId )
+ {
+ TInt index = iBrowsePath->IndexOfId(iFocusItemId);
+ if (KErrNotFound != index)
+ {
+ iBrowsePath->Set(index);
+ }
+ else if( n > 0 ) // Focus item has been deleted, select next
+ {
+ // Bounds check for largest and smallest
+ if( iIndex >= n )
+ {
+ iIndex = n-1;
+ }
+ if( iIndex < 0 )
+ {
+ iIndex = 0;
+ }
+ iBrowsePath->Set(iIndex);
+ iFocusItemId = iBrowsePath->Id();
+ }
+ iIndex = iBrowsePath->Index();
+ }
+ else
+ {
+ // Bounds checking for iIndex
+ if( iIndex >= n && iIndex > 0 )
+ {
+ iIndex = n-1;
+
+ // Just in case if ids has 0 items
+ if( iIndex > 0 && iIndex < items.Count() )
+ {
+ iFocusItemId = items[iIndex];
+ }
+ }
+
+ if (iBrowsePath->Levels()>0 && iIndex>=0 &&
+ iIndex<iBrowsePath->Count())
+ {
+ iBrowsePath->Set(iIndex);
+ }
+ iFocusItemId = iBrowsePath->Id();
+ }
+ CleanupStack::PopAndDestroy(&selectionIndicies);
+ }
+
+ TInt err;
+ if( !iPathUpdated )
+ {
+ // Normal open mode
+ err = KErrNone == aErr ? KMPXPathUpdated : aErr;
+ }
+ else
+ {
+ // Updates open mode, should be returning entries
+ err = KErrNone == aErr ? KMPXCollectionEntries : aErr;
+ }
+
+ // Should not be broadcasting container opened messages
+ // When we are only rebuilding the leaf level
+ //
+ if( !iPathUpdated && aOpenTask )
+ {
+ if( err >= KErrNone)
+ {
+ iClientList->SendMsgL(
+ TMPXCollectionMessage(TMPXCollectionMessage::EPathChanged,
+ EMcPathChangedByOpen,
+ EMcContainerOpened));
+ }
+ }
+
+ iPathUpdated = EFalse;
+
+ // Notes: there should no leave function called after aCallback->HandleOpen
+ if (aCallback)
+ { // Complete open with error or PathUpdated
+ aCallback->HandleOpen(iMedia, iIndex, ETrue, err);
+ if (iPluginUids[EContextBrowse]!=KNullUid)
+ {
+ CMPXCollectionPlugin* plugin = LoadedPlugin(EContextBrowse);
+ MPX_ASSERT(aCallback == plugin->Callback());
+ plugin->SetCallback(NULL);
+ plugin->SetObserver(iEngine);
+ }
+ }
+ MPX_DEBUG_PATH(*iBrowsePath);
+ }
+
+// ----------------------------------------------------------------------------
+// Handle open event
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::HandleOpen(
+ CMPXCollectionPath* aPath,
+ TInt aErr)
+ {
+ MPX_FUNC("CMPXCollectionClientContext::HandleOpen with path returned");
+ TRAPD(err, DoHandleOpenL(aPath, aErr));
+ if (err)
+ {
+ HandleError(*(LoadedPlugin(EContextBrowse)), err);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Handle open event
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::DoHandleOpenL(
+ CMPXCollectionPath* aPath,
+ TInt aErr)
+ {
+ MPX_FUNC("CMPXCollectionClientContext::DoHandleOpen with path returned");
+ CMPXCollectionPlugin* plugin = LoadedPlugin(EContextBrowse);
+ MPX_ASSERT(plugin);
+
+ plugin->CompleteTask();
+
+ if (iBrowsePath != aPath && KErrNone == aErr)
+ {
+ delete iBrowsePath;
+ iBrowsePath = NULL;
+ MPX_ASSERT(aPath);
+ iBrowsePath = CMPXCollectionPath::NewL(*aPath);
+ }
+ iMediaType = KMPXCollectionPath;
+ iIndex = iBrowsePath->Index();
+ iFocusItemId = iBrowsePath->Id();
+
+ TInt err = KErrNone == aErr ? KMPXPathUpdated : aErr;
+
+ // Complete msg
+ // Complete open with error or PathUpdated
+ plugin->Callback()->HandleOpen(iMedia, iIndex, ETrue, err);
+ plugin->SetCallback(NULL);
+ plugin->SetObserver(iEngine);
+ if (aPath->OpenNextMode() != EMPXOpenNoPlaylist)
+ //
+ // The request was NOT to play, but the plug-in returned
+ // the path implying that we should play; so we don't
+ // send it
+ //
+ {
+ iClientList->SendMsgL(
+ TMPXCollectionMessage(TMPXCollectionMessage::EPathChanged,
+ EMcPathChangedByOpen,
+ EMcItemOpened));
+ }
+
+ MPX_DEBUG_PATH(*iBrowsePath);
+ }
+
+// ----------------------------------------------------------------------------
+// Callback of retrieving extended media property
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::HandleMedia(
+ CMPXMedia* aMedia,
+ TInt aError)
+ {
+ MPX_FUNC("CMPXCollectionClientContext::HandleMedia");
+
+ CMPXMedia* ret( aMedia );
+
+ TBool pluginCacheable(EFalse);
+ if( iMediaPath )
+ {
+ TMPXItemId id(iMediaPath->Id(CMPXCollectionPath::ECollectionUid) );
+ pluginCacheable = iEngine.PluginCacheable( TUid::Uid( id ) );
+
+ // if media returned was resulted from multiple selections we don't cache the
+ // results as it's very hard to reuse it anyway
+ if(iMediaPath->Selection().Count() > 0)
+ {
+ pluginCacheable = EFalse;
+ }
+ }
+
+ // Cache the media
+ if ( !aError && aMedia && iCacheMedia && iMediaPath && pluginCacheable )
+ {
+ TMPXItemId id( iMediaPath->Id(
+ CMPXCollectionPath::ECollectionUid ));
+ ret = AddToCache( *iMediaPath, aMedia->Attributes(), *aMedia );
+ }
+
+ CMPXCollectionPlugin* plugin = LoadedPlugin(EContextMedia);
+
+ plugin->CompleteTask();
+ MPX_ASSERT(plugin->Callback());
+ plugin->Callback()->HandleMedia(ret, aError);
+ plugin->SetCallback(NULL); // Reset current observer
+ plugin->SetObserver(iEngine);
+ }
+
+// ----------------------------------------------------------------------------
+// Callback of async CommandL
+// ----------------------------------------------------------------------------
+//
+ void CMPXCollectionClientContext::HandleCommandComplete(
+ CMPXCommand* aCommandResult,
+ TInt aError)
+ {
+ MPX_FUNC_EX("CMPXCollectionClientContext::HandleCommandComplete");
+ CMPXCollectionPlugin* plugin = LoadedPlugin(EContextMedia);
+
+ plugin->CompleteTask();
+ MPX_ASSERT(plugin->Callback());
+ plugin->Callback()->HandleCommandComplete(aCommandResult, aError);
+ plugin->SetCallback(NULL); // Reset current observer
+ plugin->SetObserver(iEngine);
+ }
+
+// ----------------------------------------------------------------------------
+// Handle find all
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::HandleFindAll(
+ CMPXMedia* aMedia,
+ TInt aError)
+ {
+ MPX_FUNC("CMPXCollectionClientContext::HandleFindAll");
+ CMPXCollectionPlugin* plugin = LoadedPlugin(EContextMedia);
+ plugin->CompleteTask();
+ MPX_ASSERT(plugin->Callback());
+ plugin->Callback()->HandleFindAll(aMedia, aError);
+ plugin->SetCallback(NULL); // Reset current observer
+ plugin->SetObserver(iEngine);
+ }
+
+// ----------------------------------------------------------------------------
+// Handle delete all
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::HandleRemove(
+ const CDesCArray& aUriArray,
+ TInt aError)
+ {
+ MPX_FUNC("CMPXCollectionClientContext::HandleRemove");
+ CMPXCollectionPlugin* plugin = LoadedPlugin(EContextRemove);
+
+ plugin->CompleteTask();
+ MPX_ASSERT(plugin->Callback());
+ plugin->Callback()->HandleRemove(aUriArray, aError);
+ plugin->SetCallback(NULL); // Reset current observer
+ plugin->SetObserver(iEngine);
+ }
+
+// ----------------------------------------------------------------------------
+// Execute a async task
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::ExecuteTask(
+ TInt aTask,
+ TInt aParamData,
+ TAny* aPtrData,
+ const CBufBase& aBuf,
+ TAny* aCallback,
+ CBase* aCObject1,
+ CBase* aCObject2)
+ {
+ MPX_DEBUG2("-->CMPXCollectionClientContext::ExecuteTask %d", aTask);
+ CMPXCollectionPlugin* plugin(NULL);
+ TRAPD(err, ExecuteTaskL(aTask, aParamData, aPtrData, aCallback, aBuf,
+ aCObject1,aCObject2,plugin));
+ if (KErrNone !=err)
+ {
+ HandleError(*plugin, err, EFalse);
+ }
+ MPX_DEBUG1("<--CMPXCollectionClientContext::ExecuteTask");
+ }
+
+// ----------------------------------------------------------------------------
+// Indicates that a task was terminated with an error
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::HandleTaskError(
+ TInt aTask,
+ TAny* aPtrData,
+ TAny* aCallback,
+ TInt aError)
+ {
+ MPX_FUNC_EX("CMPXCollectionClientContext::HandleTaskError");
+ CMPXCollectionPlugin* plugin(NULL);
+ switch (aTask)
+ {
+ case EMcsOpen:
+ case EMcsBack:
+ case EMcsOpenIndex:
+ plugin = LoadedPlugin(EContextBrowse);
+ plugin->SetObserver(*this);
+ plugin->SetCallback(
+ reinterpret_cast<MMPXCollectionEngineObserver*>(aCallback));
+ HandleError(*plugin, aError, EFalse);
+ break;
+ case EMcsOpenPath:
+ case EMcsMediaByPath:
+ case EMcsCommandExt:
+ case EMcsRemovePath:
+ case EMcsFindAll:
+ case EMcsCommand:
+ plugin = reinterpret_cast<CMPXCollectionPlugin*>(aPtrData);
+ plugin->SetCallback(
+ reinterpret_cast<MMPXCollectionEngineObserver*>(aCallback));
+ HandleError(*plugin, aError, ETrue);
+ break;
+ default:
+ break;
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Initialize before first open
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::InitL(MMPXCollectionEngineObserver* aCallback)
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::InitL() <---");
+ delete iMedia;
+ iMedia = NULL;
+ delete iBrowsePath;
+ iBrowsePath = NULL;
+ RArray<TInt> supportedIds;
+ CleanupClosePushL(supportedIds);
+ supportedIds.AppendL(KMPXMediaIdContainer);
+ supportedIds.AppendL(KMPXMediaIdGeneral);
+ iMedia=CMPXMedia::NewL(supportedIds.Array());
+ iBrowsePath = CMPXCollectionPath::NewL();
+ CleanupStack::PopAndDestroy(&supportedIds);
+
+ iEngine.ListPluginsL(*iMedia, iUids.Array());
+ if (iPluginUids[EContextBrowse]!=KNullUid )
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::InitL() Collection changed");
+ iClientList->SendMsgL(
+ TMPXCollectionMessage(TMPXCollectionMessage::ECollectionChanged,0,0));
+ }
+
+ // sets the browse plugin to NULL
+ SetPlugin(EContextBrowse, NULL);
+
+ // Update collection path, and buffer, send path update msg,
+ // complete request
+ TRAPD(err, DoHandleOpenL(iMedia, NULL, aCallback, KErrNone, ETrue, ETrue));
+ if (err)
+ {
+ MPX_DEBUG2("CMPXCollectionClientContext::InitL() Complete Open %i", err);
+ aCallback->HandleOpen(iMedia, // Not used
+ iIndex,
+ ETrue, err);
+ }
+ MPX_DEBUG1("CMPXCollectionClientContext::InitL() --->");
+ }
+
+// ----------------------------------------------------------------------------
+// Execute a async task
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::ExecuteTaskL(
+ TInt aTask,
+ TInt aParamData,
+ TAny* aPtrData,
+ TAny* aCallback,
+ const CBufBase& aBuf,
+ CBase* aCObject1,
+ CBase* aCObject2,
+ CMPXCollectionPlugin*& aPlugin)
+ {
+ MPX_DEBUG4("CMPXCollectionClientContext::ExecuteTaskL 0x%08x, task %d, aParam %d",
+ this, aTask, aParamData);
+ switch (aTask)
+ {
+ case EMcsOpen:
+ {
+ aPlugin = LoadedPlugin(EContextBrowse);
+ aPlugin->SetObserver(*this);
+ aPlugin->SetCallback(
+ reinterpret_cast<MMPXCollectionEngineObserver*>(aCallback));
+ OpenL();
+ break;
+ }
+ case EMcsOpenPath:
+ {
+ // Set plugin first for handling error
+ TUid oldUid = iPluginUids[EContextBrowse];
+ aPlugin = reinterpret_cast<CMPXCollectionPlugin*>(aPtrData);
+ // Set plugin and task pointer for browse context
+ SetPlugin(EContextBrowse, aPlugin);
+ iPathUpdated = EFalse;
+ aPlugin->SetObserver(*this);
+ aPlugin->SetCallback(
+ reinterpret_cast<MMPXCollectionEngineObserver*>(aCallback));
+ CMPXCollectionPath* path = static_cast<CMPXCollectionPath*>(aCObject1);
+ delete iBrowsePath;
+ iBrowsePath = NULL;
+ iBrowsePath = CMPXCollectionPath::NewL(*path);
+ SetPathOpenMode(*iBrowsePath, static_cast<TMPXOpenMode>(aParamData));
+
+ // If the browsing plugin is changing, need to broadcast the
+ // collection changed message
+ if (iPluginUids[EContextBrowse] != oldUid)
+ {
+ // no leave before plugin API OpenL
+ TRAP_IGNORE(iClientList->SendMsgL(
+ TMPXCollectionMessage(
+ TMPXCollectionMessage::ECollectionChanged,0,iPluginUids[EContextBrowse].iUid)));
+ }
+ iIndex=0;
+ iFocusItemId = KMPXInvalidItemId;
+ DoPluginOpenL();
+ break;
+ }
+ case EMcsOpenIndex:
+ {
+ // Internalize mode
+ TInt mode = (TInt)aPtrData;
+ aPlugin = LoadedPlugin(EContextBrowse);
+ aPlugin->SetObserver(*this);
+ aPlugin->SetCallback(
+ reinterpret_cast<MMPXCollectionEngineObserver*>(aCallback));
+ iBrowsePath->Set(aParamData);
+ SetPathOpenMode(*iBrowsePath,static_cast<TMPXOpenMode>(mode));
+ iIndex=0;
+ iFocusItemId = KMPXInvalidItemId;
+ DoPluginOpenL();
+ break;
+ }
+ case EMcsBack:
+ {
+ aPlugin = LoadedPlugin(EContextBrowse);
+ aPlugin->SetObserver(*this);
+ aPlugin->SetCallback(
+ reinterpret_cast<MMPXCollectionEngineObserver*>(aCallback));
+ BackL();
+ break;
+ }
+ case EMcsMediaByPath:
+ {
+ // Setup plugin first for handle error
+ aPlugin = reinterpret_cast<CMPXCollectionPlugin*>(aPtrData);
+ SetPlugin(EContextMedia, aPlugin);
+
+ aPlugin->SetObserver(*this);
+ aPlugin->SetCallback(
+ static_cast<MMPXCollectionEngineObserver*>(aCallback));
+ // Media path
+ CMPXCommand* cmd = reinterpret_cast<CMPXCommand*>(aCObject1);
+ MPX_ASSERT(cmd->IsSupported(KMPXCommandGeneralTargetIds));
+ MPX_ASSERT(cmd->IsSupported(KMPXCommandMediaAttributeSpecs));
+ CMPXCollectionPath* path = reinterpret_cast<CMPXCollectionPath*>(aCObject2);
+ CMPXAttributeSpecs* specs =
+ cmd->Value<CMPXAttributeSpecs>(KMPXCommandMediaAttributeSpecs);
+ User::LeaveIfNull(specs);
+ CMPXAttributeSpecs* filter =
+ cmd->Value<CMPXAttributeSpecs>(KMPXCommandMediaFilter);
+ User::LeaveIfNull(filter);
+ TCapabilitySet caps = cmd->ValueTObjectL<TCapabilitySet>(KMPXCommandMediaCapbilitySet);
+ // Ask plugin for media
+ DoPluginMediaL( *path, caps, *specs, *filter );
+ break;
+ }
+ case EMcsRemovePath:
+ {
+ aPlugin = reinterpret_cast<CMPXCollectionPlugin*>(aPtrData);
+ // set the remove plugin
+ SetPlugin(EContextRemove, aPlugin);
+
+ aPlugin->SetObserver(*this);
+ CMPXCollectionPath* path =
+ reinterpret_cast<CMPXCollectionPath*>(aCObject1);
+ aPlugin->SetCallback(
+ reinterpret_cast<MMPXCollectionEngineObserver*>(aCallback));
+ aPlugin->RemoveL( *path );
+ break;
+ }
+ case EMcsFindAll:
+ {
+ aPlugin = reinterpret_cast<CMPXCollectionPlugin*>(aPtrData);
+ // set the media plugin
+ SetPlugin(EContextMedia, aPlugin);
+
+ aPlugin->SetCallback(
+ reinterpret_cast<MMPXCollectionEngineObserver*>(aCallback));
+ CMPXMedia* media = static_cast<CMPXMedia*>(aCObject1);
+ FindAllL(*media, aBuf, *aPlugin);
+ break;
+ }
+ case EMcsCommand:
+ {
+ TMPXCollectionCommand cmd =
+ static_cast<TMPXCollectionCommand>( aParamData );
+ switch( cmd )
+ {
+ case EMcCmdCollectionInit:
+ case EMcCmdCollectionResyn:
+ // Decrement the old plugin reference count
+ aPlugin = reinterpret_cast<CMPXCollectionPlugin*>(aPtrData);
+ SetPlugin(EContextMedia, aPlugin);
+
+ if( aPlugin )
+ {
+ aPlugin->SetObserver(*this);
+ aPlugin->CommandL( cmd );
+ aPlugin->SetObserver(iEngine);
+ aPlugin->CompleteTask();
+ }
+ break;
+ default:
+ MPX_ASSERT(0);
+ break;
+ }
+ break;
+ }
+ case EMcsCommandExt:
+ {
+ CMPXCommand* cmd = reinterpret_cast<CMPXCommand*>(aCObject1);
+ aPlugin = reinterpret_cast<CMPXCollectionPlugin*>(aPtrData);
+ MMPXCollectionEngineObserver* callback =
+ reinterpret_cast<MMPXCollectionEngineObserver*>(aCallback);
+ if( cmd->IsSupported( KMPXCommandGeneralId) )
+ {
+ TMPXCommandId commandId = cmd->ValueTObjectL<TMPXCommandId>(KMPXCommandGeneralId);
+ // Decrement the old plugin reference count
+ SetPlugin(EContextMedia, aPlugin);
+ aPlugin->SetCallback( callback );
+
+ if( commandId == KMPXCommandIdCollectionSelect )
+ {
+ // Decrement the old plugin reference count
+ //
+ DoHandleSelectCommandL( *cmd );
+ aPlugin->SetCallback( NULL );
+ aPlugin->CompleteTask();
+ callback->HandleCommandComplete( NULL, KErrNone );
+ }
+ else
+ {
+ aPlugin->SetObserver(*this);
+ aPlugin->CommandL(*cmd);
+ }
+ }
+ else
+ {
+ aPlugin->CompleteTask();
+ callback->HandleCommandComplete( NULL, KErrArgument ); // return error message
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Error happens upon request
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::HandleError(
+ CMPXCollectionPlugin& aPlugin,
+ TInt aError,
+ TBool aUnusePlugin/*=EFalse*/)
+ {
+ TInt task(aPlugin.Task());
+ MPX_DEBUG3("CMPXCollectionClientContext::HandleError %d, task %d",
+ aError, task);
+ switch (task)
+ {
+ case EMcsOpen:
+ case EMcsOpenPath:
+ case EMcsBack:
+ case EMcsOpenIndex:
+ aPlugin.Callback()->HandleOpen(iMedia, // Not used
+ iIndex,
+ ETrue, aError);
+ aPlugin.CompleteTask();
+ aPlugin.SetCallback(NULL); // Reset current observer
+ aPlugin.SetObserver(iEngine);
+ break;
+ case EMcsMediaByPath:
+ aPlugin.Callback()->HandleMedia(iMedia, aError);
+ aPlugin.CompleteTask();
+ aPlugin.SetCallback(NULL); // Reset current observer
+ aPlugin.SetObserver(iEngine);
+ break;
+ case EMcsCommandExt:
+ aPlugin.Callback()->HandleCommandComplete(iMedia, aError);
+ aPlugin.CompleteTask();
+ aPlugin.SetCallback(NULL); // Reset current observer
+ aPlugin.SetObserver(iEngine);
+ break;
+ case EMcsRemovePath:
+ {
+ CDesCArray* dummy(NULL); // object will not be dereferenced in callback
+ aPlugin.Callback()->HandleRemove(*dummy, aError);
+ aPlugin.SetCallback(NULL); // Reset current observer
+ aPlugin.SetObserver(iEngine);
+ aPlugin.CompleteTask();
+ }
+ break;
+ case EMcsFindAll:
+ aPlugin.Callback()->HandleFindAll(iMedia, aError);
+ aPlugin.SetCallback(NULL); // Reset current observer
+ aPlugin.SetObserver(iEngine);
+ aPlugin.CompleteTask();
+ break;
+ case EMcsCommand:
+ {
+ // At least complete the task to not jam up the task queue
+ aPlugin.SetCallback(NULL); // Reset current observer
+ aPlugin.SetObserver(iEngine);
+ aPlugin.CompleteTask();
+ break;
+ }
+ default:
+ break;
+ }
+ if (aUnusePlugin)
+ {
+ iEngine.ReleasePlugin(aPlugin.Uid());
+ }
+ MPX_DEBUG1("<--CMPXCollectionClientContext::HandleError");
+ }
+
+// ----------------------------------------------------------------------------
+// Error happens upon request
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::ResolvePluginL(
+ const CMPXCollectionPath& aPath,
+ TUid& aUid)
+ {
+ CMPXCollectionPlugin* p= iEngine.LoadedPlugin(aUid); // Save old plugin
+ // Resolve new plugin
+ CMPXCollectionPlugin* plugin=iEngine.ResolvePluginL(aPath);
+ // Update with new Uid
+ aUid = plugin->Uid();
+ if (p != plugin && &aPath == iBrowsePath)
+ {
+ // browsing plugin changed
+ iClientList->SendMsgL(TMPXCollectionMessage(
+ TMPXCollectionMessage::ECollectionChanged,0,aUid.iUid));
+ }
+
+ if (p)
+ {
+ // Make sure we decrement the reference count for the old plugin
+ iEngine.ReleasePlugin(p->Uid());
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// resolve plugin for FindAllL
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::ResolvePluginL(
+ const CMPXMedia& aMedia,
+ CMPXCollectionPlugin*& aPlugin)
+ {
+ // We have to be finding from the same context as browse
+ // if we are from MPX UI
+ //
+ if (iPluginUids[EContextBrowse]!=KNullUid)
+ {
+ aPlugin = LoadedPlugin(EContextBrowse);
+
+ // Increment the reference count manually
+ iEngine.UsePlugin(aPlugin->Uid());
+ }
+ else // browse context does not exist
+ {
+ if (aMedia.IsSupported(KMPXMediaGeneralCollectionId))
+ {
+ TUid col = aMedia.ValueTObjectL<TUid>(KMPXMediaGeneralCollectionId);
+
+ // Increment the plugin reference count
+ aPlugin = iEngine.ResolvePluginL(col);
+ }
+ else if (aMedia.IsSupported(KMPXMediaGeneralUri))
+ {
+ const TDesC& uri = aMedia.ValueText(KMPXMediaGeneralUri);
+
+ // Increment the plugin reference count
+ aPlugin = iEngine.ResolvePluginL(uri);
+ }
+ else
+ {
+ // Unable to find a collection plugin
+ User::Leave(KErrNotSupported);
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CMPXCollectionClientContext::SetPlugin
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::SetPlugin(
+ TContextType aType,
+ CMPXCollectionPlugin* aPlugin)
+ {
+ if (iPluginUids[aType]!=KNullUid)
+ {
+ iEngine.ReleasePlugin(iPluginUids[aType]);
+ }
+ if (aPlugin)
+ {
+ iPluginUids[aType] = aPlugin->Uid();
+ }
+ else
+ {
+ iPluginUids[aType] = KNullUid;
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Add a media object to the collection
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::DoUpdateMediaL( TInt aOp, const CMPXMedia& aMedia )
+ {
+ // Media object can be a single "item" or a list of "items"
+ //
+ TMPXGeneralType type = EMPXNoType;
+ if (aMedia.IsSupported(KMPXMediaGeneralType))
+ {
+ type = aMedia.ValueTObjectL<TMPXGeneralType>(KMPXMediaGeneralType);
+ }
+ else
+ {
+ User::Leave(KErrArgument);
+ }
+
+ if ( type == EMPXGroup )
+ {
+ // Group has to have a "container"
+ MPX_ASSERT(aMedia.IsSupported(KMPXMediaArrayContents));
+ const CMPXMediaArray* array =
+ aMedia.Value<CMPXMediaArray>(KMPXMediaArrayContents);
+ User::LeaveIfNull(const_cast<CMPXMediaArray*>(array));
+ TInt count = array->Count();
+ for( TInt i=0; i<count; ++i )
+ {
+ DoUpdateMediaL( aOp, *(array->AtL(i)) );
+ }
+ }
+ else if ( type == EMPXItem )
+ {
+ DoHandleItemL( aOp, aMedia );
+ }
+ else
+ {
+ // How do we handle "group" artists?
+ User::Leave( KErrNotSupported );
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Add the media object to the correct plugin
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::DoHandleItemL( TInt aOp, const CMPXMedia& aMedia)
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::DoHandleItemL <---");
+
+ // Find the correct plugin.
+ // The code below increments the plugin reference count
+ CMPXCollectionPlugin* plugin(NULL);
+ if (aMedia.IsSupported(KMPXMediaGeneralCollectionId))
+ {
+ const TUid& uid = aMedia.ValueTObjectL<TUid>(KMPXMediaGeneralCollectionId);
+ MPX_DEBUG2("CMPXCollectionClientContext::DoHandleItemL Collection %i", uid.iUid);
+
+ // Increment the plugin reference count
+ plugin = iEngine.ResolvePluginL( uid );
+ }
+ else if (aMedia.IsSupported(KMPXMediaGeneralUri))
+ {
+ const TDesC& uri = aMedia.ValueText(KMPXMediaGeneralUri);
+ MPX_DEBUG2("CMPXCollectionClientContext::DoHandleItemL Collection %S", &uri);
+
+ // Increment the plugin reference count
+ plugin = iEngine.ResolvePluginL( uri );
+ }
+ else
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::DoHandleItemL Cannot resolve a plugin");
+ User::Leave(KErrNotSupported);
+ }
+
+ if( !plugin )
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::DoHandleItemL Cannot resolve a plugin");
+ User::Leave(KErrNotSupported);
+ }
+
+ iEngine.CleanupPluginPushL(plugin);
+
+ switch( aOp )
+ {
+ case EMcsAddItem:
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::DoHandleItemL Add");
+
+ plugin->SetObserver(*this);
+ plugin->AddL( aMedia );
+ plugin->SetObserver(iEngine);
+ break;
+ }
+ case EMcsRemoveItem:
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::DoHandleItemL Remove");
+ plugin->SetObserver(*this);
+ plugin->RemoveL( aMedia );
+ plugin->SetObserver(iEngine);
+ break;
+ }
+ case EMcsSetMedia:
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::DoHandleItemL Set");
+ plugin->SetObserver(*this);
+ plugin->SetL( aMedia );
+ plugin->SetObserver(iEngine);
+ break;
+ }
+ default:
+ {
+ User::Leave(KErrNotSupported);
+ break;
+ }
+ } // switch
+
+ CleanupStack::PopAndDestroy(); // plugin
+
+ MPX_DEBUG1("CMPXCollectionClientContext::DoHandleItemL --->");
+ }
+
+// ----------------------------------------------------------------------------
+// Handle a synchorouns command to the collection
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::DoHandleSyncCommandL(
+ const CMPXCommand& aCmd,
+ const CMPXMessageQueue& aMsgQueue,
+ CMPXCollectionPlugin* aPlugin/*=NULL*/)
+ {
+ // Only process the command if the command id has been defined,
+ // otherwise leave with KErrArgument
+ if (aCmd.IsSupported(KMPXCommandGeneralId))
+ {
+ TMPXCommandId commandId = aCmd.ValueTObjectL<TMPXCommandId>(KMPXCommandGeneralId);
+ switch( commandId )
+ {
+ case KMPXCommandIdCollectionSelect:
+ {
+ DoHandleSelectCommandL( aCmd );
+ break;
+ }
+
+ case KMPXCommandSubscriptionAdd:
+ {
+ TInt index( iClientList->Find( aMsgQueue ));
+ CMPXMediaArray* items(
+ aCmd.Value<CMPXMediaArray>( KMPXCommandSubscriptionAddItems ));
+ User::LeaveIfNull(items);
+ CMPXSubscription* subscription( CMPXSubscription::NewL( *items ));
+ CleanupStack::PushL(subscription);
+ iClientList->AddSubscriptionL( index, subscription ); // ownership transferred
+ CleanupStack::Pop(subscription);
+ break;
+ }
+ case KMPXCommandSubscriptionRemove:
+ {
+ TInt index( iClientList->Find( aMsgQueue ));
+ CMPXMediaArray* items(
+ aCmd.Value<CMPXMediaArray>( KMPXCommandSubscriptionAddItems ));
+ User::LeaveIfNull(items);
+ CMPXSubscription* subscription( CMPXSubscription::NewL( *items ));
+ CleanupStack::PushL(subscription);
+ iClientList->RemoveSubscriptionL( index, *subscription );
+ CleanupStack::PopAndDestroy(subscription);
+ break;
+ }
+ case KMPXCommandSubscriptionRemoveAll:
+ {
+ TInt index( iClientList->Find( aMsgQueue ));
+ iClientList->RemoveAllSubscriptionsL( index );
+ break;
+ }
+
+ case KMPXCommandIdCollectionPrepareDelete:
+ {
+ if (aCmd.IsSupported (KMPXCommandCollectionPrepareRemovePath))
+ {
+ CMPXCollectionPath
+ * path = aCmd.ValueCObjectL<CMPXCollectionPath> (KMPXCommandCollectionPrepareRemovePath);
+ CleanupStack::PushL(path);
+ iEngine.ResetCacheL(*path);
+ CleanupStack::PopAndDestroy(path);
+ }
+ break;
+ }
+
+ default:
+ {
+ MPX_ASSERT(aPlugin);
+ aPlugin->SetObserver(*this);
+ TRAPD( err, aPlugin->CommandL( const_cast<CMPXCommand&>(aCmd) ) );
+ aPlugin->SetObserver(iEngine);
+ User::LeaveIfError( err );
+ break;
+ }
+ }
+ }
+ else
+ {
+ User::Leave(KErrArgument);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CMPXCollectionClientContext::DoHandleSelectCommandL
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::DoHandleSelectCommandL(const CMPXCommand& aCmd)
+ {
+ TInt index(iIndex);
+
+ // Selecting a new index
+ if( aCmd.IsSupported(KMPXCommandCollectionSelectIndex) )
+ {
+ index = aCmd.ValueTObjectL<TInt>(KMPXCommandCollectionSelectIndex);
+ if (iBrowsePath->Levels()<=0)
+ {
+ User::Leave(KErrNotReady);
+ }
+ if (index<0 || index>=iBrowsePath->Count())
+ {
+ User::Leave(KErrArgument);
+ }
+ iBrowsePath->Set(index);
+ }
+ // Re-select the current index
+ else
+ {
+ TInt count = iBrowsePath->Count();
+
+ if( iFocusItemId != KMPXInvalidItemId )
+ {
+ TInt index = iBrowsePath->IndexOfId(iFocusItemId);
+ if (KErrNotFound != index)
+ {
+ iBrowsePath->Set(index);
+ }
+ else if( count > 0 ) // Focus item has been deleted, select next
+ {
+ // Bounds check for largest and smallest
+ if( iIndex >= count )
+ {
+ iIndex = count-1;
+ }
+ if( iIndex < 0 )
+ {
+ iIndex = 0;
+ }
+ iBrowsePath->Set(iIndex);
+ iFocusItemId = iBrowsePath->Id();
+ }
+ iIndex = iBrowsePath->Index();
+ }
+ else
+ {
+ // Bounds checking for iIndex
+ if( iIndex >= count && iIndex > 0 )
+ {
+ iIndex = count-1;
+
+ // Just in case if ids has 0 items
+ if( iIndex > 0 && iIndex < count )
+ {
+ iFocusItemId = iBrowsePath->IdOfIndex(iIndex);
+ }
+ }
+
+ if (iBrowsePath->Levels()>0 && iIndex>=0 &&
+ iIndex<iBrowsePath->Count())
+ {
+ iBrowsePath->Set(iIndex);
+ }
+ iFocusItemId = iBrowsePath->Id();
+ }
+ }
+ iClientList->SendMsgL(
+ TMPXCollectionMessage(TMPXCollectionMessage::EFocusChanged,
+ index, index));
+ iIndex = index; // iIndex will always be up to date
+ iFocusItemId = iBrowsePath->Id();
+ }
+
+// ----------------------------------------------------------------------------
+// CMPXCollectionClientContext::DoPluginOpenL
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::DoPluginOpenL()
+ {
+ MPX_FUNC("CMPXCollectionClientContext::DoPluginOpenL()");
+ TBool callOpen(ETrue);
+ MPX_ASSERT(iPluginUids[EContextBrowse]!=KNullUid);
+ TBool pluginCacheable(EFalse);
+ if( iBrowsePath )
+ {
+ TMPXItemId id(iBrowsePath->Id(CMPXCollectionPath::ECollectionUid) );
+ pluginCacheable = iEngine.PluginCacheable( TUid::Uid( id ) );
+ }
+
+ // Check for open playlist only mode. If in that mode, do not return the media
+ // from the cache but call the plugin to open, as that will callback a
+ // different HandleOpenL() with the collection path instead.
+ TMPXOpenMode mode( iBrowsePath->OpenNextMode() );
+ CMPXCollectionPlugin* plugin = LoadedPlugin(EContextBrowse);
+ if ( !iFilter && mode != EMPXOpenPlaylistOnly )
+ {
+ // try to get the results from the cache only if the plugin is cacheable
+ if ( pluginCacheable )
+ {
+ CMPXMedia* results( iCache.GetL( *iBrowsePath,
+ iBrowsePath->OpenAttributes(),
+ ETrue ));
+ if (results)
+ {
+ MPX_DEBUG1("CMPXCollectionClientContext::DoPluginOpenL(): Results found in cache");
+ MMPXCollectionEngineObserver* callback = plugin->Callback();
+ plugin->CompleteTask();
+ TRAPD(err, DoHandleOpenL(results, NULL, callback, KErrNone, EFalse, ETrue));
+ if (err)
+ {
+ HandleError(*plugin, err);
+ }
+
+ callOpen = EFalse;
+ }
+ }
+ }
+
+ if (callOpen)
+ {
+ if ( pluginCacheable )
+ {
+ iCacheMedia = AttributesCacheableL( iBrowsePath->OpenAttributes(), *iBrowsePath );
+ }
+ plugin->OpenL(*iBrowsePath, iBrowsePath->OpenAttributes(), iFilter);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CMPXCollectionClientContext::DoPluginMediaL
+// ----------------------------------------------------------------------------
+//
+void CMPXCollectionClientContext::DoPluginMediaL(
+ CMPXCollectionPath& aPath,
+ const TCapabilitySet& aCaps,
+ CMPXAttributeSpecs& aSpecs,
+ CMPXFilter& aFilter)
+ {
+ MPX_FUNC("CMPXCollectionClientContext::DoPluginMediaL()");
+ TBool callMedia(ETrue);
+ delete iMediaPath;
+ iMediaPath = NULL;
+
+ TMPXItemId id(aPath.Id(CMPXCollectionPath::ECollectionUid) );
+ TBool pluginCacheable( iEngine.PluginCacheable( TUid::Uid( id ) ));
+
+ // try to get the results from the cache only if
+ // the plugin is cacheable
+ CMPXMedia* results( NULL );
+ if ( pluginCacheable )
+ {
+ results = iCache.GetL( aPath, aPath.OpenAttributes() );
+
+ if (results)
+ {
+ // Check if the attribute specs match
+ if ( aSpecs.Count() > 0 )
+ {
+ /*
+ // need to check if requested attribute specs
+ // match what we have cached
+ if ( results->IsSupported( KMPXCommandMediaAttributeSpecs ))
+ {
+ CMPXAttributeSpecs* specs( results->Value<CMPXAttributeSpecs>(
+ KMPXCommandMediaAttributeSpecs ));
+ User::LeaveIfNull(specs);
+ if ( *specs == *aSpecs )
+ {
+ callMedia = EFalse;
+ }
+ }
+ */
+ }
+ else
+ {
+ // Else client did not specify attribute specs, so we can return
+ // the match
+ callMedia = EFalse;
+ }
+ }
+ }
+
+ if ( callMedia )
+ {
+ iMediaPath = CMPXCollectionPath::NewL( aPath );
+
+ if ( pluginCacheable )
+ {
+ iCacheMedia = AttributesCacheableL( aPath.OpenAttributes(), aPath );
+ }
+ LoadedPlugin(EContextMedia)->MediaL( aPath,
+ aPath.OpenAttributes(),
+ aCaps,
+ &aSpecs,
+ &aFilter);
+ }
+ else
+ {
+ HandleMedia( results, KErrNone );
+ }
+ }
+
+
+// ----------------------------------------------------------------------------
+// CMPXCollectionClientContext::AttributesCacheableL
+// ----------------------------------------------------------------------------
+//
+TBool CMPXCollectionClientContext::AttributesCacheableL(
+ const TArray<TMPXAttribute>& aAttrs,
+ const CMPXCollectionPath& aPath )
+ {
+ MPX_DEBUG1("-->CMPXCollectionClientContext::AttributesCacheableL");
+
+ TMPXItemId id( aPath.Id( CMPXCollectionPath::ECollectionUid ));
+ const TArray<TUid>& nonCacheAttrs( iEngine.PluginNonCacheableAttributesL( TUid::Uid( id )));
+
+ TBool found( EFalse );
+ TInt nonCacheCount( nonCacheAttrs.Count() );
+ for ( TInt i = 0; i < nonCacheCount && !found; i++ )
+ {
+ TInt attrCount( aAttrs.Count() );
+ for ( TInt j = 0; j < attrCount && !found; j++ )
+ {
+ TMPXAttribute att( aAttrs[j] );
+ if ( nonCacheAttrs[i] == TUid::Uid( att.ContentId() ))
+ {
+ found = ETrue;
+ }
+ }
+ }
+ MPX_DEBUG1("<--CMPXCollectionClientContext::AttributesCacheableL");
+ return !found;
+ }
+
+// ----------------------------------------------------------------------------
+// CMPXCollectionClientContext::AddToCache
+// ----------------------------------------------------------------------------
+//
+CMPXMedia* CMPXCollectionClientContext::AddToCache(
+ const CMPXCollectionPath& aPath,
+ const TArray<TMPXAttribute>& aAttrs,
+ CMPXMedia& aResults,
+ TBool aMediaFromOpenL,
+ CMPXCollectionCache::TCachePriority aPriority /* = EPriorityNormal */)
+ {
+ CMPXMedia* ret( &aResults );
+ TRAP_IGNORE(ret = iCache.AddL(aPath, aAttrs, aResults, aMediaFromOpenL, aPriority));
+ return ret;
+ }
+
+// ----------------------------------------------------------------------------
+// CMPXCollectionClientContext::LoadedPlugin
+// ----------------------------------------------------------------------------
+//
+CMPXCollectionPlugin* CMPXCollectionClientContext::LoadedPlugin(TContextType aType)
+ {
+ MPX_ASSERT(iPluginUids[aType]!=KNullUid);
+ CMPXCollectionPlugin* plugin(iEngine.LoadedPlugin(iPluginUids[aType]));
+ MPX_ASSERT(plugin);
+ return plugin;
+ }
+
+// End of file