/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: ESMR Location plugin handler implementation
*
*/
#include "emailtrace.h"
#include "cesmrlocationpluginhandler.h"
#include "esmrconfig.hrh"
#include <calentry.h>
#include <stringloader.h>
#include <aknquerydialog.h>
#include <esmrgui.rsg>
//<cmail>
#include "cesmrurlparserplugin.h"
//</cmail>
#include <clmklandmarkselectordlg.h>
#include <tlmkitemiddbcombiinfo.h>
#include <epos_cposlandmark.h>
#include <aknutils.h>
#include <ct/rcpointerarray.h>
#ifdef RD_USE_MYLOCATIONUI
#include <mylocationui.h>
#endif //RD_USE_MYLOCATIONUI
#include "cesmrlocationplugin.h"
#include "esmrcommands.h"
#include "mesmrcalentry.h"
#include "cesmrdynamicitemselectionlist.h"
#include "cesmrlocationhistorymanager.h"
#include "mesmrlocationhistoryitem.h"
#include "cesmrconfirmationquery.h"
// Unnamed namespace for local definitions
namespace { //codescanner::namespace
_LIT(KSpace, " ");
// Maximum length of the text in location field
const TInt KMaxLocationTextLength = 255;
}
// ============================ MEMBER FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::CESMRLocationPluginHandler
// -----------------------------------------------------------------------------
//
CESMRLocationPluginHandler::CESMRLocationPluginHandler( MObjectProvider& aParent )
: iParent(&aParent)
{
FUNC_LOG;
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::~CESMRLocationPluginHandler
// -----------------------------------------------------------------------------
//
CESMRLocationPluginHandler::~CESMRLocationPluginHandler()
{
FUNC_LOG;
delete iWait;
delete iLocationPlugin;
delete iLandmark;
delete iUrlParser;
delete iLocationHistoryManager;
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::NewL
// -----------------------------------------------------------------------------
//
CESMRLocationPluginHandler* CESMRLocationPluginHandler::NewL(
MObjectProvider& aParent )
{
FUNC_LOG;
CESMRLocationPluginHandler* self =
new (ELeave) CESMRLocationPluginHandler( aParent );
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop( self );
return self;
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::ConstructL
// -----------------------------------------------------------------------------
//
void CESMRLocationPluginHandler::ConstructL()
{
FUNC_LOG;
iWait = new( ELeave ) CActiveSchedulerWait;
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::HandleCommandL
// -----------------------------------------------------------------------------
//
TBool CESMRLocationPluginHandler::HandleCommandL( TInt aCommand,
MESMRCalEntry& aEntry,
TBool aIgnoreQuery )
{
FUNC_LOG;
iIgnoreQuery = aIgnoreQuery;
iEntryUpdated = EFalse;
switch ( aCommand )
{
case EESMRCmdAssignFromMap:
{
if( !(iWait->IsStarted()) )
{
CCalEntry& entry = aEntry.Entry();
const TDesC& location = entry.LocationL();
CCalGeoValue* geoVal = entry.GeoValueL();
if ( geoVal )
{
// Launch Maps
LocationPluginL().SelectFromMapL( location, geoVal );
}
else
{
// Extract location URL from description
TPtrC locationUrl;
UrlParserL().FindLocationUrl( entry.DescriptionL(),
locationUrl );
// Launch Maps
LocationPluginL().SelectFromMapL( location, locationUrl );
}
iWait->Start(); // codescanner::callActiveObjectWithoutCheckingOrStopping
// iLandmark is set in async callback SelectFromMapCompleted
// from Maps application.
if ( iLandmark )
{
UpdateEntryFromLandmarkL( aEntry, *iLandmark );
delete iLandmark;
iLandmark = NULL;
}
}
}
break;
case EESMRCmdUpdateFromMap:
{
if ( !(iWait->IsStarted()) )
{
// Launch Maps and ignore existing coordinates,
// because location has been updated
LocationPluginL().SelectFromMapL( aEntry.Entry().LocationL(),
KNullDesC );
iWait->Start(); // codescanner::callActiveObjectWithoutCheckingOrStopping
// iLandmark is set in async callback SelectFromMapCompleted
// from Maps application.
if ( iLandmark )
{
UpdateEntryFromLandmarkL( aEntry, *iLandmark );
delete iLandmark;
iLandmark = NULL;
}
}
break;
}
case EESMRCmdSearchFromMap:
{
const TDesC& location = aEntry.Entry().LocationL();
LocationPluginL().SearchFromMapL( location );
}
break;
case EESMRCmdShowOnMap:
{
CCalGeoValue* geoVal = aEntry.Entry().GeoValueL();
TReal lat, lon;
if ( geoVal && geoVal->GetLatLong( lat, lon ) )
{
LocationPluginL().ShowOnMapL( *geoVal );
}
else
{
const TDesC& description = aEntry.Entry().DescriptionL();
TPtrC locationUrl;
TInt position = UrlParserL().FindLocationUrl( description,
locationUrl );
if ( position >= 0 )
{
LocationPluginL().ShowOnMapL( locationUrl );
}
}
break;
}
case EESMRCmdLandmarks:
{
SearchFromLandmarksL( iParent, aEntry );
break;
}
case EESMRCmdPreviousLocations:
{
ShowSelectPreviousLocationQueryL( aEntry );
break;
}
case EMRCommandMyLocations:
{
#ifdef RD_USE_MYLOCATIONUI
CMyLocationSelectorUi* ui = CMyLocationSelectorUi::NewL();
CleanupStack::PushL( ui );
CPosLandmark* landmark = ui->LaunchMyLocationSelectorUiL();
if ( landmark )
{
CleanupStack::PushL( landmark );
UpdateEntryFromLandmarkL( aEntry, *landmark );
CleanupStack::PopAndDestroy( landmark );
}
CleanupStack::PopAndDestroy( ui );
#else // RD_USE_MYLOCATIONUI
ASSERT( EFalse );
#endif //RD_USE_MYLOCATIONUI
break;
}
default:
User::Leave( KErrGeneral );
}
return iEntryUpdated;
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::IsCommandAvailableL
// -----------------------------------------------------------------------------
//
TBool
CESMRLocationPluginHandler::IsCommandAvailableL( TInt aCommand,
const MESMRCalEntry& aEntry )
{
FUNC_LOG;
TBool res( EFalse );
switch ( aCommand )
{
case EESMRCmdAssignFromMap: //fallthrough
case EESMRCmdUpdateFromMap:
case EESMRCmdSearchFromMap:
case EESMRCmdLandmarks:
{
res = ETrue;
break;
}
case EESMRCmdPreviousLocations:
{
if ( LocationHistoryManagerL().ItemCount() > 0 )
{
res = ETrue;
}
break;
}
case EESMRCmdShowOnMap:
{
// Try to fetch vCal GEO value from entry
CCalGeoValue* geoVal = aEntry.Entry().GeoValueL();
TReal lat, lon;
if ( geoVal && geoVal->GetLatLong( lat, lon ) )
{
res = ETrue;
}
else
{
// Check if description field has location url
const TDesC& description = aEntry.Entry().DescriptionL();
TPtrC locationUrl;
TInt position = UrlParserL().FindLocationUrl( description,
locationUrl );
if ( position >= 0 )
{
res = ETrue;
}
}
break;
}
#ifdef RD_USE_MYLOCATIONUI
case EMRCommandMyLocations:
{
res = ETrue;
break;
}
#endif
default:
{
break;
}
}
return res;
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::StoreLocationToHistoryL
// -----------------------------------------------------------------------------
//
void CESMRLocationPluginHandler::StoreLocationToHistoryL(
const MESMRCalEntry& aEntry )
{
FUNC_LOG;
const CCalEntry& entry = aEntry.Entry();
const TDesC& entryLocation = entry.LocationL();
// Store location only if location field contains text.
if ( entryLocation.Length() > 0 )
{
const TDesC& entryDescription = entry.DescriptionL();
// Search for location url from description.
TPtrC locationUrl;
TInt position = UrlParserL().FindLocationUrl( entryDescription,
locationUrl );
// If url was not found.
if ( position < 0 )
{
locationUrl.Set( KNullDesC );
}
// Check if history item with same location and url
// is already stored.
TInt existingHistoryItemIndex = KErrNotFound;
TInt itemCount = LocationHistoryManagerL().ItemCount();
for ( TInt i = 0; i < itemCount; ++i )
{
const MESMRLocationHistoryItem& item =
iLocationHistoryManager->LocationHistoryItemL( i );
if ( item.Address().Compare( entryLocation ) == 0 &&
item.Url().Compare( locationUrl ) == 0 )
{
existingHistoryItemIndex = i;
break;
}
}
// If history item with same location and url existed
// update it's position in history array only.
if ( existingHistoryItemIndex >= 0 )
{
// Ownership is not transferred,
// existing item is already owned by location manager.
const MESMRLocationHistoryItem& item =
iLocationHistoryManager->LocationHistoryItemL( existingHistoryItemIndex );
iLocationHistoryManager->UpdateLocationHistoryL( &item );
}
else
{
// Create new history item.
MESMRLocationHistoryItem* historyItem =
iLocationHistoryManager->CreateLocationHistoryItemL(
entryLocation,
locationUrl );
// Store new item to history.
CleanupDeletePushL( historyItem );
iLocationHistoryManager->UpdateLocationHistoryL( historyItem );
CleanupStack::Pop( historyItem );
}
}
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::UpdateEntryLocationL
// -----------------------------------------------------------------------------
//
TBool CESMRLocationPluginHandler::UpdateEntryLocationL( MESMRCalEntry& aEntry,
const TDesC& aLocation,
TBool aIgnoreQuery,
TBool& aLocationReplaced )
{
FUNC_LOG;
TBool entryUpdated = EFalse;
if ( aLocation.Length() > 0 )
{
CCalEntry& entry = aEntry.Entry();
const TDesC& location = entry.LocationL();
// Replace old location field content.
TBool replace = ETrue;
if ( !aIgnoreQuery
&& location.Length() > 0
&& location != aLocation )
{
// Query for replacing old location field content
replace = CESMRConfirmationQuery::ExecuteL( location );
}
// If previous location was empty or user selects to
// replace previous location with new one.
if ( location.Length() == 0 || replace )
{
entry.SetLocationL( aLocation.Left( KMaxLocationTextLength ) );
entryUpdated = ETrue;
aLocationReplaced = ETrue;
}
else
{
// Concatenate new address to existing one
// Create CPtrCArray for existing and new location strings
CPtrCArray* strings = new( ELeave ) CPtrCArray( 2 );
CleanupStack::PushL( strings );
strings->AppendL( TPtrC( location ) );
strings->AppendL( TPtrC( aLocation ) );
HBufC* newLocation =
StringLoader::LoadLC( R_MEET_REQ_NEW_LOCATION_FORMAT,
*strings );
entry.SetLocationL( newLocation->Left( KMaxLocationTextLength ) );
entryUpdated = ETrue;
CleanupStack::PopAndDestroy( 2, strings );
}
}
return entryUpdated;
}
// -----------------------------------------------------------------------------
// From MESMRLocationPluginObserver
// CESMRLocationPluginHandler::SelectFromMapCompleted
// -----------------------------------------------------------------------------
//
void CESMRLocationPluginHandler::SelectFromMapCompleted( TInt aError,
CPosLandmark* aLandmark )
{
FUNC_LOG;
// Remove previous landmark if one is set.
if ( iLandmark )
{
delete iLandmark;
iLandmark = NULL;
}
if ( aError == KErrNone )
{
// pointer to the result of landmark fetch
iLandmark = aLandmark;
}
if ( iWait->IsStarted() )
{
iWait->AsyncStop();
}
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::LocationPluginL
// -----------------------------------------------------------------------------
//
CESMRLocationPlugin& CESMRLocationPluginHandler::LocationPluginL()
{
FUNC_LOG;
if ( !iLocationPlugin )
{
// Lazy construction of Location ECom plugin
iLocationPlugin = CESMRLocationPlugin::NewL();
iLocationPlugin->SetObserver(this);
}
return *iLocationPlugin;
}
// ---------------------------------------------------------------------------
// Creates adress descriptor from a landmark object
// ---------------------------------------------------------------------------
//
HBufC* CESMRLocationPluginHandler::CreateAddressFromLandmarkL(
const CPosLandmark& aLandmark )
{
FUNC_LOG;
CPtrCArray* addressStrings = new( ELeave ) CPtrCArray( 2 );
CleanupStack::PushL( addressStrings );
TBool streetAvailable = aLandmark.IsPositionFieldAvailable( EPositionFieldStreet );
TBool cityAvailable = aLandmark.IsPositionFieldAvailable( EPositionFieldCity );
if ( streetAvailable )
{
TPtrC streetPtr( KNullDesC );
User::LeaveIfError( aLandmark.GetPositionField( EPositionFieldStreet,
streetPtr ) );
if ( streetPtr.Length() > 0 )
{
addressStrings->AppendL( streetPtr );
}
}
if ( cityAvailable )
{
TPtrC cityPtr( KNullDesC );
User::LeaveIfError( aLandmark.GetPositionField( EPositionFieldCity,
cityPtr ) );
if ( cityPtr.Length() > 0 )
{
addressStrings->AppendL( cityPtr );
}
}
HBufC* address(NULL);
if ( addressStrings->Count() == 2 )
{
//format street and city to buffer
address = StringLoader::LoadL( R_MEET_REQ_ADDRESS_STREET_CITY,
*addressStrings );
}
else if ( addressStrings->Count() == 1 )
{
// alloc street or city to buffer
address = addressStrings->At( 0 ).AllocL();
}
else if ( addressStrings->Count() == 0 )
{
TPtrC namePtr( KNullDesC );
User::LeaveIfError( aLandmark.GetLandmarkName( namePtr ));
if ( namePtr.Length() > 0)
{
address = namePtr.AllocL();
}
}
CleanupStack::PopAndDestroy( addressStrings );
//Transfer ownership of address
return address;
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::UpdateEntryFromLandmarkL
// Updates location information into calendar entry from aLandmark.
// -----------------------------------------------------------------------------
//
void CESMRLocationPluginHandler::UpdateEntryFromLandmarkL(
MESMRCalEntry& aEntry,
const CPosLandmark& aLandmark )
{
FUNC_LOG;
//parse and add address to calendar entry
HBufC* streetAddress = CreateAddressFromLandmarkL( aLandmark );
if ( streetAddress )
{
CleanupDeletePushL( streetAddress );
UpdateEntryLocationL( aEntry, *streetAddress );
CleanupStack::PopAndDestroy( streetAddress );
}
CCalEntry& entry = aEntry.Entry();
TLocality locality;
if ( aLandmark.GetPosition( locality ) == KErrNone )
{
// Store GEO value to entry
CCalGeoValue* geoVal = CCalGeoValue::NewL();
CleanupStack::PushL( geoVal );
geoVal->SetLatLongL( locality.Latitude(), locality.Longitude() );
entry.SetGeoValueL( *geoVal );
CleanupStack::PopAndDestroy( geoVal );
//parse and add location url to calendar entry
HBufC* locationUrl = UrlParserL().CreateUrlFromLandmarkL( aLandmark );
CleanupDeletePushL( locationUrl );
UpdateEntryDescriptionL( aEntry, *locationUrl );
CleanupStack::PopAndDestroy( locationUrl );
}
else if ( iLocationReplaced )// Location field content from this landmark
{
// Clear GEO value and location URL
entry.ClearGeoValueL();
const TDesC& description = entry.DescriptionL();
TPtrC url;
TInt pos = UrlParserL().FindLocationUrl( description, url );
if ( pos > KErrNotFound )
{
TPtrC desc = description.Mid( pos + url.Length() );
entry.SetDescriptionL( desc );
}
}
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::SearchFromLandmarksL
// -----------------------------------------------------------------------------
//
void CESMRLocationPluginHandler::SearchFromLandmarksL( MObjectProvider* aParent, MESMRCalEntry& aEntry )
{
FUNC_LOG;
CLmkLandmarkSelectorDlg* landmarkDlg = CLmkLandmarkSelectorDlg::NewL();
CleanupStack::PushL( landmarkDlg );
landmarkDlg->SetMopParent( aParent );
TLmkItemIdDbCombiInfo selectedItem;
// Execute landmark selection dialog
TInt isAccepted = landmarkDlg->ExecuteLD( selectedItem );
CleanupStack::Pop( landmarkDlg );
if ( isAccepted != 0 )
{
TPosLmItemId itemId = selectedItem.GetItemId();
CPosLandmarkDatabase* lmDataBase = selectedItem.GetLmDb();
CleanupStack::PushL( lmDataBase );
// Read selected landmark from landmarks database
CPosLandmark* landmark = lmDataBase->ReadLandmarkLC( itemId );
UpdateEntryFromLandmarkL( aEntry, *landmark );
CleanupStack::PopAndDestroy( landmark );
CleanupStack::PopAndDestroy( lmDataBase );
ReleaseLandmarkResources();
}
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::ShowSelectPreviousLocationQueryL
// Shows "Previous locations" query and updates aEntry
// according to selection.
// -----------------------------------------------------------------------------
//
void CESMRLocationPluginHandler::ShowSelectPreviousLocationQueryL( MESMRCalEntry& aEntry )
{
FUNC_LOG;
// Array for listbox items.
RCPointerArray<HBufC> addressArray;
CleanupClosePushL( addressArray );
// Populate address array.
TInt itemCount = LocationHistoryManagerL().ItemCount();
for ( TInt i = 0; i < itemCount; ++i )
{
const MESMRLocationHistoryItem& item =
iLocationHistoryManager->LocationHistoryItemL( i );
HBufC* address = item.Address().AllocLC();
addressArray.AppendL( address );
CleanupStack::Pop( address );
}
CESMRDynamicItemSelectionList* selectionQuery =
CESMRDynamicItemSelectionList::NewL();
CleanupStack::PushL( selectionQuery );
// Execute selection query.
TInt idx = selectionQuery->ExecuteL( addressArray,
CESMRDynamicItemSelectionList::EESMRRecentLocationList );
CleanupStack::PopAndDestroy( selectionQuery );
if ( idx >= 0 && idx < addressArray.Count() )
{
const MESMRLocationHistoryItem& item =
iLocationHistoryManager->LocationHistoryItemL( idx );
// Update entry location.
const TDesC& selectedLocation = item.Address();
UpdateEntryLocationL( aEntry, selectedLocation );
// Update entry description if url available.
const TDesC& selectedLocationUrl = item.Url();
if ( selectedLocationUrl.Length() > 0 )
{
UpdateEntryDescriptionL( aEntry, selectedLocationUrl );
}
}
CleanupStack::PopAndDestroy( &addressArray );
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::UpdateEntryLocationL
// Updates aEntry location with aLocation.
// -----------------------------------------------------------------------------
//
void CESMRLocationPluginHandler::UpdateEntryLocationL(
MESMRCalEntry& aEntry, const TDesC& aLocation )
{
FUNC_LOG;
iEntryUpdated |= UpdateEntryLocationL( aEntry,
aLocation,
iIgnoreQuery,
iLocationReplaced );
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::UpdateEntryDescriptionL
// Updates aEntry description with aLocationUrl.
// -----------------------------------------------------------------------------
//
void CESMRLocationPluginHandler::UpdateEntryDescriptionL(
MESMRCalEntry& aEntry, const TDesC& aLocationUrl )
{
FUNC_LOG;
if ( aLocationUrl.Length() > 0 )
{
CCalEntry& entry = aEntry.Entry();
HBufC* description = HBufC::NewL( entry.DescriptionL().Length() +
aLocationUrl.Length() + 1);
CleanupStack::PushL( description );
TPtr descriptionPointer( description->Des() );
TPtrC urlPointer;
TInt position;
position = UrlParserL().FindLocationUrl( entry.DescriptionL(), urlPointer);
if ( position >= KErrNone )
{
descriptionPointer.Copy( entry.DescriptionL() );
if ( ( position > 0 ) && ( entry.DescriptionL().Length() >
(position + aLocationUrl.Length() ) ) )
{
descriptionPointer.Delete( position, ( urlPointer.Length() + 1 ) );
}
else
{
descriptionPointer.Delete( position, urlPointer.Length() );
}
descriptionPointer.Insert( 0, aLocationUrl );
if ( position > 0 )
{
descriptionPointer.Insert( aLocationUrl.Length(), KSpace );
}
entry.SetDescriptionL( *description );
iEntryUpdated = ETrue;
}
else
{
descriptionPointer.Copy( entry.DescriptionL() );
descriptionPointer.Insert( 0, aLocationUrl );
if ( entry.DescriptionL().Length() != 0 )
{
descriptionPointer.Insert( aLocationUrl.Length(), KSpace );
}
entry.SetDescriptionL( *description );
iEntryUpdated = ETrue;
}
CleanupStack::PopAndDestroy( description );
}
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::UrlParserL
// Creates and returns location URL parser.
// -----------------------------------------------------------------------------
//
CESMRUrlParserPlugin& CESMRLocationPluginHandler::UrlParserL()
{
FUNC_LOG;
if ( !iUrlParser )
{
iUrlParser = CESMRUrlParserPlugin::NewL();
}
return *iUrlParser;
}
// -----------------------------------------------------------------------------
// CESMRLocationPluginHandler::LocationHistoryManagerL
// Creates and returns location history manager.
// -----------------------------------------------------------------------------
//
CESMRLocationHistoryManager& CESMRLocationPluginHandler::LocationHistoryManagerL()
{
FUNC_LOG;
if ( !iLocationHistoryManager )
{
iLocationHistoryManager = CESMRLocationHistoryManager::NewL();
}
return *iLocationHistoryManager;
}
// EOF