--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingappbase/smartmessaging/gmsmodel/src/CGmsPictureControl.cpp Thu Dec 17 08:44:11 2009 +0200
@@ -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 <coeutils.h> // for ConeUtils::FileExists
+#include <AknUtils.h>
+#include <imageconversion.h>
+#include <aknlayoutscalable_apps.cdl.h>
+#include <MIHLScaler.h>
+
+// 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<CGmsPictureControl*>( aPtr )->DoConversionReady();
+ return 0;
+}
+
+TInt CGmsPictureControl::ScalingReady( TAny* aPtr )
+{
+ __ASSERT_ALWAYS(aPtr, User::Panic(KSmEditorGmsPic, ENullPtr) );
+ static_cast<CGmsPictureControl*>( 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