--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mpxmusicplayer/mediakeyhandler/src/mpxnotifierdialog.cpp Thu Dec 17 08:45:05 2009 +0200
@@ -0,0 +1,710 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Implementation of media key handler
+*
+*/
+
+
+
+// INCLUDE FILES
+#include <eikenv.h>
+#include <apgwgnam.h>
+#include <eikimage.h>
+#include <eikappui.h>
+#include <gulfont.h>
+#include <fontids.hrh>
+#include <AknUtils.h>
+#include <AknsBasicBackgroundControlContext.h>
+#include <AknsUtils.h>
+#include <AknsConstants.h>
+#include <AknsDrawUtils.h>
+#include <avkon.rsg>
+#include <eiklabel.h>
+#include <data_caging_path_literals.hrh>
+#include <aknlayoutscalable_apps.cdl.h>
+#include <skinlayout.cdl.h>
+#include <mpxmediakeyhandler.mbg>
+#include <mpxmediakeyhandler.rsg>
+#include <StringLoader.h>
+#include <mpxuser.h>
+#include <activeidle2domainpskeys.h>
+#include <mpxpskeywatcher.h>
+
+#include "mpxlog.h"
+#include "mpxnotifierdialog.h"
+
+using namespace AknLayoutScalable_Apps;
+
+
+// CONSTANTS
+const TInt KMPXComponentsCount = CMPXNotifierDialog::EMPXComponentsCount;
+
+const TInt KMPXOneSecInMicroSecs( 1000000 );
+const TInt KMPXOneHourInSeconds( 3600 );
+const TInt KMPXOneHundredHoursInSecs( 360000 );
+const TInt KMPXDurationDisplayResvLen( 10 );
+
+const TInt KMPXWindowPosition = 10; // window group's priority
+const TInt KMPXInactivityTime = 4000000; // 4 seconds - close window after this
+_LIT( KMPXInfoPopupWgName, "MPXInfoPopup" ); // window groups name
+
+_LIT( KMPXMediaKeyHandlerMbmFile, "mpxmediakeyhandler.mbm" );
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// ---------------------------------------------------------------------------
+//
+CMPXNotifierDialog::CMPXNotifierDialog()
+ {
+ }
+
+// ---------------------------------------------------------------------------
+// Symbian 2nd phase constructor can leave.
+// ---------------------------------------------------------------------------
+//
+void CMPXNotifierDialog::ConstructL()
+ {
+ // create a window group for popup
+ // needed to prevent apps noticing this window
+ RWsSession& wsSession = iCoeEnv->WsSession();
+ iWindowGroup = RWindowGroup( wsSession );
+ User::LeaveIfError( iWindowGroup.Construct( ( TUint32 )&iWindowGroup, EFalse ) );
+ iWindowGroup.AutoForeground( EFalse );
+ iEikonEnv->EikAppUi()->AddToStackL( this );
+
+ CApaWindowGroupName* name = CApaWindowGroupName::NewLC(
+ wsSession, ( TUint32 )&iWindowGroup );
+ name->SetHidden( ETrue );
+ name->SetCaptionL( KMPXInfoPopupWgName ); // Available to OOM watcher so this won't be closed
+ User::LeaveIfError( name->SetWindowGroupName( iWindowGroup ) );
+ CleanupStack::PopAndDestroy( name );
+
+ iWindowGroup.SetOrdinalPosition( 0, ECoeWinPriorityNeverAtFront );
+
+ // create control's window to own window group
+ CreateWindowL( &iWindowGroup );
+
+ // create icon & label controls
+ iSongLabel = new ( ELeave ) CEikLabel();
+ iSongLabel->SetContainerWindowL( *this );
+ iSongLabel->SetTextL( KNullDesC );
+
+ iTimeLabel = new ( ELeave ) CEikLabel();
+ iTimeLabel->SetContainerWindowL( *this );
+ iTimeLabel->SetTextL( KNullDesC );
+
+ CreateIconsL();
+
+ // Timer
+ iTimer = CPeriodic::NewL( CActive::EPriorityStandard );
+
+ // for watching when we go active idle
+ iPSKeyWatcher = CMPXPSKeyWatcher::NewL( KPSUidAiInformation, KActiveIdleState, this );
+
+ MakeVisible( EFalse );
+ ResizeInfoPopup();
+ ActivateL();
+ }
+
+// ---------------------------------------------------------------------------
+// Two-phased constructor.
+// ---------------------------------------------------------------------------
+//
+CMPXNotifierDialog* CMPXNotifierDialog::NewL()
+ {
+ CMPXNotifierDialog* self = new( ELeave ) CMPXNotifierDialog();
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CMPXNotifierDialog::~CMPXNotifierDialog()
+ {
+ iEikonEnv->EikAppUi()->RemoveFromStack( this );
+ delete iPSKeyWatcher;
+ iWindowGroup.Close();
+ if (iTimer)
+ iTimer->Cancel();
+ delete iTimer;
+ delete iSongLabel;
+ delete iTimeLabel;
+ delete iPlayIcon;
+ delete iPauseIcon;
+ delete iFFIcon;
+ delete iFRIcon;
+ }
+
+// ---------------------------------------------------------------------------
+// Shows pop-up dialog.
+// ---------------------------------------------------------------------------
+//
+void CMPXNotifierDialog::ShowInfoPopupL(
+ TMPXPlaybackPopupIcons aIcon,
+ const TDesC& aTitle,
+ TInt aTime,
+ TMPXPlaybackPopupModes aMode )
+ {
+ MPX_DEBUG2( "CMPXNotifierDialog::ShowInfoPopupL aMode = %d", aMode );
+ if ( ( EMPXPopupShowIfVisible == aMode && !IsVisible() ) ||
+ ( EMPXPopupShowIfVisibleRestartTimer == aMode && !IsVisible() ) )
+ {
+ MPX_DEBUG1( "CMPXNotifierDialog::ShowInfoPopupL do nothing" );
+ return;
+ }
+
+ UpdateInfoPopupL( aIcon, aTitle, aTime );
+
+ if ( EMPXPopupTimeout == aMode ||
+ EMPXPopupShowIfVisibleRestartTimer == aMode )
+ {
+ MPX_DEBUG1( "CMPXNotifierDialog::ShowInfoPopupL starting timer" );
+ iTimer->Cancel();
+ iTimer->Start(
+ KMPXInactivityTime,
+ KMPXInactivityTime,
+ TCallBack( TimerCallback, this ) );
+ }
+ else if ( EMPXPopupNoTimeout == aMode )
+ {
+ MPX_DEBUG1( "CMPXNotifierDialog::ShowInfoPopupL canceling timer" );
+ iTimer->Cancel();
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Removes pop-up from screen.
+// ---------------------------------------------------------------------------
+//
+void CMPXNotifierDialog::CancelInfoPopup()
+ {
+ MPX_DEBUG1( "CMPXNotifierDialog::CancelInfoPopup" );
+ iTimer->Cancel();
+ if ( IsVisible() )
+ {
+ iWindowGroup.SetOrdinalPosition( 0, ECoeWinPriorityNeverAtFront );
+ MakeVisible( EFalse );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Gets notified when display orientation hange is started
+// ---------------------------------------------------------------------------
+//
+void CMPXNotifierDialog::NotifyOrientationChangeBegin()
+ {
+ // ::HandeResourceChange() will unhide the dialog as soon as the
+ // orientation change has been completed. KEikDynamicLayoutVariantSwitch comes
+ // too late so the layout is not correct from the beginning
+ if( IsVisible() )
+ {
+ MakeVisible( EFalse );
+ iReopenDialog = ETrue;
+ }
+ }
+
+// Updates pop-up dialog contents.
+// ---------------------------------------------------------------------------
+//
+void CMPXNotifierDialog::UpdateInfoPopupL(
+ TMPXPlaybackPopupIcons aIcon,
+ const TDesC& aTitle,
+ TInt aTime )
+ {
+ ShowIcon( aIcon );
+
+ // Set label text
+ // magic: allocate 3 chars more (make sure "..." fits).
+ HBufC* buf = HBufC::NewLC( aTitle.Length() + 3 );
+ *buf = aTitle;
+ TPtr ptr( buf->Des() );
+ AknTextUtils::ClipToFit(
+ ptr,
+ *iSongLabel->Font(),
+ iSongLabel->Rect().Width() );
+ iSongLabel->SetTextL( *buf );
+ CleanupStack::PopAndDestroy( buf );
+
+ // Set duration label
+ if ( aTime != KErrNotFound )
+ {
+ HBufC* duration = DisplayableDurationL( aTime );
+ CleanupStack::PushL( duration );
+ iTimeLabel->SetTextL( *duration );
+ CleanupStack::PopAndDestroy( duration );
+ }
+ else
+ {
+ iTimeLabel->SetTextL( KNullDesC );
+ }
+
+ if ( !IsVisible() )
+ {
+ // make this window visible
+ iWindowGroup.SetOrdinalPosition( 0, KMPXWindowPosition );
+ MakeVisible( ETrue );
+ }
+ DrawDeferred();
+ }
+
+// ---------------------------------------------------------------------------
+// Create icons.
+// ---------------------------------------------------------------------------
+//
+void CMPXNotifierDialog::CreateIconsL()
+ {
+ delete iPlayIcon;
+ iPlayIcon = NULL;
+ iPlayIcon = new ( ELeave ) CEikImage();
+ iPlayIcon->SetContainerWindowL( *this );
+ ConstructImageL(
+ iPlayIcon,
+ AknsUtils::SkinInstance(),
+ KAknsIIDQgnIndiMupPlay,
+ KAknsIIDQsnIconColors,
+ EAknsCIQsnIconColorsCG26,
+ EMbmMpxmediakeyhandlerQgn_indi_mup_play,
+ EMbmMpxmediakeyhandlerQgn_indi_mup_play_mask );
+
+ delete iPauseIcon;
+ iPauseIcon = NULL;
+ iPauseIcon = new ( ELeave ) CEikImage();
+ iPauseIcon->SetContainerWindowL( *this );
+ ConstructImageL(
+ iPauseIcon,
+ AknsUtils::SkinInstance(),
+ KAknsIIDQgnIndiMupPause,
+ KAknsIIDQsnIconColors,
+ EAknsCIQsnIconColorsCG26,
+ EMbmMpxmediakeyhandlerQgn_indi_mup_pause,
+ EMbmMpxmediakeyhandlerQgn_indi_mup_pause_mask );
+ delete iFFIcon;
+ iFFIcon = NULL;
+ iFFIcon = new ( ELeave ) CEikImage();
+ iFFIcon->SetContainerWindowL( *this );
+ ConstructImageL(
+ iFFIcon,
+ AknsUtils::SkinInstance(),
+ KAknsIIDQgnIndiMupForw,
+ KAknsIIDQsnIconColors,
+ EAknsCIQsnIconColorsCG26,
+ EMbmMpxmediakeyhandlerQgn_indi_mup_forw,
+ EMbmMpxmediakeyhandlerQgn_indi_mup_forw_mask );
+
+ delete iFRIcon;
+ iFRIcon = NULL;
+ iFRIcon = new ( ELeave ) CEikImage();
+ iFRIcon->SetContainerWindowL( *this );
+ ConstructImageL(
+ iFRIcon,
+ AknsUtils::SkinInstance(),
+ KAknsIIDQgnIndiMupRew,
+ KAknsIIDQsnIconColors,
+ EAknsCIQsnIconColorsCG26,
+ EMbmMpxmediakeyhandlerQgn_indi_mup_rew,
+ EMbmMpxmediakeyhandlerQgn_indi_mup_rew_mask );
+ }
+
+// ---------------------------------------------------------------------------
+// Constructs skinnable icon.
+// ---------------------------------------------------------------------------
+//
+void CMPXNotifierDialog::ConstructImageL(
+ CEikImage* aImage,
+ MAknsSkinInstance* aSkin,
+ const TAknsItemID& aId,
+ const TAknsItemID& aColorId,
+ TInt aColorIndex,
+ TInt aBitmapId,
+ TInt aMaskId )
+ {
+ CFbsBitmap* bitmap = NULL;
+ CFbsBitmap* mask = NULL;
+
+ TParse parse;
+ parse.Set( KMPXMediaKeyHandlerMbmFile, &KDC_APP_RESOURCE_DIR, NULL );
+ TFileName iconFile( parse.FullName() );
+ User::LeaveIfError( MPXUser::CompleteWithDllPath( iconFile ) );
+
+ AknsUtils::CreateColorIconL(
+ aSkin,
+ aId,
+ aColorId,
+ aColorIndex,
+ bitmap,
+ mask,
+ iconFile,
+ aBitmapId,
+ aMaskId,
+ KRgbBlack );
+
+ aImage->SetPicture( bitmap, mask ); // Owership transferred to CEikImage
+ }
+
+// ---------------------------------------------------------------------------
+// Resize info popup.
+// ---------------------------------------------------------------------------
+//
+void CMPXNotifierDialog::ResizeInfoPopup()
+ {
+ TRect appRect = iEikonEnv->EikAppUi()->ApplicationRect();
+
+ // get parent rectangle (status pane)
+ TAknWindowLineLayout statusPane = AknLayout::status_pane( appRect, 0 );
+ TAknLayoutRect res;
+ res.LayoutRect( appRect, statusPane );
+ TRect parentRect = res.Rect();
+
+ // set the rectangle
+ TAknWindowComponentLayout l = popup_mup_playback_window();
+ res.LayoutRect( parentRect, l.LayoutLine() );
+ SetRect( res.Rect() );
+ DrawNow();
+ }
+
+// ---------------------------------------------------------------------------
+// Sets pop-up layouts.
+// ---------------------------------------------------------------------------
+//
+void CMPXNotifierDialog::SetLayoutsL( TBool aLong )
+ {
+ TAknWindowComponentLayout l;
+ // play icon
+ l = popup_mup_playback_window_g1();
+ AknLayoutUtils::LayoutImage( iPlayIcon, Rect(), l.LayoutLine() );
+ // pause icon
+ l = popup_mup_playback_window_g1();
+ AknLayoutUtils::LayoutImage( iPauseIcon, Rect(), l.LayoutLine() );
+ // FF icon
+ l = popup_mup_playback_window_g1();
+ AknLayoutUtils::LayoutImage( iFFIcon, Rect(), l.LayoutLine() );
+ // FR icon
+ l = popup_mup_playback_window_g1();
+ AknLayoutUtils::LayoutImage( iFRIcon, Rect(), l.LayoutLine() );
+ // song label
+ TAknTextComponentLayout t = popup_mup_playback_window_t1();
+ AknLayoutUtils::LayoutLabel( iSongLabel, Rect(), t.LayoutLine() );
+ // time label
+ if( aLong )
+ {
+ t = popup_mup_playback_window_t2( 1 );
+ }
+ else
+ {
+ t = popup_mup_playback_window_t2();
+ }
+
+ AknLayoutUtils::LayoutLabel( iTimeLabel, Rect(), t.LayoutLine() );
+
+ // Set label color
+ TRgb color;
+ MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+ TInt error = AknsUtils::GetCachedColor(
+ skin,
+ color,
+ KAknsIIDQsnTextColors,
+ EAknsCIQsnTextColorsCG19 );
+ if ( !error )
+ {
+ AknLayoutUtils::OverrideControlColorL(
+ *iSongLabel,
+ EColorLabelText,
+ color );
+
+ AknLayoutUtils::OverrideControlColorL(
+ *iTimeLabel,
+ EColorLabelText,
+ color );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Show playback icon.
+// ---------------------------------------------------------------------------
+//
+void CMPXNotifierDialog::ShowIcon(
+ TMPXPlaybackPopupIcons aIcon )
+ {
+
+ switch ( aIcon )
+ {
+ case EMPXPopupPlayIcon:
+ {
+ iIconShown = EMPXPopupPlayIcon;
+ iPlayIcon->MakeVisible( ETrue );
+ iPauseIcon->MakeVisible( EFalse );
+ iFFIcon->MakeVisible( EFalse );
+ iFRIcon->MakeVisible( EFalse );
+ break;
+ }
+ case EMPXPopupPauseIcon:
+ {
+ iIconShown = EMPXPopupPauseIcon;
+ iPlayIcon->MakeVisible( EFalse );
+ iPauseIcon->MakeVisible( ETrue );
+ iFFIcon->MakeVisible( EFalse );
+ iFRIcon->MakeVisible( EFalse );
+ break;
+ }
+ case EMPXPopupFFIcon:
+ {
+ iIconShown = EMPXPopupFFIcon;
+ iFFIcon->MakeVisible( ETrue );
+ iPlayIcon->MakeVisible( EFalse );
+ iPauseIcon->MakeVisible( EFalse );
+ iFRIcon->MakeVisible( EFalse );
+ break;
+ }
+ case EMPXPopupFRIcon:
+ {
+ iIconShown = EMPXPopupFFIcon;
+ iPlayIcon->MakeVisible( EFalse );
+ iPauseIcon->MakeVisible( EFalse );
+ iFFIcon->MakeVisible( EFalse );
+ iFRIcon->MakeVisible( ETrue );
+ break;
+ }
+ default:
+ {
+ iIconShown = EMPXPopupNoneIcon;
+ iPlayIcon->MakeVisible( EFalse );
+ iPauseIcon->MakeVisible( EFalse );
+ iFFIcon->MakeVisible( EFalse );
+ iFRIcon->MakeVisible( EFalse );
+ break;
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Callback for timer
+// ---------------------------------------------------------------------------
+//
+TInt CMPXNotifierDialog::TimerCallback( TAny* aPtr )
+ {
+ MPX_DEBUG1( "CMPXNotifierDialog::TimerCallback" );
+ static_cast<CMPXNotifierDialog*>( aPtr )->CancelInfoPopup();
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// Convert to displayable duration.
+// ---------------------------------------------------------------------------
+//
+HBufC* CMPXNotifierDialog::DisplayableDurationL(
+ TInt aDuration )
+ {
+ TInt resId;
+ HBufC* format = NULL;
+ if ( aDuration >= KMPXOneHundredHoursInSecs )
+ {
+ resId = R_MPX_TIME_DURAT_HHHMMSS_WITH_ZERO;
+ format = StringLoader::LoadLC(
+ resId, aDuration / KMPXOneHourInSeconds );
+ }
+ else
+ {
+ resId = R_QTN_TIME_DURAT_MIN_SEC_WITH_ZERO;
+ if ( aDuration >= KMPXOneHourInSeconds )
+ {
+ resId = R_QTN_TIME_DURAT_LONG_WITH_ZERO;
+ }
+ format = StringLoader::LoadLC( resId );
+ }
+
+ SetLayoutsL( aDuration > KMPXOneHourInSeconds? ETrue: EFalse);
+
+ // Convert total playing time to texts.
+ TTime durTime( (TInt64)aDuration * KMPXOneSecInMicroSecs );
+
+ HBufC* buf =
+ HBufC::NewLC( format->Length() + KMPXDurationDisplayResvLen );
+ TPtr bufTPtr( buf->Des() );
+
+ durTime.FormatL( bufTPtr, *format );
+ AknTextUtils::LanguageSpecificNumberConversion( bufTPtr );
+ CleanupStack::Pop( buf );
+ CleanupStack::PopAndDestroy( format );
+
+ return buf;
+ }
+
+// ---------------------------------------------------------------------------
+// From CCoeControl
+// Draws the control.
+// ---------------------------------------------------------------------------
+//
+void CMPXNotifierDialog::Draw( const TRect& /* aRect */ ) const
+ {
+ CWindowGc& gc = SystemGc();
+
+ MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+ MAknsControlContext* cc = AknsDrawUtils::ControlContext( this );
+
+ // background
+ AknsDrawUtils::Background( skin, cc, gc, Rect() );
+
+ // skin stuff - find out size of the corner piece
+ TAknLayoutRect cornerRect;
+ // skinned draw uses submenu popup window skin (skinned border)
+ cornerRect.LayoutRect(
+ Rect(),
+ SkinLayout::Submenu_skin_placing_Line_2() );
+
+ TRect innerRect( Rect() );
+ innerRect.Shrink( cornerRect.Rect().Width(), cornerRect.Rect().Height() );
+
+ if ( !AknsDrawUtils::DrawFrame(
+ skin,
+ gc,
+ Rect(),
+ innerRect,
+ KAknsIIDQsnFrPopupSub,
+ KAknsIIDQsnFrPopupCenterSubmenu ) )
+ {
+ // skinned border failed -> black border
+ gc.SetPenStyle( CGraphicsContext::ESolidPen );
+ gc.SetBrushColor( KRgbBlack );
+ gc.DrawRect( Rect() );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// From CCoeControl
+// Handles a change to the control's resources.
+// ---------------------------------------------------------------------------
+//
+void CMPXNotifierDialog::HandleResourceChange( TInt aType )
+ {
+ CCoeControl::HandleResourceChange( aType );
+
+ if ( aType == KAknsMessageSkinChange )
+ {
+ // Reload icons & layout
+ TRAP_IGNORE(
+ {
+ CreateIconsL();
+ ShowIcon( iIconShown );
+ SetLayoutsL();
+ } );
+ }
+ else if ( aType == KEikDynamicLayoutVariantSwitch )
+ {
+ ResizeInfoPopup();
+ if( iReopenDialog )
+ {
+ MakeVisible( ETrue );
+ iReopenDialog = EFalse;
+ }
+ }
+ else
+ {
+ // pass
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// From CCoeControl
+// Responds to changes to the size and position of the contents of this
+// control.
+// ---------------------------------------------------------------------------
+//
+void CMPXNotifierDialog::SizeChanged()
+ {
+ TRAP_IGNORE( SetLayoutsL() );
+ }
+
+// ---------------------------------------------------------------------------
+// From CCoeControl
+// Gets the number of controls contained in a compound control.
+// ---------------------------------------------------------------------------
+//
+TInt CMPXNotifierDialog::CountComponentControls() const
+ {
+ return KMPXComponentsCount;
+ }
+
+// ---------------------------------------------------------------------------
+// From CCoeControl
+// Gets an indexed component of a compound control.
+// ---------------------------------------------------------------------------
+//
+CCoeControl* CMPXNotifierDialog::ComponentControl( TInt aIndex ) const
+ {
+ CCoeControl* control = NULL;
+
+ switch ( aIndex )
+ {
+ case EMPXTrackLabel:
+ {
+ control = iSongLabel;
+ break;
+ }
+ case EMPXTimeLabel:
+ {
+ control = iTimeLabel;
+ break;
+ }
+ case EMPXPlayIcon:
+ {
+ control = iPlayIcon;
+ break;
+ }
+ case EMPXPauseIcon:
+ {
+ control = iPauseIcon;
+ break;
+ }
+ case EMPXFFIcon:
+ {
+ control = iFFIcon;
+ break;
+ }
+ case EMPXFRIcon:
+ {
+ control = iFRIcon;
+ break;
+ }
+ default:
+ {
+ // Pass
+ break;
+ }
+ }
+
+ return control;
+ }
+
+// ---------------------------------------------------------------------------
+// From MMPXPSKeyObserver
+// Handle PS event
+// ---------------------------------------------------------------------------
+//
+void CMPXNotifierDialog::HandlePSEvent( TUid aUid, TInt aKey )
+ {
+ if ( ( aUid == KPSUidAiInformation ) && ( aKey == KActiveIdleState ) )
+ {
+ //we want to cancel popup when going to active idle
+ CancelInfoPopup();
+ }
+ }
+// End of File