diff -r ebe688cedc25 -r 7fdbb852d323 messagingappbase/smartmessaging/gmsmodel/src/CGmsPictureControl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/messagingappbase/smartmessaging/gmsmodel/src/CGmsPictureControl.cpp Wed Sep 01 12:31:54 2010 +0100 @@ -0,0 +1,507 @@ +/* +* Copyright (c) 2002 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: +* GMS picture viewer control which is compatible with Editor Base. +* It is based very much on the CMmsImageControl. +* %version: bh1cfmsg#16 % +* +*/ + + + +// INCLUDE FILES +#include "CGmsPictureControl.h" + +#include // for ConeUtils::FileExists +#include +#include +#include +#include + +// CONSTANTS + +// Mime type of the image, required by the decoder. +_LIT8( KGmsOtaMimeType, "image/x-ota-bitmap"); + +_LIT(KSmEditorGmsPic,"smeditor gmsPic"); + +// ========================================================== + +/** +* Helper class which allows CGmsPictureControl to receive a callback +* to it's callback method when an asynchronous operation has finished. +* CAsyncCallBack needed tweaking since it is ment for callback only, and +* it completes the task immediately. +*/ +class CGmsAOCallBack: public CAsyncCallBack + { + public: + + CGmsAOCallBack( const TCallBack &aCallBack, TInt aPriority ) + : CAsyncCallBack( aCallBack, aPriority ) + { + } + + void SetItActive() + { + SetActive(); + } + + protected: + + void RunL() + { + iCallBack.CallBack(); + } + }; + + +// MEMBER FUNCTIONS + +EXPORT_C CGmsPictureControl* CGmsPictureControl::NewL( + const CCoeControl* aParent) +{ + CGmsPictureControl* self = new(ELeave) CGmsPictureControl(); + + CleanupStack::PushL(self); + self->ConstructL(aParent); + CleanupStack::Pop(self); + + return self; +} + +EXPORT_C CGmsPictureControl::~CGmsPictureControl() +{ + delete iBitmap; + iBitmap = NULL; + delete iScaledBitmap; + iScaledBitmap = NULL; + + delete iConverter; + iConverter = NULL; + delete iScaler; + delete iConversionAO; + delete iScalingAO; + iFs.Close(); +} + +EXPORT_C void CGmsPictureControl::LoadImageL( + const TFileName& aImageFile, + TUint aMaxHeight /* = 0 */) +{ + __ASSERT_DEBUG((aImageFile.Length() > 0), Panic( ENoImageFile ) ); + + if (!ConeUtils::FileExists(aImageFile)) + { + User::Leave(KErrNotFound); + } + if (aMaxHeight) + { + iMaxHeight = aMaxHeight; + } + + Reset(); + + iConverter = CImageDecoder::FileNewL( iFs, aImageFile, KGmsOtaMimeType ); + __ASSERT_ALWAYS( iConverter->FrameCount() == 1, Panic(EBadImageContent) ); + TFrameInfo frameInfo = iConverter->FrameInfo( 0 ); + iBitmap = new( ELeave ) CFbsBitmap; + User::LeaveIfError( iBitmap->Create( frameInfo.iOverallSizeInPixels, + EGray2 ) ); + + iConverter->Convert( &(iConversionAO->iStatus), *iBitmap ); + iConversionAO->SetItActive(); +} + +EXPORT_C TSize CGmsPictureControl::OriginalImageResolution() const +{ + TSize size(0,0); + if ( iConverter ) + { + size = iConverter->FrameInfo( 0 ).iOverallSizeInPixels; + } + return size; +} + +TRect CGmsPictureControl::CurrentLineRect() +{ + return Rect(); +} + +void CGmsPictureControl::SetAndGetSizeL(TSize& aSize) +{ + // Size proposed in aSize parameter is used, only height is + // proposed by this control. + + if (AknLayoutUtils::ScalableLayoutInterfaceAvailable()) + { + TAknWindowComponentLayout layout = + AknLayoutScalable_Apps::mce_image_pane_g3(); + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( Rect(), layout.LayoutLine() ); + aSize.iHeight = layoutRect.Rect().Height(); + + // Adjust max height if needed + if ( iMaxHeight > 0 && (TUint)aSize.iHeight > iMaxHeight ) + { + aSize.iHeight = iMaxHeight; + } + } + + else + { // use old sizing functionality if scalable IF isn't available: + aSize = CalculateControlSize(aSize); + } + + SetSizeWithoutNotification(aSize); +} + +/** +* This internal function is the old version and is used ONLY if scalable +* layout interface is NOT available. This should be removed when it is always +* available. +*/ +const TInt KGmsImageHeightMax = 58; +const TInt KBaseLineDelta = 17; + +TSize CGmsPictureControl::CalculateControlSize(TSize& aProposedSize) + { + // These lines below, although they look a bit strange, are required to + // conform with old sizing functionality when scalable layout IF is + // not available: + if ( iMaxHeight == 0 ) + { // max height hasn't been set by the client: + iMaxHeight = KGmsImageHeightMax; + } + if ( (TUint)aProposedSize.iHeight > iMaxHeight ) + { // proposed size is greater than max size -> adjust: + aProposedSize.iHeight = iMaxHeight; + } + + TSize trgSize(aProposedSize.iWidth, 0); + + if (!iConverter) + { + return trgSize; + } + + TSize bmpSize = OriginalImageResolution(); + + bmpSize.SetSize(bmpSize.iWidth*2, bmpSize.iHeight*2); + + if (bmpSize.iHeight < aProposedSize.iHeight) + { + trgSize.iHeight = bmpSize.iHeight; + } + else + { + trgSize.iHeight = aProposedSize.iHeight; + } + + // For "wide" images height may be too big - check aspect ratio + TReal widthRatio = (TReal)bmpSize.iWidth / (TReal)trgSize.iWidth; + TReal heightRatio = (TReal)bmpSize.iHeight / (TReal)trgSize.iHeight; + + if (widthRatio > heightRatio) + { + // image must be scaled more in vertical size + trgSize.iHeight = (TInt)(bmpSize.iHeight / widthRatio); + } + + if (trgSize.iHeight%KBaseLineDelta) + { + trgSize.iHeight = trgSize.iHeight-trgSize.iHeight%KBaseLineDelta+KBaseLineDelta; + } + return trgSize; + } + +void CGmsPictureControl::ClipboardL(TMsgClipboardFunc /*aFunc*/) +{ + User::Leave(KErrNotSupported); // Image control does not support clipboard +} + +void CGmsPictureControl::EditL(TMsgEditFunc /*aFunc*/) +{ + User::Leave(KErrNotSupported); // Image control is not editable +} + +TBool CGmsPictureControl::IsFocusChangePossible(TMsgFocusDirection /*aDirection*/) const +{ + return ETrue; +} + +TBool CGmsPictureControl::IsCursorLocation(TMsgCursorLocation /*aLocation*/) const +{ + return ETrue; +} + +TUint32 CGmsPictureControl::EditPermission() const +{ + return EMsgEditNone; +} + +void CGmsPictureControl::Reset() +{ + delete iBitmap; + iBitmap = NULL; + delete iScaledBitmap; + iScaledBitmap = NULL; + + delete iConverter; + iConverter = NULL; + + SetModified( ETrue ); +} + +void CGmsPictureControl::NotifyViewEvent(TMsgViewEvent /*aEvent*/, + TInt /*aParam*/) +{ +} + +TInt CGmsPictureControl::ConversionReady( TAny* aPtr ) +{ + __ASSERT_ALWAYS(aPtr, User::Panic(KSmEditorGmsPic, ENullPtr) ); + static_cast( aPtr )->DoConversionReady(); + return 0; +} + +TInt CGmsPictureControl::ScalingReady( TAny* aPtr ) +{ + __ASSERT_ALWAYS(aPtr, User::Panic(KSmEditorGmsPic, ENullPtr) ); + static_cast( aPtr )->DoScalingReady(); + return 0; +} + +void CGmsPictureControl::PrepareForReadOnly(TBool /*aReadOnly*/) +{ +} + +TInt CGmsPictureControl::CountComponentControls() const + { + // This method is required by the base class + return 0; + } + +CCoeControl* CGmsPictureControl::ComponentControl(TInt /*aIndex*/) const + { + // This method is required by the base class + return NULL; + } + +void CGmsPictureControl::FocusChanged( TDrawNow /*aDrawNow*/ ) + { + // This method is required by the base class + } + +void CGmsPictureControl::SizeChanged() +{ + iBitmapRect = Rect(); + + if (AknLayoutUtils::ScalableLayoutInterfaceAvailable()) + { + TAknWindowComponentLayout layout = + AknLayoutScalable_Apps::mce_image_pane_g3(); + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( Rect(), layout.LayoutLine() ); + iBitmapRect = layoutRect.Rect(); + + // Adjust max height if needed, this is not the usual case but + // implemented here just because of supporting the existing + // public LoadImageL() method. Usually the size of imageRect + // should be fully determined by avkon layout! + if ( iMaxHeight > 0 && (TUint)iBitmapRect.Size().iHeight > iMaxHeight ) + { + iBitmapRect.SetHeight(iMaxHeight); + } + TInt yAxisOffset = Rect().iTl.iY - iBitmapRect.iTl.iY; + iBitmapRect.Move(0,yAxisOffset); + + // If leave occurs then scaling is not performed + TRAP_IGNORE( ScaleIfPossibleL( iBitmapRect.Size() ) ); + } + + else + { // Use old sizing functionality if scalable IF isn't available: + // Note that usage of image size and image rect is not identical + // to scalable version! + TSize imageSize(CalculateImageSize()); + + // If leave occurs then scaling is not performed + TRAP_IGNORE( ScaleIfPossibleL( imageSize ) ); + } +} + +void CGmsPictureControl::Draw(const TRect& /*aRect*/) const +{ + // Ensure that scaled bitmap exists and that no scaling is + // currently ongoing. + if ( iScaledBitmap && + iScaledBitmap->Handle() && + ! iScalingAO->IsActive() ) + { + CWindowGc& gc = SystemGc(); + gc.DrawBitmap(iBitmapRect,iScaledBitmap); + } +} + +/** +* This internal function is the old version and is used ONLY if scalable +* layout interface is NOT available. This should be removed when it is always +* available. +*/ +TSize CGmsPictureControl::CalculateImageSize() const +{ + TSize trgSize(0,0); + + TSize bmpSize = OriginalImageResolution(); + bmpSize.SetSize(bmpSize.iWidth*2, bmpSize.iHeight*2); + + TRect rect(Rect()); + + // Width is basically static during the session, but it's always + // calculated anyway. + if (bmpSize.iWidth < rect.Width()) + { + // "narrow" image - request only what is needed. + trgSize.iWidth = bmpSize.iWidth; + } + else + { + // "wide" image - request all we can get. + trgSize.iWidth = rect.Width(); + } + + // Height is dynamic, i.e. changes when moving up&down in the message. + // Request maximum height possible. + // Note: Either max size allowed by spec or the size of the image itself + // is considered here, i.e. not the given rect. + if ( iMaxHeight > 0 && (TUint)bmpSize.iHeight > iMaxHeight ) + { + trgSize.iHeight = iMaxHeight; + } + else + { + trgSize.iHeight = bmpSize.iHeight; + } + return trgSize; +} + +TBool CGmsPictureControl::ScaleIfPossibleL( TSize aSize ) +{ + if ( !iBitmap ) + { + // Image hasn't been loaded, cannot scale + return EFalse; + } + else if ( iConversionAO->IsActive() ) + { + // Conversion is ongoing, but not ready yet, + // image will be scaled after conversion finishes. + return EFalse; + } + + else + { + if ( !iScalingAO->IsActive() ) + { + // Scaling is possible, it is done asynchronously + delete iScaledBitmap; + iScaledBitmap = NULL; + iScaledBitmap = new( ELeave ) CFbsBitmap; + + User::LeaveIfError( iScaler->Scale( iScalingAO->iStatus, + *iBitmap, + TRect(iBitmap->SizeInPixels()), + *iScaledBitmap, + TRect(aSize) ) ); + iScalingAO->SetItActive(); + return ETrue; + } + } + return EFalse; +} + +void CGmsPictureControl::DoConversionReady() +{ + __ASSERT_DEBUG( iConversionAO->iStatus == KErrNone, + Panic(EConversionError) ); + + if ( iConversionAO->iStatus == KErrNone ) + { + SetModified( ETrue ); + // We want to scale the image now: + SetRect( Rect() ); + + //we must delete the converter here because it is holding the + //converted imagefile so that it cant be replaced when FORWARD:ing + delete iConverter; + iConverter = NULL; + } +} + +void CGmsPictureControl::DoScalingReady() +{ + __ASSERT_DEBUG( iScalingAO->iStatus == KErrNone, + Panic(EScalingError) ); + + if ( iScalingAO->iStatus == KErrNone ) + { + SetModified( ETrue ); + // We want to draw the image now: + DrawNow(); + } +} + + +void CGmsPictureControl::Panic(TGmsPicControlPanic aCode) + { + User::Panic(KSmEditorGmsPic, aCode); + } + +void CGmsPictureControl::ConstructL(const CCoeControl* aParent) +{ + __ASSERT_DEBUG( aParent, Panic(ENoParent) ); + + User::LeaveIfError( iFs.Connect() ); + + iControlType = EMsgImageControl; + + SetContainerWindowL(*aParent); + + TRect rect(aParent->Rect()); + if (rect.Height() == 0 || rect.Width() == 0) + { + // We have been called before view construction. + // Set rect to screen size. + rect.SetRect ( + TPoint(0,0), + iEikonEnv->EikAppUi()->ClientRect().Size()); + } + SetPosition(rect.iTl); + SetSizeWithoutNotification(rect.Size()); + + iConversionAO = new( ELeave ) CGmsAOCallBack( + TCallBack( ConversionReady, this ), CActive::EPriorityStandard ); + iScaler = IHLScaler::CreateL(); + iScalingAO = new( ELeave ) CGmsAOCallBack( + TCallBack( ScalingReady, this ), CActive::EPriorityStandard ); +} + +CGmsPictureControl::CGmsPictureControl() +{ + // By default iMaxHeight is not used: + iMaxHeight = 0; +} + +// End of File