appinstaller/AppinstUi/Plugin/CommonUI/Src/CUIDetailsDialog.cpp
changeset 0 ba25891c3a9e
child 13 0817e13c927e
equal deleted inserted replaced
-1:000000000000 0:ba25891c3a9e
       
     1 /*
       
     2 * Copyright (c) 2002-2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:   This file contains the implementation of CSisxUIInstall
       
    15 *                class member functions.
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 // INCLUDE FILES
       
    21 #include <aknmessagequerydialog.h>
       
    22 #include <aknlistquerydialog.h> // remove
       
    23 #include <StringLoader.h>
       
    24 #include <bautils.h>
       
    25 #include <eikenv.h>
       
    26 #include <data_caging_path_literals.hrh>
       
    27 #include <SWInstCommonUI.rsg>
       
    28 #include <pathinfo.h>
       
    29 #include <avkon.rsg>
       
    30 #include <DRMHelper.h>
       
    31 
       
    32 #include "CUIDetailsDialog.h"
       
    33 #include "CUICertificateDetailsDialog.h"
       
    34 #include "CUIUtils.h"
       
    35 
       
    36 using namespace SwiUI::CommonUI;
       
    37 
       
    38 // LOCAL CONSTANTS AND MACROS
       
    39 
       
    40 _LIT( KNextLine, "\n" );
       
    41 _LIT( KLinkTagOpen, "<AknMessageQuery Link>" );
       
    42 _LIT( KLinkTagClose, "</AknMessageQuery Link>" );
       
    43 
       
    44 // ============================ MEMBER FUNCTIONS ===============================
       
    45 
       
    46 // -----------------------------------------------------------------------------
       
    47 // CCUIDetailsDialog::CCUIDetailsDialog
       
    48 // C++ default constructor can NOT contain any code, that might leave.
       
    49 // -----------------------------------------------------------------------------
       
    50 //
       
    51 CCUIDetailsDialog::CCUIDetailsDialog()
       
    52     : iCbaResourceId( R_AVKON_SOFTKEYS_OK_EMPTY )
       
    53     {
       
    54     }
       
    55 
       
    56 // -----------------------------------------------------------------------------
       
    57 // CCUIDetailsDialog::CCUIDetailsDialog
       
    58 // C++ default constructor can NOT contain any code, that might leave.
       
    59 // -----------------------------------------------------------------------------
       
    60 //
       
    61 CCUIDetailsDialog::CCUIDetailsDialog( TInt aCbaResourceId )
       
    62     : iCbaResourceId( aCbaResourceId )
       
    63     {
       
    64     }
       
    65 // -----------------------------------------------------------------------------
       
    66 // CCUIDetailsDialog::CCUIDetailsDialog
       
    67 // C++ default constructor can NOT contain any code, that might leave.
       
    68 // -----------------------------------------------------------------------------
       
    69 //
       
    70 CCUIDetailsDialog::CCUIDetailsDialog( TInt aCbaResourceId, TCUIDetailsHeader aHeaderType )
       
    71     : iCbaResourceId( aCbaResourceId ), iHeaderType( aHeaderType )
       
    72     {
       
    73     }
       
    74 
       
    75 // -----------------------------------------------------------------------------
       
    76 // CCUIDetailsDialog::ConstructL
       
    77 // Symbian 2nd phase constructor can leave.
       
    78 // -----------------------------------------------------------------------------
       
    79 //
       
    80 void CCUIDetailsDialog::ConstructL()
       
    81     {    
       
    82     iCoeEnv = CEikonEnv::Static();    
       
    83     if ( !iCoeEnv )
       
    84         {
       
    85         User::Leave( KErrGeneral );        
       
    86         }
       
    87 
       
    88     TFileName fileName;
       
    89     fileName.Append( KDC_RESOURCE_FILES_DIR );
       
    90     fileName.Append( KCUIResourceFileName );
       
    91     iResourceFileOffset = CUIUtils::LoadResourceFileL( fileName, iCoeEnv );    
       
    92     }
       
    93 
       
    94 // -----------------------------------------------------------------------------
       
    95 // CCUICertificateDetailsDialog::NewL
       
    96 // Two-phased constructor.
       
    97 // -----------------------------------------------------------------------------
       
    98 //
       
    99 EXPORT_C CCUIDetailsDialog* CCUIDetailsDialog::NewL()
       
   100     {
       
   101     CCUIDetailsDialog* self = new ( ELeave ) CCUIDetailsDialog();
       
   102     CleanupStack::PushL( self );
       
   103     self->ConstructL();
       
   104     CleanupStack::Pop();
       
   105     return self;
       
   106     }
       
   107 
       
   108 // -----------------------------------------------------------------------------
       
   109 // CCUICertificateDetailsDialog::NewL
       
   110 // Two-phased constructor.
       
   111 // -----------------------------------------------------------------------------
       
   112 //
       
   113 EXPORT_C CCUIDetailsDialog* CCUIDetailsDialog::NewL( TInt aCbaResourceId )
       
   114     {
       
   115     CCUIDetailsDialog* self = new ( ELeave ) CCUIDetailsDialog( aCbaResourceId );
       
   116     CleanupStack::PushL( self );
       
   117     self->ConstructL();
       
   118     CleanupStack::Pop();
       
   119     return self;
       
   120     }
       
   121     
       
   122 // -----------------------------------------------------------------------------
       
   123 // CCUICertificateDetailsDialog::NewL
       
   124 // Two-phased constructor.
       
   125 // -----------------------------------------------------------------------------
       
   126 //
       
   127 EXPORT_C CCUIDetailsDialog* CCUIDetailsDialog::NewL( TInt aCbaResourceId,
       
   128                                                      TBool aWithInstallHeader )
       
   129     {
       
   130     CCUIDetailsDialog* self = new ( ELeave ) CCUIDetailsDialog( aCbaResourceId,
       
   131                                 ( aWithInstallHeader ? EInstallHeader : EDetailsHeader ) );
       
   132     CleanupStack::PushL( self );
       
   133     self->ConstructL();
       
   134     CleanupStack::Pop();
       
   135     return self;
       
   136     }
       
   137 
       
   138 // -----------------------------------------------------------------------------
       
   139 // CCUICertificateDetailsDialog::NewL
       
   140 // Two-phased constructor.
       
   141 // -----------------------------------------------------------------------------
       
   142 //
       
   143 EXPORT_C CCUIDetailsDialog* CCUIDetailsDialog::NewL( TInt aCbaResourceId,
       
   144                                                      TCUIDetailsHeader aHeaderType )
       
   145     {
       
   146     CCUIDetailsDialog* self = new ( ELeave ) CCUIDetailsDialog( aCbaResourceId,
       
   147                                                                 aHeaderType  );
       
   148     CleanupStack::PushL( self );
       
   149     self->ConstructL();
       
   150     CleanupStack::Pop();
       
   151     return self;
       
   152     }
       
   153 
       
   154 // Destructor
       
   155 EXPORT_C CCUIDetailsDialog::~CCUIDetailsDialog()
       
   156     {
       
   157     delete iMessageArray;    
       
   158    
       
   159     if( iResourceFileOffset )
       
   160         {
       
   161         iCoeEnv->DeleteResourceFile( iResourceFileOffset );
       
   162         }
       
   163 
       
   164     iCommonCertificates.Close();
       
   165     }
       
   166 
       
   167 // -----------------------------------------------------------------------------
       
   168 // CCUIDetailsDialog::ExecuteLD
       
   169 // Displays the dialog.
       
   170 // (other items were commented in a header).
       
   171 // -----------------------------------------------------------------------------
       
   172 //
       
   173 EXPORT_C TInt CCUIDetailsDialog::ExecuteLD( MCUIInfoIterator& aIterator )
       
   174     {
       
   175     return ShowDialogL( aIterator );
       
   176     }
       
   177 
       
   178 // -----------------------------------------------------------------------------
       
   179 // CCUIDetailsDialog::ExecuteLD
       
   180 // Displays the dialog with given certificates.
       
   181 // (other items were commented in a header).
       
   182 // -----------------------------------------------------------------------------
       
   183 //
       
   184 EXPORT_C TInt CCUIDetailsDialog::ExecuteLD( MCUIInfoIterator& aIterator,
       
   185                                             const RPointerArray<CCUICertificateInfo>& aCertInfos )
       
   186     {
       
   187     // Copy the certificates
       
   188     for ( TInt index = 0; index < aCertInfos.Count(); index++ )
       
   189         {
       
   190         iCommonCertificates.Append( aCertInfos[index] );        
       
   191         }
       
   192 
       
   193     return ShowDialogL( aIterator );    
       
   194     }
       
   195 
       
   196 // -----------------------------------------------------------------------------
       
   197 // CCUIDetailsDialog::ExecuteLD
       
   198 // Displays the dialog with given certificates.
       
   199 // (other items were commented in a header).
       
   200 // -----------------------------------------------------------------------------
       
   201 //
       
   202 EXPORT_C TInt CCUIDetailsDialog::ExecuteLD( MCUIInfoIterator& aIterator,
       
   203                                             RFile& aFile )
       
   204     {
       
   205     iFile = aFile;
       
   206     iFileSet = ETrue;
       
   207 
       
   208     return ShowDialogL( aIterator );
       
   209     }
       
   210 
       
   211 // -----------------------------------------------------------------------------
       
   212 // CCUIDetailsDialog::ExecuteLD
       
   213 // Displays the dialog with given certificates.
       
   214 // (other items were commented in a header).
       
   215 // -----------------------------------------------------------------------------
       
   216 //
       
   217 EXPORT_C TInt CCUIDetailsDialog::ExecuteLD( MCUIInfoIterator& aIterator,
       
   218                                             const RPointerArray<CCUICertificateInfo>& aCertInfos,
       
   219                                             RFile& aFile )
       
   220     {
       
   221     iFile = aFile;
       
   222     iFileSet = ETrue;
       
   223 
       
   224     return ExecuteLD( aIterator, aCertInfos );    
       
   225     }
       
   226 
       
   227 // -----------------------------------------------------------------------------
       
   228 // CCUIDetailsDialog::ShowDialogL
       
   229 // Helper to show the details dialog.
       
   230 // (other items were commented in a header).
       
   231 // -----------------------------------------------------------------------------
       
   232 //
       
   233 TInt CCUIDetailsDialog::ShowDialogL( MCUIInfoIterator& aIterator )
       
   234     {
       
   235     TInt result( 0 );
       
   236 
       
   237     CleanupStack::PushL( this );
       
   238 
       
   239     PopulateArrayL( aIterator );
       
   240     HBufC* message = GetMessageDescriptorLC();        
       
   241     
       
   242     // Create and show the message query dialog
       
   243     TCallBack certCallback( ShowCertificates, this );    
       
   244     TCallBack drmCallback( ShowDrm, this );
       
   245     
       
   246     CAknMessageQueryDialog* dlg = CAknMessageQueryDialog::NewL( *message );
       
   247     dlg->PrepareLC( R_SWCOMMON_DETAILS_DIALOG );
       
   248 #ifdef RD_COMBINE_INSTALLATION_QUERIES
       
   249     HBufC* header = NULL;
       
   250     switch( iHeaderType )
       
   251         {
       
   252         case EInstallAndDownloadHeader:
       
   253             header = StringLoader::LoadLC( R_SWCOMMON_HEADER_DOWNLOAD );
       
   254             dlg->QueryHeading()->SetTextL( *header );
       
   255             CleanupStack::PopAndDestroy( header );
       
   256             break;
       
   257             
       
   258         case EInstallHeader:
       
   259             header = StringLoader::LoadLC( R_SWCOMMON_HEADER_INSTALL );
       
   260             dlg->QueryHeading()->SetTextL( *header );
       
   261             CleanupStack::PopAndDestroy( header );
       
   262             break;
       
   263             
       
   264         case EDetailsHeader:
       
   265         default:
       
   266             break;
       
   267         }
       
   268 #endif //RD_COMBINE_INSTALLATION_QUERIES
       
   269     dlg->ButtonGroupContainer().SetCommandSetL( iCbaResourceId );
       
   270     
       
   271     if ( iCommonCertificates.Count() > 0 )
       
   272         {
       
   273         dlg->SetLink( certCallback );
       
   274         }
       
   275     if ( iFileSet )
       
   276         {        
       
   277         dlg->SetLink( drmCallback );
       
   278         }    
       
   279     
       
   280     result = dlg->RunLD();
       
   281     CleanupStack::PopAndDestroy( 2 ); // message, this
       
   282 
       
   283     return result;    
       
   284     }
       
   285 
       
   286 // -----------------------------------------------------------------------------
       
   287 // CCUIDetailsDialog::SetFieldL
       
   288 // Sets a field in the details dialog.
       
   289 // (other items were commented in a header).
       
   290 // -----------------------------------------------------------------------------
       
   291 //
       
   292 void CCUIDetailsDialog::SetFieldL( CDesCArray& aItemArray,
       
   293                                    const TDesC& aHeading, 
       
   294                                    const TDesC& aValue )
       
   295     {
       
   296     HBufC* temp = HBufC::NewLC( aHeading.Length() + aValue.Length() + 3 );
       
   297     TPtr ptr( temp->Des() );
       
   298     
       
   299     if ( aItemArray.Count() > 0 )
       
   300         {
       
   301         ptr += KNextLine;
       
   302         ptr += KNextLine;        
       
   303         }
       
   304     
       
   305     ptr += aHeading;        
       
   306     ptr += KNextLine;
       
   307     if ( aValue.Length() > 0 )
       
   308         {
       
   309         ptr += aValue;
       
   310         }    
       
   311     aItemArray.AppendL( *temp );    
       
   312     CleanupStack::PopAndDestroy( temp );    
       
   313     }
       
   314 
       
   315 // -----------------------------------------------------------------------------
       
   316 // CCUIDetailsDialog::PopulateArrayL
       
   317 // Helper to populate the field array.
       
   318 // (other items were commented in a header).
       
   319 // -----------------------------------------------------------------------------
       
   320 //
       
   321 void CCUIDetailsDialog::PopulateArrayL( MCUIInfoIterator& aIterator )
       
   322     {
       
   323     delete iMessageArray;    
       
   324     iMessageArray = NULL;    
       
   325     iMessageArray = new (ELeave) CDesCArrayFlat( 8 );
       
   326 
       
   327     // Construct the text to be shown
       
   328     aIterator.Reset();    
       
   329     while ( aIterator.HasNext() )
       
   330         {
       
   331         TPtrC heading;
       
   332         TPtrC value;
       
   333         
       
   334         aIterator.Next( heading, value );
       
   335         SetFieldL( *iMessageArray, heading, value );        
       
   336         }
       
   337     }
       
   338 
       
   339 // -----------------------------------------------------------------------------
       
   340 // CCUIDetailsDialog::GetMessageDescriptorLC
       
   341 // Helper to get descriptor containing the fields of the dialog.
       
   342 // (other items were commented in a header).
       
   343 // -----------------------------------------------------------------------------
       
   344 //
       
   345 HBufC* CCUIDetailsDialog::GetMessageDescriptorLC()
       
   346     {
       
   347     TInt size( 0 ); 
       
   348     TInt index( 0 );
       
   349 
       
   350     HBufC* type = StringLoader::LoadLC( R_SWCOMMON_DETAIL_TYPE );    
       
   351     HBufC* typeString = HBufC::NewLC( type->Length() + 1);
       
   352     typeString->Des().Copy( *type );
       
   353     typeString->Des().Append( KNextLine() );    
       
   354 
       
   355     HBufC* message = HBufC::NewLC( size );    
       
   356     
       
   357     for ( index = 0; index < iMessageArray->Count(); index++ )
       
   358         {       
       
   359         HBufC* tmp = message;
       
   360         message = message->ReAllocL( tmp->Length() + (*iMessageArray)[index].Length() );
       
   361         CleanupStack::Pop( tmp );
       
   362         CleanupStack::PushL( message );
       
   363         
       
   364         message->Des().Append( (*iMessageArray)[index] );
       
   365         // If this is the type field we need to add possible certificates and
       
   366         // drm details
       
   367         if ( (*iMessageArray)[index].Find( *typeString ) == 2 )
       
   368             {
       
   369             if ( iCommonCertificates.Count() > 0 )
       
   370                 {
       
   371                 AddCertificatesLC( message );                
       
   372                 }            
       
   373             if ( iFileSet )
       
   374                 {
       
   375                 AddDrmLC( message );                
       
   376                 }            
       
   377             }        
       
   378         }    
       
   379 
       
   380     CleanupStack::Pop( message );
       
   381     CleanupStack::PopAndDestroy( 2, type );
       
   382     CleanupStack::PushL( message );    
       
   383 
       
   384     return message;    
       
   385     }
       
   386 
       
   387 // -----------------------------------------------------------------------------
       
   388 // CCUIDetailsDialog::AddCertificatesLC
       
   389 // Helper to add certificate information to query text.
       
   390 // (other items were commented in a header).
       
   391 // -----------------------------------------------------------------------------
       
   392 //
       
   393 void CCUIDetailsDialog::AddCertificatesLC( HBufC*& aMessage )
       
   394     {
       
   395     HBufC* certHeading = StringLoader::LoadLC( R_SWCOMMON_DETAIL_CERTIFICATES );
       
   396     HBufC* certificateLink = LoadLinkLC( R_SWCOMMON_DETAIL_VALUE_VIEW_CERT );
       
   397     HBufC* newString = HBufC::NewL( certHeading->Length() + 
       
   398                                     aMessage->Length() + 
       
   399                                     certificateLink->Length() + 
       
   400                                     3 );
       
   401 
       
   402     TPtr ptr( newString->Des() );
       
   403     ptr += *aMessage;        
       
   404     ptr += KNextLine;
       
   405     ptr += KNextLine;
       
   406     ptr += *certHeading;
       
   407     ptr += KNextLine;
       
   408     ptr += *certificateLink;
       
   409    
       
   410     CleanupStack::PopAndDestroy( 3, aMessage );
       
   411   
       
   412     aMessage = newString;
       
   413     CleanupStack::PushL( aMessage ); 
       
   414     }
       
   415 
       
   416 // -----------------------------------------------------------------------------
       
   417 // CCUIDetailsDialog::AddDrmLC
       
   418 // Helper to add DRM information to query text.
       
   419 // (other items were commented in a header).
       
   420 // -----------------------------------------------------------------------------
       
   421 //
       
   422 void CCUIDetailsDialog::AddDrmLC( HBufC*& aMessage )
       
   423     {
       
   424     HBufC* drmHeading = StringLoader::LoadLC( R_SWCOMMON_DETAIL_DRM );
       
   425     HBufC* drmLink = LoadLinkLC( R_SWCOMMON_DETAIL_VALUE_VIEW_DRM );
       
   426     HBufC* newString = HBufC::NewL( drmHeading->Length() + 
       
   427                                     aMessage->Length() + 
       
   428                                     drmLink->Length() + 
       
   429                                     3 );
       
   430 
       
   431     TPtr ptr( newString->Des() );
       
   432     ptr += *aMessage;        
       
   433     ptr += KNextLine;
       
   434     ptr += KNextLine;
       
   435     ptr += *drmHeading;
       
   436     ptr += KNextLine;
       
   437     ptr += *drmLink;
       
   438     
       
   439     CleanupStack::PopAndDestroy( 3, aMessage );
       
   440   
       
   441     aMessage = newString;
       
   442     CleanupStack::PushL( aMessage ); 
       
   443     }
       
   444 
       
   445 // -----------------------------------------------------------------------------
       
   446 // CCUIDetailsDialog::ShowCertificates
       
   447 // Used as a callback function in message query.
       
   448 // (other items were commented in a header).
       
   449 // -----------------------------------------------------------------------------
       
   450 //
       
   451 TInt CCUIDetailsDialog::ShowCertificates( TAny* ptr )
       
   452     {
       
   453     TInt err( KErrNone );    
       
   454     CCUIDetailsDialog* self = static_cast<CCUIDetailsDialog*>(ptr);
       
   455     TRAP( err, self->DoShowCertificatesL() );
       
   456     return err;    
       
   457     }
       
   458 
       
   459 // -----------------------------------------------------------------------------
       
   460 // CCUIDetailsDialog::ShowDrm
       
   461 // Used as a callback function in message query.
       
   462 // (other items were commented in a header).
       
   463 // -----------------------------------------------------------------------------
       
   464 //
       
   465 TInt CCUIDetailsDialog::ShowDrm( TAny* ptr )
       
   466     {
       
   467     TInt err( KErrNone );    
       
   468     CCUIDetailsDialog* self = static_cast<CCUIDetailsDialog*>(ptr);
       
   469     TRAP( err, self->DoShowDrmL() );
       
   470     return err;    
       
   471     }
       
   472 
       
   473 // -----------------------------------------------------------------------------
       
   474 // CCUIDetailsDialog::DoShowCertificatesL
       
   475 // Show CCUICertificateInfo certificates.
       
   476 // (other items were commented in a header).
       
   477 // -----------------------------------------------------------------------------
       
   478 //
       
   479 void CCUIDetailsDialog::DoShowCertificatesL()
       
   480     {
       
   481     if ( iCommonCertificates.Count() > 1 )
       
   482         {
       
   483         CDesCArrayFlat *itemArray = new( ELeave ) CDesCArrayFlat( 2 );
       
   484         CleanupStack::PushL( itemArray );
       
   485 
       
   486         for ( TInt index = 0; index < iCommonCertificates.Count(); index++ )
       
   487             {
       
   488             itemArray->AppendL( iCommonCertificates[index]->IssuerNameL() );            
       
   489             }        
       
   490 
       
   491         TInt selection( 0 );
       
   492         TInt dlgResult( EAknSoftkeyOk );
       
   493         
       
   494         while ( dlgResult )
       
   495             {
       
   496             // First show a dialog where user can select the certificate, which
       
   497             // will be viewed in more detail
       
   498             CAknListQueryDialog* dlg = new ( ELeave ) CAknListQueryDialog( &selection );
       
   499             dlg->PrepareLC( R_SWCOMMON_SEC_SELECTION_DIALOG );
       
   500             dlg->SetItemTextArray( itemArray );
       
   501             dlg->SetOwnershipType( ELbmDoesNotOwnItemArray );
       
   502             dlg->ListBox()->SetCurrentItemIndex( selection );            
       
   503 
       
   504             dlgResult = dlg->RunLD();
       
   505             if ( dlgResult )
       
   506                 {
       
   507                 // Show details about the selected certificate
       
   508                 CCUICertificateDetailsDialog* certDlg = 
       
   509                     CCUICertificateDetailsDialog::NewL();
       
   510                 
       
   511                 certDlg->ExecuteLD( *( iCommonCertificates[selection] ) );    
       
   512                 }            
       
   513             }        
       
   514 
       
   515         CleanupStack::PopAndDestroy( itemArray );
       
   516         }   
       
   517     else if ( iCommonCertificates.Count() == 1 )
       
   518         {
       
   519         CCUICertificateDetailsDialog* certDlg = 
       
   520             CCUICertificateDetailsDialog::NewL();
       
   521                 
       
   522         certDlg->ExecuteLD( *( iCommonCertificates[0] ) );    
       
   523         }    
       
   524     }
       
   525 
       
   526 // -----------------------------------------------------------------------------
       
   527 // CCUIDetailsDialog::DoShowDrmL
       
   528 // Show detailed drm info.
       
   529 // (other items were commented in a header).
       
   530 // -----------------------------------------------------------------------------
       
   531 //
       
   532 void CCUIDetailsDialog::DoShowDrmL()
       
   533     {
       
   534     CDRMHelper* helper = CDRMHelper::NewLC( *iCoeEnv );
       
   535     helper->LaunchDetailsViewEmbeddedL( iFile );   
       
   536     CleanupStack::PopAndDestroy( helper );    
       
   537     }
       
   538 
       
   539 // -----------------------------------------------------------------------------
       
   540 // CCUIDetailsDialog::LoadLinkLC
       
   541 // Helper to construct a message query link from resource string.
       
   542 // (other items were commented in a header).
       
   543 // -----------------------------------------------------------------------------
       
   544 //
       
   545 HBufC* CCUIDetailsDialog::LoadLinkLC( TInt aResourceId )
       
   546     {
       
   547     HBufC* link = StringLoader::LoadLC( aResourceId );
       
   548     HBufC* tmp = link->ReAllocL( link->Length() + KLinkTagOpen().Length() + KLinkTagClose().Length() );
       
   549     
       
   550     CleanupStack::Pop( link );
       
   551     link = tmp;
       
   552     CleanupStack::PushL( link );
       
   553     
       
   554     link->Des().Insert(0, KLinkTagOpen);
       
   555     link->Des().Append( KLinkTagClose );   
       
   556 
       
   557     return link;    
       
   558     }
       
   559 
       
   560 //  End of File