menucontentsrv/engsrc/menueng.cpp
branchRCL_3
changeset 114 a5a39a295112
equal deleted inserted replaced
113:0efa10d348c0 114:a5a39a295112
       
     1 /*
       
     2 * Copyright (c) 2009 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:
       
    15 *
       
    16 */
       
    17 
       
    18 // INCLUDE FILES
       
    19 
       
    20 #include <xcfwtree.h>
       
    21 #include <xcfwengine.h>
       
    22 #include <pathinfo.h>
       
    23 #include <f32file.h>
       
    24 #include <sysutil.h>
       
    25 #include "menueng.h"
       
    26 #include "menuengobjectfactoryproxy.h"
       
    27 #include "menuengobject.h"
       
    28 #include "menuengobserver.h"
       
    29 #include "menuengoperation.h"
       
    30 #include "menuengfilter.h"
       
    31 #include "menuengvisitor.h"
       
    32 #include "menuengitemlister.h"
       
    33 #include "menuengdeletionchecker.h"
       
    34 #include "menuengidmanagerinit.h"
       
    35 #include "menuengidsetter.h"
       
    36 #include "menuengidmanager.h"
       
    37 #include "menuengidcollector.h"
       
    38 #include "menuengflags.h"
       
    39 #include "mcsmenuitem.h" // for flags
       
    40 
       
    41 // CONSTANTS
       
    42 
       
    43 LOCAL_D const TInt KDriveAndColon = 2; //drive letter and colon, e.g. "c:"
       
    44 _LIT( KMenuTypeIdSeed, "menu:id_seed" );
       
    45 _LIT( KMenuAttrIdSeed, "seed" );
       
    46 _LIT( KMenuContentDirName, "content\\" );
       
    47 _LIT( KMenuContentExtension, ".xml" );
       
    48 _LIT( KMenuTempExtension, ".$$$" );
       
    49 
       
    50 // ================= LOCAL FUNCTIONS =======================
       
    51 
       
    52 /**
       
    53 * Insert string into other string, checking vaailable space.
       
    54 * Leaves with KErrOverflow if aSoure cannot be inserted to aTarget.
       
    55 * @param aTarget Target descriptor.
       
    56 * @param aPos Insertion point.
       
    57 * @param aSource Source descriptor.
       
    58 */
       
    59 LOCAL_C void InsertL( TDes& aTarget, TInt aPos, const TDesC& aSource )
       
    60     {
       
    61     if ( aTarget.MaxLength() < aTarget.Length() + aSource.Length() )
       
    62         {
       
    63         User::Leave( KErrOverflow );
       
    64         }
       
    65     aTarget.Insert( aPos, aSource );
       
    66     }
       
    67 
       
    68 /**
       
    69 * Append string to the end of other string, checking available space.
       
    70 * Leaves with KErrOverflow if aSource cannot be appended to aTarget.
       
    71 * @param aTarget Target descriptor.
       
    72 * @param aSource Source descriptor.
       
    73 */
       
    74 LOCAL_C void AppendL( TDes& aTarget, const TDesC& aSource )
       
    75     {
       
    76     if ( aTarget.MaxLength() < aTarget.Length() + aSource.Length() )
       
    77         {
       
    78         User::Leave( KErrOverflow );
       
    79         }
       
    80     aTarget.Append( aSource );
       
    81     }
       
    82 
       
    83 // ================= MEMBER FUNCTIONS =======================
       
    84 
       
    85 // ---------------------------------------------------------
       
    86 // CMenuEng::Object
       
    87 // ---------------------------------------------------------
       
    88 //
       
    89 CMenuEngObject& CMenuEng::Object( MXCFWNode& aNode ) const
       
    90     {
       
    91     return (CMenuEngObject&)(*aNode.Data());
       
    92     }
       
    93 
       
    94 // ---------------------------------------------------------
       
    95 // CMenuEng::~CMenuEng
       
    96 // ---------------------------------------------------------
       
    97 //
       
    98 EXPORT_C CMenuEng::~CMenuEng()
       
    99     {
       
   100     Cancel();
       
   101     CancelAllOperations();
       
   102     iOperations.Close();
       
   103     iNotifyQueue.Close();
       
   104     delete iEngine;
       
   105     delete iTree;
       
   106     delete iObjectFactory;
       
   107     delete iIdManager;
       
   108     iFs.Close();
       
   109     iName.Close();
       
   110     iTempFileName.Close();
       
   111     iRamFileName.Close();
       
   112     delete iActiveWait;
       
   113     }
       
   114 
       
   115 // ---------------------------------------------------------
       
   116 // CMenuEng::NewL
       
   117 // ---------------------------------------------------------
       
   118 //
       
   119 EXPORT_C CMenuEng* CMenuEng::NewL
       
   120 ( const TDesC& aName, MMenuEngObserver& aObserver )
       
   121     {
       
   122     CMenuEng* eng = new (ELeave) CMenuEng( aObserver );
       
   123     CleanupStack::PushL( eng );
       
   124     eng->ConstructL( aName );
       
   125     CleanupStack::Pop( eng );
       
   126     return eng;
       
   127     }
       
   128 
       
   129 // ---------------------------------------------------------
       
   130 // CMenuEng::CMenuEng
       
   131 // ---------------------------------------------------------
       
   132 //
       
   133 CMenuEng::CMenuEng( MMenuEngObserver& aObserver )
       
   134 : CActive( CActive::EPriorityStandard ), iObserver( aObserver )
       
   135     {
       
   136     CActiveScheduler::Add( this );
       
   137     iLegacyFormat = EFalse;
       
   138     }
       
   139 
       
   140 // ---------------------------------------------------------
       
   141 // CMenuEng::ConstructL
       
   142 // ---------------------------------------------------------
       
   143 //
       
   144 void CMenuEng::ConstructL( const TDesC& aName )
       
   145     {
       
   146     ValidateNameL( aName );
       
   147     iName.CreateL( aName );
       
   148     User::LeaveIfError( iFs.Connect() );
       
   149     // Keep temp file and the RAM file name as members -
       
   150     // we use these all the time.
       
   151     TFileName fname;
       
   152     GetFileNameL( fname, ETempFile );
       
   153     iTempFileName.CreateL( fname );
       
   154     GetFileNameL( fname, ERamFile );
       
   155     iRamFileName.CreateL( fname );
       
   156     iObjectFactory = CMenuEngObjectFactoryProxy::NewL( *this );
       
   157     iEngine = CXCFWEngine::NewL( this );
       
   158     iEngine->RegisterObjectFactoryL( iObjectFactory );
       
   159     SelfComplete( KErrNone ); 	// Start processing asynchronously.
       
   160     ActiveWaitForFileLoadL();	//we need to wait until parsing is complete
       
   161     }
       
   162 
       
   163 // ---------------------------------------------------------
       
   164 // CMenuEng::QueueOperationL
       
   165 // ---------------------------------------------------------
       
   166 //
       
   167 EXPORT_C void CMenuEng::QueueOperationL( MMenuEngOperation& aOperation )
       
   168     {
       
   169     __ASSERT_DEBUG( KErrNotFound == iOperations.Find( &aOperation ), \
       
   170                     User::Invariant() );
       
   171     iOperations.AppendL( &aOperation );
       
   172     // If idle, kick back into life.
       
   173     if ( EReady == iState )
       
   174         {
       
   175         iState = EExecuteOp;
       
   176         SelfComplete( KErrNone );
       
   177         }
       
   178     }
       
   179 
       
   180 // ---------------------------------------------------------
       
   181 // CMenuEng::DequeueOperation
       
   182 // ---------------------------------------------------------
       
   183 //
       
   184 EXPORT_C void CMenuEng::DequeueOperation( MMenuEngOperation& aOperation )
       
   185     {
       
   186     if ( iCurrentOperation == &aOperation )
       
   187         {
       
   188         iCurrentOperation = NULL;
       
   189         }
       
   190     TInt i = iOperations.Find( &aOperation );
       
   191     if ( KErrNotFound != i )
       
   192         {
       
   193         iOperations.Remove( i );
       
   194         }
       
   195     }
       
   196 
       
   197 // ---------------------------------------------------------
       
   198 // CMenuEng::TraverseFolderL
       
   199 // ---------------------------------------------------------
       
   200 //
       
   201 EXPORT_C void CMenuEng::TraverseFolderL
       
   202 ( TInt aFolder, MMenuEngVisitor& aVisitor ) const
       
   203     {
       
   204     if ( !iTree )
       
   205         {
       
   206         User::Leave( KErrNotReady );
       
   207         }
       
   208     TraverseNodeL( FolderNodeL( aFolder ), aVisitor );
       
   209     }
       
   210 
       
   211 // ---------------------------------------------------------
       
   212 // CMenuEng::NewObjectL
       
   213 // ---------------------------------------------------------
       
   214 //
       
   215 EXPORT_C CMenuEngObject* CMenuEng::NewObjectL( const TDesC& aType )
       
   216     {
       
   217     if ( !iIdManager )
       
   218         {
       
   219         User::Leave( KErrNotReady );
       
   220         }
       
   221     CMenuEngObject* object = CMenuEngObject::NewL( *this, aType );
       
   222     CleanupStack::PushL( object );
       
   223     TInt id;
       
   224     iIdManager->AllocL( id );
       
   225     object->SetId( id );
       
   226     CleanupStack::Pop( object );
       
   227     return object;
       
   228     }
       
   229 
       
   230 // ---------------------------------------------------------
       
   231 // CMenuEng::RootFolderL
       
   232 // ---------------------------------------------------------
       
   233 //
       
   234 EXPORT_C void CMenuEng::RootFolderL( TInt& aId ) const
       
   235     {
       
   236     if ( !iTree )
       
   237         {
       
   238         User::Leave( KErrNotReady );
       
   239         }
       
   240     aId = iRoot;
       
   241     }
       
   242 
       
   243 // ---------------------------------------------------------
       
   244 // CMenuEng::ParentFolderL
       
   245 // ---------------------------------------------------------
       
   246 //
       
   247 EXPORT_C void CMenuEng::ParentFolderL( TInt aId, TInt& aParentId ) const
       
   248     {
       
   249     if ( !iTree )
       
   250         {
       
   251         User::Leave( KErrNotReady );
       
   252         }
       
   253     TInt parentId = 0;
       
   254     if ( aId != iRoot )
       
   255         {
       
   256         // We may have nodes above the root, but do not allow access to those.
       
   257         // Say 0 to the root's parent.
       
   258         MXCFWNode* parentNode = NodeL( aId ).Parent();
       
   259         if ( parentNode )
       
   260             {
       
   261             parentId = Object( *parentNode ).Id();
       
   262             }
       
   263         }
       
   264     aParentId = parentId;
       
   265     }
       
   266 
       
   267 // ---------------------------------------------------------
       
   268 // CMenuEng::GetItemL
       
   269 // ---------------------------------------------------------
       
   270 //
       
   271 EXPORT_C void CMenuEng::GetItemL( TInt aId, TMenuItem& aItem ) const
       
   272     {
       
   273     if ( !iTree )
       
   274         {
       
   275         User::Leave( KErrNotReady );
       
   276         }
       
   277     const CMenuEngObject& object = ObjectL( aId );
       
   278     aItem.SetId( object.Id() );
       
   279     aItem.SetFlags( object.Flags() );
       
   280     aItem.SetType( object.Type() );
       
   281     TInt parent;
       
   282     ParentFolderL( aId, parent );
       
   283     aItem.SetParent( parent );
       
   284     }
       
   285 
       
   286 // ---------------------------------------------------------
       
   287 // CMenuEng::GetItemsL
       
   288 // ---------------------------------------------------------
       
   289 //
       
   290 EXPORT_C void CMenuEng::GetItemsL(
       
   291         RArray<TMenuItem>& aItemArray,
       
   292         TInt aFolder,
       
   293         const MMenuEngFilter* aFilter,
       
   294         TBool aRecursive ) const
       
   295     {
       
   296     if ( !iTree )
       
   297         {
       
   298         User::Leave( KErrNotReady );
       
   299         }
       
   300     TMenuEngItemLister lister
       
   301         ( *this, aItemArray, aFolder, aFilter, aRecursive );
       
   302     TraverseFolderL( aFolder, lister );
       
   303     }
       
   304 
       
   305 // ---------------------------------------------------------
       
   306 // CMenuEng::ObjectL
       
   307 // ---------------------------------------------------------
       
   308 //
       
   309 EXPORT_C const CMenuEngObject& CMenuEng::ObjectL( TInt aId ) const
       
   310     {
       
   311     if ( !iTree )
       
   312         {
       
   313         User::Leave( KErrNotReady );
       
   314         }
       
   315     return Object( NodeL( aId ) );
       
   316     }
       
   317 
       
   318 // ---------------------------------------------------------
       
   319 // CMenuEng::GetLegacyFormat
       
   320 // ---------------------------------------------------------
       
   321 //
       
   322 EXPORT_C TBool CMenuEng::GetOnceLegacyFormat()
       
   323     {
       
   324     TBool format = iLegacyFormat;
       
   325     iLegacyFormat = EFalse;
       
   326     return format;
       
   327     }
       
   328 
       
   329 // ---------------------------------------------------------
       
   330 // CMenuEng::RemoveL
       
   331 // ---------------------------------------------------------
       
   332 //
       
   333 EXPORT_C void CMenuEng::RemoveL( TInt aId )
       
   334     {
       
   335 	if ( SysUtil::DiskSpaceBelowCriticalLevelL( &iFs, 0, EDriveC) )
       
   336 		{
       
   337 		User::Leave( KErrDiskFull );
       
   338 		}
       
   339     if ( iState != EExecuteOp )
       
   340         {
       
   341         User::Leave( KErrLocked );
       
   342         }
       
   343     // Check if aId exists.
       
   344     MXCFWNode& node = NodeL( aId );
       
   345     // Can't delete the root.
       
   346     if ( aId == iRoot )
       
   347         {
       
   348         User::Leave( KErrAccessDenied );
       
   349         }
       
   350     // Can't delete read-only items, or folders containing any read-only items.
       
   351     TMenuEngDeletionChecker checker;
       
   352     TraverseNodeL( node, checker );
       
   353     // Get the IDs of items to be deleted.
       
   354     RArray<TInt> deletedIds;
       
   355     CleanupClosePushL( deletedIds );
       
   356     TMenuEngIdCollector idCollector( deletedIds );
       
   357     TraverseNodeL( node, idCollector );
       
   358     // Add notification event.
       
   359     MXCFWNode* parent = node.Parent();
       
   360     __ASSERT_DEBUG( parent, User::Invariant() );
       
   361     AppendNotifyL( Object( *parent ).Id(),
       
   362                    RMenuNotifier::EItemsAddedRemoved );
       
   363     // Delete node.
       
   364     iTree->RemoveNodeL( &node );
       
   365     iChanged = ETrue;
       
   366     // Deletion successful, remove the IDs.
       
   367     for ( TInt i = 0; i < deletedIds.Count(); i++ )
       
   368         {
       
   369         iIdManager->Remove( deletedIds[i] );
       
   370         }
       
   371     CleanupStack::PopAndDestroy( &deletedIds );
       
   372     }
       
   373 
       
   374 // ---------------------------------------------------------
       
   375 // CMenuEng::MoveToFolderL
       
   376 // ---------------------------------------------------------
       
   377 //
       
   378 EXPORT_C void CMenuEng::MoveToFolderL
       
   379 ( RArray<TInt>& aItems, TInt aFolder, TInt aMoveBefore )
       
   380     {
       
   381 	if ( SysUtil::DiskSpaceBelowCriticalLevelL( &iFs, 0, EDriveC) )
       
   382 		{
       
   383 		User::Leave( KErrDiskFull );
       
   384 		}
       
   385     if ( iState != EExecuteOp )
       
   386         {
       
   387         User::Leave( KErrLocked );
       
   388         }
       
   389     TInt i;
       
   390     TInt id;
       
   391     MXCFWNode* fromFolder = NULL;
       
   392     // Check that toFolder exists.
       
   393     MXCFWNode& toFolder = FolderNodeL( aFolder );
       
   394     CMenuEngObject& toFolderObj = Object( toFolder );
       
   395     // Check that we can move items into target toFolder.
       
   396     if ( toFolderObj.Flags() & TMenuItem::ELockMoveInto )
       
   397         {
       
   398         User::Leave( KErrAccessDenied );
       
   399         }
       
   400     // Check that all items exist and they are not locked against moving.
       
   401     // Also check that and they are in the same toFolder.
       
   402     if ( aItems.Count() )
       
   403         {
       
   404         fromFolder = NodeL( aItems[0] ).Parent();
       
   405         for ( i = 0; i< aItems.Count(); i++ )
       
   406             {
       
   407             id = aItems[i];
       
   408             if ( id == iRoot )
       
   409                 {
       
   410                 User::Leave( KErrAccessDenied ); // Can't move the root.
       
   411                 }
       
   412             MXCFWNode& node = NodeL( id );
       
   413             if ( Object( node ).Flags() & TMenuItem::ELockItem )
       
   414                 {
       
   415                 User::Leave( KErrAccessDenied ); // lock_item
       
   416                 }
       
   417             if ( node.Parent() != fromFolder )
       
   418                 {
       
   419                 User::Leave( KErrArgument ); // Items from different folders.
       
   420                 }
       
   421             }
       
   422         // Add notification events. Presume that there will be no recursion.
       
   423         // If there is recursion, then we make an unnecessary notify, that is
       
   424         // better than missing one.
       
   425         __ASSERT_DEBUG( fromFolder, User::Invariant() );
       
   426         AppendNotifyL( Object( *fromFolder ).Id(),
       
   427                        RMenuNotifier::EItemsAddedRemoved );
       
   428         AppendNotifyL( toFolderObj.Id(),
       
   429                        RMenuNotifier::EItemsAddedRemoved );
       
   430         // Do move the items.
       
   431         // Recursion check is done by the XML tree (->KErrArgument).
       
   432         MXCFWNode* moveBefore = Child( toFolder, aMoveBefore );
       
   433         for ( i = 0; i < aItems.Count(); i++ )
       
   434             {
       
   435             iTree->MoveNodeL( &NodeL( aItems[i] ), &toFolder, moveBefore );
       
   436             }
       
   437         iChanged = ETrue;
       
   438         }
       
   439     }
       
   440 
       
   441 // ---------------------------------------------------------
       
   442 // CMenuEng::ReorderL
       
   443 // ---------------------------------------------------------
       
   444 //
       
   445 EXPORT_C void CMenuEng::ReorderL( TInt aId, TInt aMoveBefore )
       
   446     {
       
   447 	if ( SysUtil::DiskSpaceBelowCriticalLevelL( &iFs, 0, EDriveC) )
       
   448 		{
       
   449 		User::Leave( KErrDiskFull );
       
   450 		}
       
   451     if ( iState != EExecuteOp )
       
   452         {
       
   453         User::Leave( KErrLocked );
       
   454         }
       
   455     // Can't reorder the root.
       
   456     if ( aId == iRoot )
       
   457         {
       
   458         User::Leave( KErrArgument );
       
   459         }
       
   460     // Check if aId exists.
       
   461     MXCFWNode& node = NodeL( aId );
       
   462     // Check if item can be reordered.
       
   463     if ( Object( node ).Flags() & TMenuItem::ELockItem )
       
   464         {
       
   465         User::Leave( KErrAccessDenied ); // lock_item
       
   466         }
       
   467     MXCFWNode* parent = node.Parent();
       
   468     __ASSERT_DEBUG( parent, User::Invariant() );
       
   469     if ( parent )
       
   470         {
       
   471         // Add notification event.
       
   472         AppendNotifyL( Object( *parent ).Id(),
       
   473                        RMenuNotifier::EItemsReordered );
       
   474         // Move it.
       
   475         MXCFWNode* moveBefore = Child( *parent, aMoveBefore );
       
   476         iTree->MoveNodeL( &node, parent, moveBefore );
       
   477         iChanged = ETrue;
       
   478         }
       
   479     }
       
   480 
       
   481 // ---------------------------------------------------------
       
   482 // CMenuEng::AddL
       
   483 // ---------------------------------------------------------
       
   484 //
       
   485 EXPORT_C void CMenuEng::AddL
       
   486 ( CMenuEngObject& aObject, TInt aFolder, TInt aInsertBefore )
       
   487     {
       
   488 	if ( SysUtil::DiskSpaceBelowCriticalLevelL( &iFs, 0, EDriveC) )
       
   489 		{
       
   490 		User::Leave( KErrDiskFull );
       
   491 		}
       
   492     if ( &aObject.Engine() != this )
       
   493         {
       
   494         // ID integrity requires that objects are bound to engines.
       
   495         User::Leave( KErrArgument );
       
   496         }
       
   497     if ( iState != EExecuteOp )
       
   498         {
       
   499         User::Leave( KErrLocked );
       
   500         }
       
   501     if ( KMenuTypeData() == aObject.Type() )
       
   502         {
       
   503         // Internal type, disallow.
       
   504         User::Leave( KErrArgument );
       
   505         }
       
   506     // Check if aFolder exists.
       
   507     MXCFWNode& folder = FolderNodeL( aFolder );
       
   508     // Check if folder is locked.
       
   509     if ( Object( folder ).Flags() & TMenuItem::ELockMoveInto )
       
   510         {
       
   511         User::Leave( KErrAccessDenied ); // lock_moveinto
       
   512         }
       
   513     // Add notification event.
       
   514     AppendNotifyL( aFolder, RMenuNotifier::EItemsAddedRemoved );
       
   515     // Add the node.
       
   516     MXCFWNode* insertBefore = Child( folder, aInsertBefore );
       
   517     if ( insertBefore )
       
   518         {
       
   519         iTree->AddNodeL( &aObject, &folder, insertBefore );
       
   520         // No leaving after this point - ownership of aObject taken by the
       
   521         // tree. (Well, almost -- CXCFWTree is buggy, but hopefully it will
       
   522         // be fixed.)
       
   523         }
       
   524     else
       
   525         {
       
   526         // CXCFWTree API design flaw:
       
   527         // AddNodeL( &aObject, &folder, NULL ) leaves with KErrArgument!
       
   528         iTree->AddNodeL( &aObject, &folder );
       
   529         // No leaving after this point - ownership of aObject taken by the
       
   530         // tree. (Well, almost -- CXCFWTree is buggy, but hopefully it will
       
   531         // be fixed.)
       
   532         }
       
   533     iChanged = ETrue;
       
   534     }
       
   535 
       
   536 // ---------------------------------------------------------
       
   537 // CMenuEng::ModifiableObjectL
       
   538 // ---------------------------------------------------------
       
   539 //
       
   540 EXPORT_C CMenuEngObject& CMenuEng::ModifiableObjectL( TInt aId , TInt aEvent)
       
   541     {
       
   542     if ( !iTree )
       
   543         {
       
   544         User::Leave( KErrNotReady );
       
   545         }
       
   546     if ( iState != EExecuteOp )
       
   547         {
       
   548         User::Leave( KErrLocked );
       
   549         }
       
   550     MXCFWNode& node = NodeL( aId );
       
   551     CMenuEngObject& object = Object( node );
       
   552     // Add notification event.
       
   553     MXCFWNode* parent = node.Parent();
       
   554     __ASSERT_DEBUG( parent, User::Invariant() );
       
   555     if( aEvent != RMenuNotifier::EItemsNone )
       
   556     	{
       
   557     	AppendNotifyL( Object( *parent ).Id(), aEvent );
       
   558     	}
       
   559     iChanged = ETrue; // Might not be true, but how could we know?
       
   560     // Note1: We must presume that this object will actually be changed
       
   561     // because we haven't any information what is being done to it!
       
   562     // If the object had a back-pointer to the engine, this could
       
   563     // be solved, but that would be a BAD THING to do.
       
   564     // Note2: other possible solution is to drop this method and invent
       
   565     // something else to allow item data update.
       
   566     return object;
       
   567     }
       
   568 
       
   569 
       
   570 
       
   571 // ---------------------------------------------------------
       
   572 // CMenuEng::AppendNotifyL
       
   573 // ---------------------------------------------------------
       
   574 //
       
   575 EXPORT_C void CMenuEng::AppendNotifyL( TInt aFolder, TInt aEvents )
       
   576     {
       
   577     for ( TInt i = 0; i < iNotifyQueue.Count(); i++ )
       
   578         {
       
   579         if ( iNotifyQueue[i].iFolder == aFolder )
       
   580             {
       
   581             iNotifyQueue[i].iEvents |= aEvents;
       
   582             return;
       
   583             }
       
   584         }
       
   585     iNotifyQueue.AppendL( TMenuEngNotify( aFolder, aEvents ) );
       
   586     }
       
   587 
       
   588 // ---------------------------------------------------------
       
   589 // CMenuEng::NodeL
       
   590 // ---------------------------------------------------------
       
   591 //
       
   592 EXPORT_C TBool CMenuEng::Exist( TInt aId ) const
       
   593     {
       
   594     TBool exists(EFalse);
       
   595     const RNodeArray& nodes = iTree->Nodes();
       
   596     for ( TInt i = 0; i < nodes.Count(); i++ )
       
   597         {
       
   598         CMenuEngObject& object = Object( *nodes[i] );
       
   599         if ( aId == object.Id()
       
   600                 && !( ( object.Flags() & TMenuItem::EHidden )
       
   601                         || ( object.Flags() & TMenuItem::EMissing ) ) )
       
   602             {
       
   603             exists = ETrue;
       
   604             }
       
   605         }
       
   606     return exists;
       
   607     }
       
   608 // ---------------------------------------------------------
       
   609 // CMenuEng::RunL
       
   610 // ---------------------------------------------------------
       
   611 //
       
   612 void CMenuEng::RunL()
       
   613     {
       
   614     switch( iState )
       
   615         {
       
   616         case ENull:
       
   617             {
       
   618             // Self-completion in ConstructL(). Load RAM tree.
       
   619             __ASSERT_DEBUG( !iStatus.Int(), User::Invariant() );
       
   620             iState = ELoadRamFile;
       
   621             LoadRamFileL();
       
   622             break;
       
   623             }
       
   624 
       
   625         case ELoadRamFile:
       
   626             {
       
   627             if ( iStatus.Int() )
       
   628                 {
       
   629                 // Error loading RAM tree -> Try ROM tree.
       
   630                 iObserver.EngineTreeReloaded();
       
   631                 iState = ELoadRomFile;
       
   632                 LoadRomFileL();
       
   633                 }
       
   634             else
       
   635                 {
       
   636                 // Tree loaded OK. Start processing operations.
       
   637                 iState = EExecuteOp;
       
   638                 ExecuteOperationL();
       
   639                 }
       
   640             break;
       
   641             }
       
   642 
       
   643         case ELoadRomFile:
       
   644             {
       
   645             // Error loading ROM tree is fatal. Nothing we can do.
       
   646             User::LeaveIfError( iStatus.Int() );
       
   647             iState = ESaveFile;
       
   648             AppendPredefinedAttributeL();
       
   649             SaveTempFileL();
       
   650             break;
       
   651             }
       
   652 
       
   653         case ESaveFile:
       
   654             {
       
   655             // Error saving tree is fatal. Nothing we can do.
       
   656             User::LeaveIfError( iStatus.Int() );
       
   657             // Tree saved to temp file OK. Replace content file with temp file.
       
   658             ReplaceRamFileL();
       
   659             // Saving completed succesfully.
       
   660             iChanged = EFalse;
       
   661             // If there is a current operation, this is the final result.
       
   662             CompleteCurrentOperation( iStatus.Int() );
       
   663             // Start next operation.
       
   664             iState = EExecuteOp;
       
   665             ExecuteOperationL();
       
   666             break;
       
   667             }
       
   668 
       
   669         case EExecuteOp:
       
   670             {
       
   671             // Start next operation.
       
   672             __ASSERT_DEBUG( !iStatus.Int(), User::Invariant() );
       
   673             ExecuteOperationL();
       
   674             break;
       
   675             }
       
   676 
       
   677         case EReady:
       
   678         case EDead:
       
   679         default:
       
   680             {
       
   681             User::Invariant();
       
   682             }
       
   683         }
       
   684     }
       
   685 
       
   686 // ---------------------------------------------------------
       
   687 // CMenuEng::DoCancel
       
   688 // ---------------------------------------------------------
       
   689 //
       
   690 void CMenuEng::DoCancel()
       
   691     {
       
   692     // We don't have real requests, only self-completion; which is already
       
   693     // completed.
       
   694     }
       
   695 
       
   696 // ---------------------------------------------------------
       
   697 // CMenuEng::RunError
       
   698 // ---------------------------------------------------------
       
   699 //
       
   700 TInt CMenuEng::RunError( TInt aError )
       
   701     {
       
   702     switch( iState )
       
   703         {
       
   704         case ENull:
       
   705             {
       
   706             User::Invariant(); // Self-completion cannot fail.
       
   707             break;
       
   708             }
       
   709 
       
   710         case ELoadRamFile:
       
   711             {
       
   712             // Error loading RAM tree -> keep going (try ROM tree).
       
   713             SelfComplete( aError );
       
   714             break;
       
   715             }
       
   716 
       
   717         case ELoadRomFile:
       
   718             {
       
   719             // Error loading ROM tree is fatal. Nothing we can do.
       
   720             // stop nested active scheduler loop if error in parsing
       
   721             if ( iActiveWait->IsStarted() )
       
   722                 {
       
   723                 iActiveWait->AsyncStop();
       
   724                 }
       
   725 
       
   726             iState = EDead;
       
   727             iObserver.EngineError( aError );
       
   728             // Can't delete the tree now, XCFW Engine keeps a pointer to it
       
   729             // and still uses it even after reporting the error. :(
       
   730 
       
   731             break;
       
   732             }
       
   733 
       
   734         case ESaveFile:
       
   735             {
       
   736             // File is too big and cannot be saved, delete it
       
   737             // and try reading from rom
       
   738             if (iStatus.Int() == KErrNoMemory)
       
   739             	{
       
   740             	iState = ELoadRamFile;
       
   741             	SelfComplete( aError );
       
   742             	}
       
   743             else {
       
   744 				// Error saving tree is fatal. Nothing we can do.
       
   745 				// If there is a current operation, this is the final result.
       
   746 				CompleteCurrentOperation( aError );
       
   747 				iState = EDead;
       
   748 				iObserver.EngineError( aError );
       
   749             }
       
   750             // Can't delete the tree now, XCFW Engine keeps a pointer to it
       
   751             // and still uses it even after reporting the error. :(
       
   752             break;
       
   753             }
       
   754 
       
   755         case EExecuteOp:
       
   756             {
       
   757             // Current operation failed.
       
   758             CompleteCurrentOperation( aError );
       
   759             // Continue with next operation.
       
   760             SelfComplete( KErrNone );
       
   761             break;
       
   762             }
       
   763 
       
   764         case EReady:
       
   765         case EDead:
       
   766         default:
       
   767             {
       
   768             User::Invariant();
       
   769             }
       
   770         }
       
   771     return KErrNone;
       
   772     }
       
   773 
       
   774 // ---------------------------------------------------------
       
   775 // CMenuEng::HandleEngineEventL
       
   776 // ---------------------------------------------------------
       
   777 //
       
   778 void CMenuEng::HandleEngineEventL( TXCFWEngineEvent aEvent )
       
   779     {
       
   780     switch ( aEvent )
       
   781         {
       
   782         case EEvtParsingComplete:
       
   783             {
       
   784             __ASSERT_DEBUG( iTree, User::Invariant() );
       
   785 
       
   786             // parsing operation complete
       
   787             // we can stop nested active scheduler loop
       
   788             if ( iActiveWait->IsStarted() )
       
   789                 {
       
   790                 iActiveWait->AsyncStop();
       
   791                 }
       
   792 
       
   793             TBool legacyFormat = iObjectFactory->IsLegacyFormat();
       
   794             // Reset object factory in all cases.
       
   795             iObjectFactory->Reset();
       
   796             // Tree is up (maybe unsaved yet).
       
   797             // Check the structure and get the root folder node.
       
   798             MXCFWNode& rootNode = CheckTreeL( *iTree );
       
   799             // Init ID manager, check and fix ID-s.
       
   800             InitIdManagerL( rootNode );
       
   801             // Now we have ID for all (including the root).
       
   802             iRoot = Object( rootNode ).Id();
       
   803             // This is the earliest point to do an ID sanity check.
       
   804             __ASSERT_DEBUG( DebugSanityCheck( *iTree ), User::Invariant() );
       
   805             // Send a "wildcard" notification so everybody reloads.
       
   806             iObserver.EngineEvents( 0, RMenuNotifier::EItemsAddedRemoved );
       
   807             iLegacyFormat = legacyFormat;
       
   808             SelfComplete( KErrNone ); // Go to RunL().
       
   809             break;
       
   810             }
       
   811 
       
   812         case EEvtSavingComplete:
       
   813             {
       
   814             //iLegacyFormat = EFalse;
       
   815             SelfComplete( KErrNone ); // Go to RunL().
       
   816             break;
       
   817             }
       
   818 
       
   819         case EEvtParsingCanceled:
       
   820         case EEvtSavingCanceled:
       
   821             {
       
   822             // Reset object factory in all cases.
       
   823             iObjectFactory->Reset();
       
   824             SelfComplete( KErrCancel ); // Go to RunL().
       
   825             break;
       
   826             }
       
   827 
       
   828         case EEvtParsingStarted:
       
   829         case EEvtSavingStarted:
       
   830         case EEvtNull:
       
   831         default:
       
   832             {
       
   833             break;
       
   834             }
       
   835         }
       
   836     }
       
   837 
       
   838 // ---------------------------------------------------------
       
   839 // CMenuEng::HandleEngineErrorL
       
   840 // ---------------------------------------------------------
       
   841 //
       
   842 void CMenuEng::HandleEngineErrorL( TInt aErrorCode )
       
   843     {
       
   844     // Reset object factory in all cases.
       
   845     iObjectFactory->Reset();
       
   846 
       
   847     SelfComplete( aErrorCode ); // Go to RunL().
       
   848     }
       
   849 
       
   850 // ---------------------------------------------------------
       
   851 // CMenuEng::CheckTreeL
       
   852 // ---------------------------------------------------------
       
   853 //
       
   854 MXCFWNode& CMenuEng::CheckTreeL( MXCFWTree& aTree ) const
       
   855     {
       
   856     MXCFWNode* rootFolder = NULL;
       
   857     MXCFWNode* treeRoot = aTree.Root();
       
   858     if ( treeRoot )
       
   859         {
       
   860         // The tree has nodes.
       
   861         if ( KMenuTypeData() == Object( *treeRoot ).Type() )
       
   862             {
       
   863             // Root node is "menu:data"
       
   864             RNodeArray nodes;
       
   865             CleanupClosePushL( nodes );
       
   866             aTree.GetNodesOfTypeL( KMenuTypeFolder(), nodes,
       
   867                                     treeRoot, EFalse );
       
   868             if ( 1 == nodes.Count() )
       
   869                 {
       
   870                 // Exactly 1 "menu:folder" in the root.
       
   871                 // This is the root folder.
       
   872                 rootFolder = nodes[0];
       
   873                 }
       
   874             CleanupStack::PopAndDestroy( &nodes );
       
   875             }
       
   876         }
       
   877     if ( !rootFolder )
       
   878         {
       
   879         User::Leave( KErrCorrupt );
       
   880         }
       
   881     return *rootFolder;
       
   882     }
       
   883 
       
   884 // ---------------------------------------------------------
       
   885 // CMenuEng::DebugSanityCheck
       
   886 // ---------------------------------------------------------
       
   887 //
       
   888 TBool CMenuEng::DebugSanityCheck( MXCFWTree& aTree ) const
       
   889     {
       
   890     const RNodeArray& nodes = aTree.Nodes();
       
   891     for ( TInt i = 0; i < nodes.Count(); i++ )
       
   892         {
       
   893         if ( !DebugSanityCheck( *nodes[i] ) )
       
   894             {
       
   895             return EFalse;
       
   896             }
       
   897         }
       
   898     return ETrue;
       
   899     }
       
   900 
       
   901 // ---------------------------------------------------------
       
   902 // CMenuEng::ActiveWaitForLoadFileL
       
   903 // ---------------------------------------------------------
       
   904 //
       
   905 void CMenuEng::ActiveWaitForFileLoadL()
       
   906     {
       
   907     iActiveWait = new( ELeave ) CActiveSchedulerWait();
       
   908     if ( !iActiveWait->IsStarted() )
       
   909         {
       
   910         iActiveWait->Start();
       
   911         }
       
   912     //now we check if file was properly loaded
       
   913     TInt root(0);
       
   914     RootFolderL( root );
       
   915     if( !root && ( iState != EDead ) )
       
   916     	{
       
   917     	//there was problem with Ram file(probably file was empty), lets load Rom file
       
   918     	iState = ELoadRamFile;
       
   919         if ( !iActiveWait->IsStarted() )
       
   920             {
       
   921             iActiveWait->Start();
       
   922             }
       
   923     	}
       
   924     }
       
   925 
       
   926 // ---------------------------------------------------------
       
   927 // CMenuEng::DebugSanityCheck
       
   928 // ---------------------------------------------------------
       
   929 //
       
   930 TBool CMenuEng::DebugSanityCheck( MXCFWNode& aNode ) const
       
   931     {
       
   932     __ASSERT_DEBUG( iRoot, User::Invariant() );
       
   933     // Sanity check, for node location and ID.
       
   934     // - Nodes under the root folder (==items) should have non-0 ID.
       
   935     // - Nodes not under the root folder (==other stuff like id_seed) should
       
   936     //   always have 0 id.
       
   937     // This is crucial for the ID space integrity. XCFW node lookup uses
       
   938     // a flat list of nodes; the only way we can differentiate items from
       
   939     // non-items is the ID.
       
   940     MXCFWNode* node;
       
   941     for ( node = &aNode; node; node = node->Parent() )
       
   942         {
       
   943         if ( Object( *node ).Id() == iRoot )
       
   944             {
       
   945             // The node is, or descendant of, the root folder. Must have an ID.
       
   946             return 0 != Object( aNode ).Id();
       
   947             }
       
   948         }
       
   949     // Node is not under the root folder. Must not have an ID.
       
   950     return 0 == Object( aNode ).Id();
       
   951     }
       
   952 
       
   953 // ---------------------------------------------------------
       
   954 // CMenuEng::NodeL
       
   955 // ---------------------------------------------------------
       
   956 //
       
   957 MXCFWNode& CMenuEng::NodeL( TInt aId ) const
       
   958     {
       
   959     __ASSERT_DEBUG( iTree, User::Invariant() );
       
   960     if ( !aId )
       
   961         {
       
   962         // We can actually have 0 id node (outside the item tree), but
       
   963         // those are not items.
       
   964         User::Leave( KErrNotFound );
       
   965         }
       
   966     MXCFWNode* node = NULL;
       
   967     const RNodeArray& nodes = iTree->Nodes();
       
   968     for ( TInt i = 0; i < nodes.Count(); i++ )
       
   969         {
       
   970         node = nodes[i];
       
   971         if ( aId == Object( *node ).Id() )
       
   972             {
       
   973             __ASSERT_DEBUG( DebugSanityCheck( *node ), User::Invariant() );
       
   974             return *node;
       
   975             }
       
   976         }
       
   977     User::Leave( KErrNotFound );
       
   978     /* NOTREACHED */
       
   979     return *node;
       
   980     }
       
   981 
       
   982 // ---------------------------------------------------------
       
   983 // CMenuEng::FolderNodeL
       
   984 // ---------------------------------------------------------
       
   985 //
       
   986 MXCFWNode& CMenuEng::FolderNodeL( TInt aId ) const
       
   987     {
       
   988     __ASSERT_DEBUG( iTree, User::Invariant() );
       
   989     MXCFWNode& node = NodeL( aId );
       
   990     if ( KMenuTypeFolder() == Object( node ).Type() )
       
   991         {
       
   992         return node;
       
   993         }
       
   994     User::Leave( KErrNotFound );
       
   995     /* NOTREACHED */
       
   996     return node;
       
   997     }
       
   998 
       
   999 // ---------------------------------------------------------
       
  1000 // CMenuEng::Child
       
  1001 // ---------------------------------------------------------
       
  1002 //
       
  1003 
       
  1004 MXCFWNode* CMenuEng::Child( MXCFWNode& aParent, TInt aId )
       
  1005     {
       
  1006     MXCFWNode* node;
       
  1007     for ( node = aParent.FirstChild(); node; node = node->NextSibling() )
       
  1008         {
       
  1009         if ( Object( *node ).Id() == aId )
       
  1010             {
       
  1011             break;
       
  1012             }
       
  1013         }
       
  1014     return node;
       
  1015     }
       
  1016 
       
  1017 // ---------------------------------------------------------
       
  1018 // CMenuEng::CancelAllOperations
       
  1019 // ---------------------------------------------------------
       
  1020 //
       
  1021 void CMenuEng::CancelAllOperations()
       
  1022     {
       
  1023     // For safety, we remove pointers before completion.
       
  1024     // (OperationCompleted might want to remove operation too, avoid
       
  1025     // conflict.)
       
  1026     MMenuEngOperation* operation;
       
  1027     if ( iCurrentOperation )
       
  1028         {
       
  1029         operation = iCurrentOperation;
       
  1030         iCurrentOperation = NULL;
       
  1031         operation->CompletedMenuEngOperation( KErrCancel );
       
  1032         }
       
  1033     while ( iOperations.Count() )
       
  1034         {
       
  1035         operation = iOperations[0];
       
  1036         iOperations.Remove( 0 );
       
  1037         operation->CompletedMenuEngOperation( KErrCancel );
       
  1038         }
       
  1039     }
       
  1040 
       
  1041 // ---------------------------------------------------------
       
  1042 // CMenuEng::ValidateNameL
       
  1043 // ---------------------------------------------------------
       
  1044 //
       
  1045 void CMenuEng::ValidateNameL( const TDesC& aName )
       
  1046     {
       
  1047     // We only accept alphanumeric characters and underscore as content
       
  1048     // file name. This is stricter than the (current) file system
       
  1049     // restriction, for future-proofing reasons.
       
  1050     if ( !aName.Length() )
       
  1051         {
       
  1052         User::Leave( KErrArgument );
       
  1053         }
       
  1054     for ( TInt i = 0; i < aName.Length(); i++ )
       
  1055         {
       
  1056         TChar c =  aName[i];
       
  1057         if ( !c.IsAlphaDigit() && '_' != c )
       
  1058             {
       
  1059             User::Leave( KErrArgument );
       
  1060             }
       
  1061         }
       
  1062     }
       
  1063 
       
  1064 // ---------------------------------------------------------
       
  1065 // CMenuEng::GetFileNameL
       
  1066 // ---------------------------------------------------------
       
  1067 //
       
  1068 void CMenuEng::GetFileNameL( TFileName& aFname, TFile aSelector )
       
  1069     {
       
  1070     User::LeaveIfError( iFs.PrivatePath( aFname ) );
       
  1071     if ( ERomFile == aSelector )
       
  1072         {
       
  1073         InsertL(
       
  1074             aFname,
       
  1075             0,
       
  1076             PathInfo::RomRootPath().Left( KDriveAndColon ) );
       
  1077         }
       
  1078     else
       
  1079         {
       
  1080         InsertL(
       
  1081             aFname,
       
  1082             0,
       
  1083             PathInfo::PhoneMemoryRootPath().Left( KDriveAndColon ) );
       
  1084         }
       
  1085     AppendL( aFname, KMenuContentDirName );
       
  1086     AppendL( aFname, iName );
       
  1087     AppendL( aFname, ETempFile == aSelector ?
       
  1088         KMenuTempExtension : KMenuContentExtension );
       
  1089     }
       
  1090 
       
  1091 // ---------------------------------------------------------
       
  1092 // CMenuEng::TraverseNodeL
       
  1093 // ---------------------------------------------------------
       
  1094 //
       
  1095 TBool CMenuEng::TraverseNodeL
       
  1096 ( MXCFWNode& aNode, MMenuEngVisitor& aVisitor ) const
       
  1097     {
       
  1098     CMenuEngObject& object = Object( aNode );
       
  1099     if ( KMenuTypeFolder() == object.Type() )
       
  1100         {
       
  1101         if ( aVisitor.VisitEnterL( object ) )
       
  1102             {
       
  1103             // Recursion is used - menu data tree is not very deep.
       
  1104             MXCFWNode* node = aNode.FirstChild();
       
  1105             while( node && TraverseNodeL( *node, aVisitor ) )
       
  1106                 {
       
  1107                 node = node->NextSibling();
       
  1108                 }
       
  1109             }
       
  1110         // countChildren( object );
       
  1111         return aVisitor.VisitLeaveL( object );
       
  1112         }
       
  1113     else
       
  1114         {
       
  1115         return aVisitor.VisitL( object );
       
  1116         }
       
  1117     }
       
  1118 
       
  1119 // ---------------------------------------------------------
       
  1120 // CMenuEng::InitIdManagerL
       
  1121 // ---------------------------------------------------------
       
  1122 //
       
  1123 void CMenuEng::InitIdManagerL( MXCFWNode& aRootNode )
       
  1124     {
       
  1125     __ASSERT_DEBUG( !iIdManager, User::Invariant() );
       
  1126     __ASSERT_DEBUG( iTree, User::Invariant() );
       
  1127     iIdManager = new (ELeave) CMenuEngIdManager();
       
  1128     TInt idSeed;
       
  1129     GetIdSeedL( idSeed );
       
  1130     iIdManager->SetSeed( idSeed );
       
  1131     // Read ID-s to ID manager.
       
  1132     TMenuEngIdManagerInit idManagerInit( *iIdManager );
       
  1133     TraverseNodeL( aRootNode, idManagerInit );
       
  1134     // Make sure all nodes have ID.
       
  1135     TMenuEngIdSetter idSetter( *iIdManager );
       
  1136     TraverseNodeL( aRootNode, idSetter );
       
  1137     }
       
  1138 
       
  1139 // ---------------------------------------------------------
       
  1140 // CMenuEng::GetIdSeedL
       
  1141 // ---------------------------------------------------------
       
  1142 //
       
  1143 void CMenuEng::GetIdSeedL( TInt& aIdSeed )
       
  1144     {
       
  1145     TInt seed = 0;
       
  1146     __ASSERT_DEBUG( iTree, User::Invariant() );
       
  1147     MXCFWNode* root = iTree->Root();
       
  1148     if ( root )
       
  1149         {
       
  1150         RNodeArray nodes;
       
  1151         CleanupClosePushL( nodes );
       
  1152         iTree->GetNodesOfTypeL
       
  1153             ( KMenuTypeIdSeed(), nodes, root, EFalse );
       
  1154         if ( nodes.Count() )
       
  1155             {
       
  1156             const CMenuEngObject& object = Object( *nodes[0] );
       
  1157             TPtrC val;
       
  1158             TBool dummy;
       
  1159             if ( object.FindAttribute( KMenuAttrIdSeed(), val, dummy ) )
       
  1160                 {
       
  1161                 seed = MenuEngId::AsInt( val );
       
  1162                 }
       
  1163             }
       
  1164         CleanupStack::PopAndDestroy( &nodes );
       
  1165         }
       
  1166     aIdSeed = seed;
       
  1167     }
       
  1168 
       
  1169 // ---------------------------------------------------------
       
  1170 // CMenuEng::SetIdSeedL
       
  1171 // ---------------------------------------------------------
       
  1172 //
       
  1173 void CMenuEng::SetIdSeedL( TInt aSeed )
       
  1174     {
       
  1175     __ASSERT_DEBUG( iTree, User::Invariant() );
       
  1176     MXCFWNode* root = iTree->Root();
       
  1177     if ( root )
       
  1178         {
       
  1179         CMenuEngObject* object = NULL;
       
  1180         RNodeArray nodes;
       
  1181         CleanupClosePushL( nodes );
       
  1182         iTree->GetNodesOfTypeL
       
  1183             ( KMenuTypeIdSeed(), nodes, root, EFalse );
       
  1184         if ( nodes.Count() )
       
  1185             {
       
  1186             object = &Object( *nodes[0] );
       
  1187             }
       
  1188         else
       
  1189             {
       
  1190             // Outside of the item tree -> no ID set.
       
  1191             object = CMenuEngObject::NewL( *this, KMenuTypeIdSeed() );
       
  1192             CleanupStack::PushL( object );
       
  1193             iTree->AddNodeL( object, root );
       
  1194             CleanupStack::Pop( object );
       
  1195             }
       
  1196         __ASSERT_DEBUG( object, User::Invariant() );
       
  1197         TBuf<KMenuMaxAttrValueLen> buf;
       
  1198         MenuEngId::AsString( aSeed, buf );
       
  1199         object->SetAttributeL( KMenuAttrIdSeed(), buf, EFalse );
       
  1200         CleanupStack::PopAndDestroy( &nodes );
       
  1201         }
       
  1202     }
       
  1203 
       
  1204 // ---------------------------------------------------------
       
  1205 // 
       
  1206 // ---------------------------------------------------------
       
  1207 //
       
  1208 void CMenuEng::AppendPredefinedAttributeL( )
       
  1209     {
       
  1210     __ASSERT_DEBUG( iTree, User::Invariant() );
       
  1211     MXCFWNode* root = iTree->Root();
       
  1212     RNodeArray nodes;
       
  1213     CleanupClosePushL( nodes );
       
  1214     iTree->GetNodesOfTypeL(KMenuTypeApp(),nodes, root, ETrue );
       
  1215     for (TInt i = 0; i<nodes.Count(); i++)
       
  1216     	{
       
  1217         CMenuEngObject* object = &Object( *nodes[i] );
       
  1218         object->SetAttributeL( KMenuAttrPredefined(), KNullDesC(), EFalse );
       
  1219     	}
       
  1220     CleanupStack::PopAndDestroy( &nodes );
       
  1221     }
       
  1222 
       
  1223 // ---------------------------------------------------------
       
  1224 // CMenuEng::SelfComplete
       
  1225 // ---------------------------------------------------------
       
  1226 //
       
  1227 void CMenuEng::SelfComplete( TInt aError )
       
  1228     {
       
  1229     TRequestStatus* ownStatus = &iStatus;
       
  1230     *ownStatus = KRequestPending;
       
  1231     SetActive();
       
  1232     User::RequestComplete( ownStatus, aError );
       
  1233     }
       
  1234 
       
  1235 // ---------------------------------------------------------
       
  1236 // CMenuEng::LoadRamFileL
       
  1237 // ---------------------------------------------------------
       
  1238 //
       
  1239 void CMenuEng::LoadRamFileL()
       
  1240     {
       
  1241     __ASSERT_DEBUG( ELoadRamFile == iState, User::Invariant() );
       
  1242     __ASSERT_DEBUG( !iTree, User::Invariant() );
       
  1243     iTree = CXCFWTree::NewL();
       
  1244     // Legacy xml format supported only if the xml is from rom:
       
  1245     iObjectFactory->SupportLegacyFormat( EFalse );
       
  1246     iEngine->LoadL( *iTree, iRamFileName );
       
  1247     }
       
  1248 
       
  1249 // ---------------------------------------------------------
       
  1250 // CMenuEng::LoadRomFileL
       
  1251 // ---------------------------------------------------------
       
  1252 //
       
  1253 void CMenuEng::LoadRomFileL()
       
  1254     {
       
  1255     __ASSERT_DEBUG( ELoadRomFile == iState, User::Invariant() );
       
  1256     // ROM file name is not kept as member - it is used only once.
       
  1257     TFileName fname;
       
  1258     GetFileNameL( fname, ERomFile );
       
  1259 	delete iIdManager; iIdManager = NULL;
       
  1260     delete iTree; iTree = NULL;
       
  1261     iTree = CXCFWTree::NewL();
       
  1262     // Legacy xml format supported only if the xml is from rom:
       
  1263     iObjectFactory->SupportLegacyFormat( ETrue );
       
  1264     iEngine->LoadL( *iTree, fname );
       
  1265     }
       
  1266 
       
  1267 // ---------------------------------------------------------
       
  1268 // CMenuEng::SaveTempFileL
       
  1269 // ---------------------------------------------------------
       
  1270 //
       
  1271 void CMenuEng::SaveTempFileL()
       
  1272     {
       
  1273     __ASSERT_DEBUG( ESaveFile == iState, User::Invariant() );
       
  1274     __ASSERT_DEBUG( iTree, User::Invariant() );
       
  1275     __ASSERT_DEBUG( iIdManager, User::Invariant() );
       
  1276     // Write back ID seed.
       
  1277     SetIdSeedL( iIdManager->Seed() );
       
  1278     // Save to temp file then replace content file with temp file.
       
  1279     // This avoids having incomplete content file, if something goes wrong.
       
  1280     __ASSERT_DEBUG( DebugSanityCheck( *iTree ), User::Invariant() );
       
  1281     TRAPD( err, iEngine->SaveL( *iTree, iTempFileName ) );
       
  1282     if( err==KErrDiskFull )
       
  1283         {
       
  1284         iDiskWasFullAndRamFileWasNotCreated = ETrue;
       
  1285         SelfComplete( KErrNone );
       
  1286         }
       
  1287     else
       
  1288         {
       
  1289         iDiskWasFullAndRamFileWasNotCreated = EFalse;
       
  1290         User::LeaveIfError( err );
       
  1291         }
       
  1292 
       
  1293     }
       
  1294 
       
  1295 // ---------------------------------------------------------
       
  1296 // CMenuEng::ReplaceRamFileL
       
  1297 // ---------------------------------------------------------
       
  1298 //
       
  1299 void CMenuEng::ReplaceRamFileL()
       
  1300     {
       
  1301     __ASSERT_DEBUG( ESaveFile == iState, User::Invariant() );
       
  1302     // RFs::Replace() copies the file data ->
       
  1303     // Delete() + Rename() is used instead.
       
  1304     iFs.Delete( iRamFileName );
       
  1305     TInt err = iFs.Rename( iTempFileName, iRamFileName );
       
  1306     if( err==KErrDiskFull )
       
  1307         {
       
  1308         iDiskWasFullAndRamFileWasNotCreated = ETrue;
       
  1309         }
       
  1310     else
       
  1311         {
       
  1312         iDiskWasFullAndRamFileWasNotCreated = EFalse;
       
  1313         User::LeaveIfError( err );
       
  1314         }
       
  1315     }
       
  1316 
       
  1317 // ---------------------------------------------------------
       
  1318 // CMenuEng::CompleteCurrentOperation
       
  1319 // ---------------------------------------------------------
       
  1320 //
       
  1321 void CMenuEng::CompleteCurrentOperation( TInt aError )
       
  1322     {
       
  1323     // Operation completion reported two ways:
       
  1324     // - "No change" operations report completion immediately;
       
  1325     // - "Change" operations trigger saving and wait the result.
       
  1326     __ASSERT_DEBUG( EExecuteOp == iState || ESaveFile == iState, \
       
  1327         User::Invariant() );
       
  1328     if ( iCurrentOperation )
       
  1329         {
       
  1330         iCurrentOperation->CompletedMenuEngOperation( aError );
       
  1331         iCurrentOperation = NULL;
       
  1332         }
       
  1333     // Flush notifications in the success case.
       
  1334     // (Otherwise, the changes did not happen.)
       
  1335     if ( !aError )
       
  1336         {
       
  1337         for ( TInt i = 0; i < iNotifyQueue.Count(); i++ )
       
  1338             {
       
  1339             const TMenuEngNotify& notify = iNotifyQueue[i];
       
  1340             iObserver.EngineEvents( notify.iFolder, notify.iEvents );
       
  1341             }
       
  1342         }
       
  1343     iNotifyQueue.Reset();
       
  1344     }
       
  1345 
       
  1346 // ---------------------------------------------------------
       
  1347 // CMenuEng::ExecuteOperationL
       
  1348 // ---------------------------------------------------------
       
  1349 //
       
  1350 void CMenuEng::ExecuteOperationL()
       
  1351     {
       
  1352     __ASSERT_DEBUG( EExecuteOp == iState, User::Invariant() );
       
  1353     __ASSERT_DEBUG( !iCurrentOperation, User::Invariant() );
       
  1354     if ( iOperations.Count() )
       
  1355         {
       
  1356         iCurrentOperation = iOperations[0];
       
  1357         iOperations.Remove( 0 );
       
  1358         iCurrentOperation->RunMenuEngOperationL();
       
  1359         SaveChangesL();
       
  1360         }
       
  1361     else
       
  1362         {
       
  1363         // No pending operations, we stop here.
       
  1364         // Next QueueOperationL will kick us back to operation.
       
  1365         iState = EReady;
       
  1366         }
       
  1367     }
       
  1368 
       
  1369 // ---------------------------------------------------------
       
  1370 // CMenuEng::SaveChangesL
       
  1371 // ---------------------------------------------------------
       
  1372 //
       
  1373 void CMenuEng::SaveChangesL()
       
  1374     {
       
  1375     // This method is part of ExecuteOperationL.
       
  1376     // (Post-operation processing.)
       
  1377     __ASSERT_DEBUG( EExecuteOp == iState, User::Invariant() );
       
  1378     if ( iChanged || iDiskWasFullAndRamFileWasNotCreated )
       
  1379         {
       
  1380         // Tree changed, async save.
       
  1381         iState = ESaveFile;
       
  1382         SaveTempFileL();
       
  1383         }
       
  1384     else
       
  1385         {
       
  1386         // Tree not changed, we are done.
       
  1387         CompleteCurrentOperation( KErrNone );
       
  1388         if ( iOperations.Count() )
       
  1389             {
       
  1390             // Go for the next operation (async).
       
  1391             iState = EExecuteOp; // Same as current value, code clarity.
       
  1392             SelfComplete( KErrNone );
       
  1393             }
       
  1394         else
       
  1395             {
       
  1396             // No pending operations, we stop here.
       
  1397             // Next QueueOperationL will kick us back to operation.
       
  1398             iState = EReady;
       
  1399             }
       
  1400         }
       
  1401     }
       
  1402 
       
  1403 //  End of File