upnpframework/upnpcommonui/src/upnpselectiondialog.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:52:00 +0200
changeset 0 7f85d04be362
permissions -rw-r--r--
Revision: 200947 Kit: 200951

/*
* Copyright (c) 2005-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:  Source file for UPnP Browse UI Implementation
*
*/


// INCLUDE FILES
// System
#include <aknPopupHeadingPane.h>
#include <aknPopup.h>
#include <aknlists.h>
#include <AknIconArray.h>
#include <gulicon.h>
#include <StringLoader.h>

// upnp stack api
#include <upnpstring.h>

// upnpframework / avcontroller api
#include "upnpavdevice.h"
#include "upnpavcontroller.h"
#include "upnpavcontrollerfactory.h"
#include "upnpavdevicelist.h"
#include "upnpavdevice.h"
#include "upnpavcontroller.h"

// upnpframework / internal api's
#include "upnpcommonutils.h"

// common ui internal
#include <upnpcommonui.rsg>
#include <upnpcommonui.mbg> //for icons
#include "upnpselectiondialog.h"
#include "upnpcommonui.h"

// debug stuff
_LIT( KComponentLogfile, "commonui.txt");
#include "upnplog.h"

// CONSTANTS
_LIT( KAknCommonUIMbmFileName, "\\resource\\apps\\upnpcommonui.mbm" );
const TInt KLength = 100;

// --------------------------------------------------------------------------
// CUPnPSelectionDialog::NewL
// Two-phased constructor.
// --------------------------------------------------------------------------
CUPnPSelectionDialog* CUPnPSelectionDialog::NewL(
    MUPnPAVController& aAVControl )
    {
    __LOG( "CUPnPSelectionDialog::NewL" );
    
    CUPnPSelectionDialog* self = 
                           new ( ELeave ) CUPnPSelectionDialog( aAVControl );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop();
    return self;
    }

// --------------------------------------------------------------------------
// CUPnPSelectionDialog::ConstructL
// Symbian 2nd phase constructor can leave.
// --------------------------------------------------------------------------
void CUPnPSelectionDialog::ConstructL()
    {
    __LOG( "CUPnPSelectionDialog::ConstructL" );
    
    iDeviceArray = CUpnpAVDeviceList::NewL();
    // Register as an observer to device operations

    iTypeOfDevicesToSearch = EUPnPSearchAllDevices;
    }

// --------------------------------------------------------------------------
// CUPnPSelectionDialog::CUPnPSelectionDialog
// C++ default constructor can NOT contain any code, that
// might leave.
// --------------------------------------------------------------------------
CUPnPSelectionDialog::CUPnPSelectionDialog( MUPnPAVController& aAVControl ):
                                           iAVControl( aAVControl )
    {
    __LOG( "CUPnPSelectionDialog::CUPnPSelectionDialog" );
    
    iDeviceObserver = iAVControl.DeviceObserver();
    iAVControl.RemoveDeviceObserver();
    iAVControl.SetDeviceObserver( *this );
    iPopup = NULL;
    iExitReason = KErrNone;
    }

// Destructor
CUPnPSelectionDialog::~CUPnPSelectionDialog()
    {
    __LOG( "CUPnPSelectionDialog::~CUPnPSelectionDialog" );

    delete iListBox;

    // Unregister as an observer to device operations
    iAVControl.RemoveDeviceObserver();
    if( iDeviceObserver )
        {
        iAVControl.SetDeviceObserver( *iDeviceObserver );    
        }

    delete iDeviceArray;
    }

// --------------------------------------------------------------------------
// CUPnPSelectionDialog::PreLayoutDynInitL();
// called by framework before dialog is shown
// --------------------------------------------------------------------------
void CUPnPSelectionDialog::PreLayoutDynInitL( const TDesC& aTitle )
    {
    __LOG( "CUPnPSelectionDialog::PreLayoutDynInitL" );

    // Browse dialog title text
    iPopup->SetTitleL( aTitle ); 

    CAknIconArray* icons = new ( ELeave ) CAknIconArray(2);
    CleanupStack::PushL( icons );

    // Mif icons
    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
    TFileName iconsPath( AknIconUtils::AvkonIconFileName( ) );

    TFileName mbmFileName( KAknCommonUIMbmFileName );
    TFileName dllName;
    Dll::FileName( dllName );
    TBuf<2> drive = dllName.Left( 2 ); // Drive letter followed by ':' 
    mbmFileName.Insert( 0, drive );
    
    // Media server icon
    AppendIconToArrayL( icons, skin, 
                        mbmFileName, 
                        KAknsIIDDefault, 
                        EMbmUpnpcommonuiQgn_server_icon, 
                        EMbmUpnpcommonuiQgn_server_icon_mask );
    iListBox->ItemDrawer()->FormattedCellData()->SetIconArrayL( icons );
    CleanupStack::Pop( icons );
    
    // Enable horizontal scrolling
    iListBox->ItemDrawer()->ColumnData()->EnableMarqueeL( ETrue );
    LoadListItemsL();
    }


// --------------------------------------------------------------------------
// CUPnPSelectionDialog::LoadListItemsL
// Sends the browse request to UPnP AV Controller. When result set arrives,
// UPnP AV Controller will call the "BrowseResultsL" call back method,
// which is implemented below.
// --------------------------------------------------------------------------
void CUPnPSelectionDialog::LoadListItemsL()
    {
    __LOG( "CUPnPSelectionDialog::LoadListItemsL" );

    CTextListBoxModel* model = iListBox->Model();
    MDesCArray* textArray = model->ItemTextArray();
    CDesCArray* listBoxItems = static_cast<CDesCArray*>( textArray );
    
    //contents inside the array will be owned by iDeviceArray
    CUpnpAVDeviceList* tempDeviceArray = NULL;
    // Get the devices from the UPnP Stack according to the search criteria
    if( iTypeOfDevicesToSearch == EUPnPSearchAllDevices )
        {
            CUpnpAVDeviceList* tempDeviceArray2 = NULL;
            tempDeviceArray2 = iAVControl.GetMediaServersL();
            if( tempDeviceArray2->Count() > 0 )
                {
                CleanupStack::PushL( tempDeviceArray2 );
                CleanupStack::PushL( tempDeviceArray );
                for( TInt i = 0; i < tempDeviceArray2->Count(); i++ )
                    {
                    tempDeviceArray->AppendDeviceL( 
                                                *( *tempDeviceArray2 )[i] );
                    }
                
                CleanupStack::Pop( tempDeviceArray );
                CleanupStack::Pop( tempDeviceArray2 );
                tempDeviceArray2->Reset();
                
                }
            
            tempDeviceArray2 = iAVControl.GetMediaRenderersL();
            
            if(tempDeviceArray2->Count() > 0 )
                {
                CleanupStack::PushL( tempDeviceArray2 );
                CleanupStack::PushL( tempDeviceArray );
                for( TInt i = 0; i < tempDeviceArray2->Count(); i++ )
                    {
                    tempDeviceArray->AppendDeviceL( 
                                                *( *tempDeviceArray2 )[i] );
                    }
                
                CleanupStack::Pop( tempDeviceArray );    
                CleanupStack::Pop( tempDeviceArray2);
                tempDeviceArray2->Reset();
                }
            
            delete tempDeviceArray2;
            
        }
    else if( iTypeOfDevicesToSearch == EUPnPSearchAllServerDevices ||
      iTypeOfDevicesToSearch == EUPnPSearchServerDevicesWithCopyCapability ||
      iTypeOfDevicesToSearch == EUPnPSearchServerDevicesWithSearchCapability )
        {
        tempDeviceArray = iAVControl.GetMediaServersL();
        }
    else
        {
        tempDeviceArray = iAVControl.GetMediaRenderersL();
        }
    
    CleanupStack::PushL( tempDeviceArray );
    if ( tempDeviceArray->Count() )
        {
        for ( TInt i=0; i < tempDeviceArray->Count(); i++ )
            {
            // Check if the device match with the search criteria
            if( MatchWithSearchCriteria( 
                     const_cast<CUpnpAVDevice*>( ( *tempDeviceArray)[i] ) ) )
                {
                iDeviceArray->AppendDeviceL( *( *tempDeviceArray )[i] );
                }
            else
                {
                CUpnpAVDevice* tempDevice = ( *tempDeviceArray )[i];
                delete tempDevice;
                tempDevice = NULL;
                }
            }        
        
        
        for ( TInt i=0; i < iDeviceArray->Count(); i++ )
            {
            // Get device friendly name and replace illegal characters.
            HBufC8* tmpfriendlyname = 
            UPnPCommonUtils::ReplaceIllegalFilenameCharactersL(               
                ( *iDeviceArray )[i]->FriendlyName().Left( KLength ) );
            CleanupStack::PushL( tmpfriendlyname);
            
            HBufC* device = UpnpString::ToUnicodeL( *tmpfriendlyname );
            CleanupStack::PushL( device);

            TBuf<KMaxFileName> item;
            item.Format( _L( "%d\t%S\t\t" ),0, device ); 

            CleanupStack::PopAndDestroy( device );
            CleanupStack::PopAndDestroy( tmpfriendlyname );
            listBoxItems->AppendL( item );            
            }

        // Updates CBA.
        UpdateCommandSetL();

        iListBox->HandleItemAdditionL(); // Update listbox
        iListBox->SetCurrentItemIndexAndDraw( 0 ); // select new item
 
        }     
    else
        {
        HBufC* waitText = StringLoader::LoadLC( 
                            R_UPNPCOMMONUI_EXTERNAL_WAITING_NOTE );
        iListBox->View()->SetListEmptyTextL( *waitText );
        CleanupStack::PopAndDestroy( waitText ); 
        }
        
    CleanupStack::Pop( tempDeviceArray );
    tempDeviceArray->Reset();
    delete tempDeviceArray;    

    }

// --------------------------------------------------------------------------
// CUPnPSelectionDialog::UPnPDeviceDiscovered
// Returns discovered device from UPnP AV control point.
// --------------------------------------------------------------------------
void CUPnPSelectionDialog::UPnPDeviceDiscovered( 
                                               const CUpnpAVDevice& aDevice )
    {
    __LOG( "CUPnPSelectionDialog::UPnPDeviceDiscovered" );

    TRAPD( error, UPnPDeviceDiscoveredL( aDevice ) );
    if( error )
        {
        __LOG1( "UPnPDeviceDiscoveredL, leave %d .", error );
        }
    }

// --------------------------------------------------------------------------
// CUPnPSelectionDialog::UPnPDeviceDiscoveredL
// Returns discovered device from UPnP AV control point.
// --------------------------------------------------------------------------
void CUPnPSelectionDialog::UPnPDeviceDiscoveredL( 
                                               const CUpnpAVDevice& aDevice )
    {
    __LOG( "CUPnPSelectionDialog::UPnPDeviceDiscovered" );

    
    if ( MatchWithSearchCriteria( const_cast<CUpnpAVDevice*>( &aDevice ) ) )
        {
        CUpnpAVDevice* tempDevice = CUpnpAVDevice::NewL( aDevice );
        CleanupStack::PushL( tempDevice );
        //ownership transferred                                      
        iDeviceArray->AppendDeviceL( *tempDevice );
        CleanupStack::Pop( tempDevice );

        HBufC8* tmpfriendlyname = 
            UPnPCommonUtils::ReplaceIllegalFilenameCharactersL( 
            ( ( CUpnpAVDevice* )tempDevice )->FriendlyName() );

        CleanupStack::PushL( tmpfriendlyname );
        TPtrC8 friendlyname = *tmpfriendlyname;

        CTextListBoxModel* model = iListBox->Model();
        MDesCArray* textArray = model->ItemTextArray();
        CDesCArray* listBoxItems = static_cast<CDesCArray*>( textArray );
        TBuf<KMaxFileName> item;
        HBufC* tmpStr = 
                    UpnpString::ToUnicodeL( friendlyname.Left( KLength ) );
        CleanupStack::PushL( tmpStr );
        item.Format( _L( "%d\t%S\t\t" ),0, tmpStr ); 
        CleanupStack::PopAndDestroy( tmpStr );
        CleanupStack::PopAndDestroy( tmpfriendlyname );
        listBoxItems->AppendL( item  );
        iListBox->HandleItemAdditionL(); // Update listbox

        // Updates CBA.
        UpdateCommandSetL();

        iListBox->ActivateL();
        iListBox->DrawDeferred();
        }
    }

// --------------------------------------------------------------------------
// CUPnPSelectionDialog::UPnPDeviceDisappeared
// Returns disappeared device from UPnP AV control point.
// --------------------------------------------------------------------------
void CUPnPSelectionDialog::UPnPDeviceDisappeared(
                                            const CUpnpAVDevice& aDevice )
    {
    __LOG( "CUPnPSelectionDialog::UPnPDeviceDisappeared" );

    TRAPD( error, UPnPDeviceDisappearedL( aDevice ) );
    if ( error )
        {
        __LOG1( "UPnPDeviceDisappearedL, leave %d", error );
        }
    }

// --------------------------------------------------------------------------
// CUPnPSelectionDialog::UPnPDeviceDisappearedL
// Returns disappeared device from UPnP AV control point.
// --------------------------------------------------------------------------
void CUPnPSelectionDialog::UPnPDeviceDisappearedL(
    const CUpnpAVDevice& aDevice )
    {
    __LOG( "CUPnPSelectionDialog::UPnPDeviceDisappearedL" );

    CTextListBoxModel* model = iListBox->Model();
    TInt currentItem = iListBox->CurrentItemIndex();
    MDesCArray* textArray = model->ItemTextArray();
    CDesCArray* listBoxItems = static_cast<CDesCArray*>( textArray );
    TInt i( 0 );
    TPtrC8 ptr( aDevice.Uuid() );
    
    while( i < iDeviceArray->Count() && 
           ptr.Compare( ( *iDeviceArray )[i]->Uuid() ) )
        {
        i++;
        }
    if ( i < iDeviceArray->Count() )
        {
        iDeviceArray->RemoveAndDestroy( i );
        listBoxItems->Delete( i, 1 );
        AknListBoxUtils::HandleItemRemovalAndPositionHighlightL(
            iListBox, currentItem, ETrue );
        iListBox->DrawDeferred();
        }

    if ( !iDeviceArray->Count() )
        {
        // show "Waiting devices" text
        HBufC* waitText = StringLoader::LoadLC( 
                                R_UPNPCOMMONUI_EXTERNAL_WAITING_NOTE );
        iListBox->View()->SetListEmptyTextL( *waitText );
        CleanupStack::PopAndDestroy( waitText ); 

        // Updates CBA.
        UpdateCommandSetL();
        }
    }

// --------------------------------------------------------------------------
// CUPnPSelectionDialog::WLANConnectionLost
// --------------------------------------------------------------------------
void CUPnPSelectionDialog::WLANConnectionLost() 
    {
    __LOG( "CUPnPSelectionDialog::WLANConnectionLost" );
    DismissItself( KErrDisconnected );
    };
    
// --------------------------------------------------------------------------
// CUPnPSelectionDialog::AppendIconToArrayL
// Load a possibly skinned icon (with mask) and append it to an
// icon array.
// --------------------------------------------------------------------------
void CUPnPSelectionDialog::AppendIconToArrayL( CAknIconArray* aArray,
                                               MAknsSkinInstance* aSkin,
                                               const TDesC& aMbmFile,
                                               const TAknsItemID& aID,
                                               TInt aBitmapId,
                                               TInt aMaskId )
    {
    __LOG( "CUPnPSelectionDialog::AppendIconToArrayL" );
    __ASSERTD( aArray != NULL, __FILE__, __LINE__ );

    CFbsBitmap* bitmap = NULL;
    CFbsBitmap* mask = NULL;

    AknsUtils::CreateIconLC( aSkin, aID,
        bitmap, mask, aMbmFile, aBitmapId, aMaskId );

    CGulIcon* icon = CGulIcon::NewL( bitmap, mask );
    icon->SetBitmapsOwnedExternally( EFalse );

    // icon now owns the bitmaps, no need to keep on cleanup stack.
    CleanupStack::Pop( 2 ); // mask, bitmap
    bitmap = NULL;
    mask = NULL;

    CleanupStack::PushL( icon );
    aArray->AppendL( icon );

    // aArray now owns the icon, no need to delete.
    CleanupStack::Pop();
    }

// --------------------------------------------------------------------------
// CUPnPSelectionDialog::CreatePopupL
// Creates a selection popup.
// --------------------------------------------------------------------------
void CUPnPSelectionDialog::CreatePopupL( 
                                const TDesC& aTitle,
                                TUPnPDeviceTypesToSearch aDeviceType )
    {
    __LOG( "CUPnPSelectionDialog::CreatePopupL" );

    // Store the type of devices that are searched
    iTypeOfDevicesToSearch = aDeviceType;

    // Create and configure the list box 
    iListBox = new (ELeave) CAknSingleGraphicPopupMenuStyleListBox;
    iPopup = CAknPopupList::NewL( iListBox, 
                                  R_UPNPCOMMONUI_SOFTKEYS_EMPTY_CANCEL,
                                  AknPopupLayouts::EDynMenuWindow );
    iListBox->ConstructL( iPopup, EAknListBoxSelectionList );
    iListBox->CreateScrollBarFrameL( ETrue );
    iListBox->ScrollBarFrame()->SetScrollBarVisibilityL(
        CEikScrollBarFrame::EOff, 
        CEikScrollBarFrame::EAuto );
    PreLayoutDynInitL( aTitle );
    }

// --------------------------------------------------------------------------
// CUPnPSelectionDialog::StartPopupL
// Parses the friendly names from the list of UPnPAVDevices and
// executes the selection dialog. Returns ID of the selected item.
// --------------------------------------------------------------------------
TInt CUPnPSelectionDialog::StartPopupL( CUpnpAVDevice& aDevice )
    {
    __LOG( "CUPnPSelectionDialog::StartPopupL" );

    TInt ret = KErrNone;
    
    // Start animation
    RDebug::Print( _L( "CUPnPSelectionDialog::\
StartPopupL header animation" ) );
    iPopup->Heading()-> SetHeaderAnimationL( 
                        R_UPNPCOMMONUI_ANIMATION_FOR_SELECTION_DIALOG );

    TInt popupOk = iPopup->ExecuteLD();
    iPopup = NULL;
    if ( popupOk )
        {
        if ( iListBox->CurrentItemIndex() >= 0 )
            {
            CUpnpAVDevice* device =
                        ( *iDeviceArray )[iListBox->CurrentItemIndex()];
            aDevice.CopyFromL( *device );
            ret = KErrNone;
            }
        }
    else
        {
        if( KErrNone == iExitReason )
            {
            ret = KErrCancel;    
            }
        else
            {
            ret = iExitReason;
            }
        
        }
    return ret;    
    }


// --------------------------------------------------------------------------
// CUPnPSelectionDialog::DismissItself
// Dismiss the selection dialog via an error code.
// --------------------------------------------------------------------------
void CUPnPSelectionDialog::DismissItself( TInt aError )
    {
    iExitReason = aError;
    if( iPopup )
        {
        iPopup->CancelPopup();
        }
    }

// --------------------------------------------------------------------------
// CUPnPSelectionDialog::MatchWithSearchCriteria
// Checks if a given device matches with the search criteria.
// --------------------------------------------------------------------------
TBool CUPnPSelectionDialog::MatchWithSearchCriteria( CUpnpAVDevice *aDevice )
    {
    TBool returnValue = EFalse;
    if( aDevice )
        {
        // If all device types are accepted
        if( iTypeOfDevicesToSearch == EUPnPSearchAllDevices )
            {
            returnValue = ETrue;
            }
        // If all media server devices are accepted
        else if( iTypeOfDevicesToSearch == EUPnPSearchAllServerDevices &&
                 aDevice->DeviceType() == CUpnpAVDevice::EMediaServer )
            {
            returnValue = ETrue;
            }
        // If all rendering devices are accepted
        else if( iTypeOfDevicesToSearch == EUPnPSearchAllRenderingDevices &&
                 aDevice->DeviceType() == CUpnpAVDevice::EMediaRenderer )
            {
            returnValue = ETrue;
            }
        // If media server devices with copy capability are accepted
        else if( iTypeOfDevicesToSearch ==
                 EUPnPSearchServerDevicesWithCopyCapability &&
                 aDevice->DeviceType() == CUpnpAVDevice::EMediaServer &&
                 aDevice->CopyCapability() )
            {
            returnValue = ETrue;
            }
        // If media server devices with search capability are accepted
        else if( iTypeOfDevicesToSearch ==
                 EUPnPSearchServerDevicesWithSearchCapability &&
                 aDevice->DeviceType() == CUpnpAVDevice::EMediaServer &&
                 aDevice->SearchCapability() )
            {
            returnValue = ETrue;
            }
        // If rendering devices with image capability are accepted
        else if( iTypeOfDevicesToSearch ==
                 EUPnPSearchRenderingDevicesWithImageCapability &&
                 aDevice->DeviceType() == CUpnpAVDevice::EMediaRenderer &&
                 aDevice->ImageCapability() )
            {
            returnValue = ETrue;
            }
        // If rendering devices with video capability are accepted
        else if( iTypeOfDevicesToSearch ==
                 EUPnPSearchRenderingDevicesWithVideoCapability &&
                 aDevice->DeviceType() == CUpnpAVDevice::EMediaRenderer &&
                 aDevice->VideoCapability() )
            {
            returnValue = ETrue;
            }
        // If rendering devices with audio capability are accepted
        else if( iTypeOfDevicesToSearch ==
                 EUPnPSearchRenderingDevicesWithAudioCapability &&
                 aDevice->DeviceType() == CUpnpAVDevice::EMediaRenderer &&
                 aDevice->AudioCapability() )
            {
            returnValue = ETrue;
            }
        else
            {
            returnValue = EFalse;
            }
        }
    return returnValue;
    }

// --------------------------------------------------------------------------
// CUPnPSelectionDialog::UpdateCommandSetL
// Updates command set of the dialog by the search type of the devices.
// --------------------------------------------------------------------------
void CUPnPSelectionDialog::UpdateCommandSetL()
    {
    // Default values, used when no items in the list.
    TInt resId = R_UPNPCOMMONUI_SOFTKEYS_EMPTY_CANCEL;
    if ( iDeviceArray->Count() )
        {
        // Updates the commands set by iTypeOfDevicesToSearch variable.
        switch( iTypeOfDevicesToSearch )
            {
            case EUPnPSearchServerDevicesWithCopyCapability:
                // When copying or moving we should use "Ok" lsk 
                // instead of "Select".
                resId = R_AVKON_SOFTKEYS_OK_CANCEL;
                break;
            default:
                resId = R_AVKON_SOFTKEYS_SELECT_CANCEL;
                break;
            }
        }
    
    CEikButtonGroupContainer* bgc = iPopup->ButtonGroupContainer();    
    bgc->SetCommandSetL( resId );
    bgc->DrawDeferred();
    }

// End of file