diff -r ae942d28ec0e -r 2455ef1f5bbc javauis/lcdui_akn/lcdui/src/CMIDTextFieldItem.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javauis/lcdui_akn/lcdui/src/CMIDTextFieldItem.cpp Wed Sep 01 12:33:18 2010 +0100 @@ -0,0 +1,691 @@ +/* +* Copyright (c) 2003 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: ?Description +* +*/ + + +#include +// +#include "CMIDTextFieldItem.h" +// CMIDEdwin API for iTextField and CMIDTextFieldEdwin::NewL +#include "CMIDTextFieldEdwin.h" +// API for iLabelControl +#include "CMIDItemLabel.h" +// CAknEdwinDrawingModifier API for iDrawingModifier +#include + +// LAF in UpdateLayout +#include +// information to decorate text +#include + +#include + +/** This macro is executed each time a trapped call returns an error code different than KErrNone */ +#undef TRAP_INSTRUMENTATION_LEAVE +#define TRAP_INSTRUMENTATION_LEAVE(aResult) DEBUG_INT2("In CMIDTextFieldItem.cpp, trapped method was called at line %D and got exception %D", __LINE__, aResult); + + +MMIDTextField* CMIDTextFieldItem::NewL( + const TDesC& aLabel, const TDesC& aText, TInt aConstraints, + TInt aMaxSize, CMIDUIManager* aUIManager) +{ + CMIDTextFieldItem* textFieldItem = new(ELeave)CMIDTextFieldItem(aUIManager); + CleanupStack::PushL(textFieldItem); + textFieldItem->ConstructL(aLabel,aText,aConstraints,aMaxSize); + CleanupStack::Pop(textFieldItem); + return textFieldItem; +} + +CMIDTextFieldItem::~CMIDTextFieldItem() +{ + if (iText) + { + delete iText; + iText = NULL; + } + if (iTextField) + { + delete iTextField; + iTextField = NULL; + } + if (iDrawingModifier) + { + delete iDrawingModifier; + iDrawingModifier = NULL; + } +} + +void CMIDTextFieldItem::DeleteTextL(TInt aOffset,TInt aLength) +{ + TextComponent()->DeleteTextL(aOffset,aLength); +} + +void CMIDTextFieldItem::SetTextL(const TDesC& aText) +{ + ASSERT(iTextField); + // Position of cursor is temporally set to start of text. + // This is prevetion of panic caused cursor posited off rectagle of CMIDTextField. + iTextField->SetCursorPosL(0, EFalse); + iTextField->SetTextL(aText); + // Setting position to right position. + iTextField->SetCursorPosL(aText.Length(), EFalse); +} + +void CMIDTextFieldItem::InsertTextL(const TDesC& aText,TInt aPosition) +{ + TextComponent()->InsertTextL(aText,aPosition); +} + +void CMIDTextFieldItem::SetConstraintsL(TUint aConstraints) +{ + HBufC* text = iTextField->GetTextL(); + CleanupStack::PushL(text); + TInt maxSize = iTextField->GetMaxSize(); + + delete iTextField; + iTextField = NULL; + + CreateTextFieldL(KNullDesC, aConstraints, maxSize); + iTextField->SetTextWithNewConstraintsL(text); + + if (iForm && IsFocused()) + {//in case non-midlet cmds have been added or removed + iForm->CurrentDisplayable().InitializeCbasL(); + } + + if (iForm) + { + // the newly created textbox needs to be layouted, request layout for the whole form + // as applying new constraints may change the size of the textfield + iForm->RequestLayoutL(); + } + + CleanupStack::PopAndDestroy(text); +} + +void CMIDTextFieldItem::CreateTextFieldL(const TDesC& aText, TUint aConstraints, TInt aMaxSize) +{ + ASSERT(!iTextField); + + iTextField = CMIDTextFieldEdwin::NewL(aConstraints, aText, aMaxSize, NULL, this); + iTextField->SetFocusing(ETrue); + iTextField->SetEdwinSizeObserver(this); + iTextField->SetEdwinObserver(this); + + // Get cursor position set by CMIDEdwin::NewL. This is needed since SetContainerWindowL + // and ActivateL calls lead into cursor position resetting, i.e. setting it to 0 pos. + TInt cursorPos = iTextField->CursorPos(); + + if (IsFocused()) + { + iTextField->SetFocus(ETrue); + } + + if (DrawableWindow()) + { + // do not set container window if the fieldItem does not have CCoeControl::iWin set + iTextField->SetContainerWindowL(*this); + } + + if (IsActivated()) + { + iTextField->ActivateL(); + } + + // Restore original cursor position + iTextField->SetCursorPosL(cursorPos, EFalse); +} + +void CMIDTextFieldItem::UpdateLayout() +{ + TAknWindowComponentLayout textPaneLayout = + AknLayoutScalable_Avkon::form2_midp_text_pane(0); + + TAknTextComponentLayout textLayout = + AknLayoutScalable_Avkon::form2_mdip_text_pane_t1(0); + + // set the top margin for Edwin + iEdwinMarginTop = textPaneLayout.LayoutLine().it; + + // set the minimum height of the Edwin (one line text) + TAknTextDecorationMetrics decorationMetrics(textLayout.LayoutLine().iFont); + TInt topMargin, bottomMargin; + + decorationMetrics.GetTopAndBottomMargins(topMargin, bottomMargin); + + iEdwinMinHeight = textPaneLayout.LayoutLine().iH + topMargin + bottomMargin; +} + + +TInt CMIDTextFieldItem::SetMaxSizeL(TInt aMaxSize) +{ + return TextComponent()->SetMaxSizeL(aMaxSize); +} + +TInt CMIDTextFieldItem::GetMaxSize() +{ + return TextComponent()->GetMaxSize(); +} + +TInt CMIDTextFieldItem::Size() +{ + return TextComponent()->Size(); +} + +TInt CMIDTextFieldItem::GetCaretPosition() +{ + return TextComponent()->GetCaretPosition(); +} + +HBufC* CMIDTextFieldItem::GetTextL() +{ + return TextComponent()->GetTextL(); +} + +void CMIDTextFieldItem::SetInitialInputModeL(const TDesC& aCharacterSubset) +{ + TextComponent()->SetInitialInputModeL(aCharacterSubset); +} + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +CMIDTextFieldItem::CMIDTextFieldItem(CMIDUIManager* aUIManager) + : CMIDControlItem(EDefault, aUIManager) +{ + iMMidItem = this; + SetFocusing(ETrue); +} + +/** Construct the item. + +We chose to inhibit redrawing of the edwin on reformat, +see CEikEdwin::OnReformatL() - this is called when laying-out the edwin. +This is done via iDrawingModifier. This avoids drawing of edwin in the wrong +position when modifying the form, or changing focus between items and resizing +the item when inserting or removing a line. +*/ +void CMIDTextFieldItem::ConstructL(const TDesC& aLabel,const TDesC& aText, + TInt aConstraints, TInt aMaxSize) +{ + CMIDControlItem::ConstructL(); + + TInt formWidth = FormClientAreaWidth(); + SetSize(TSize(formWidth, 0)); + + SetLabelL(aLabel); + iLabelControl->SetWidthL(formWidth); + + iDrawingModifier = new(ELeave)CAknEdwinDrawingModifier(); + iDrawingModifier->SetInhibitNotifyNewFormatDrawing(ETrue); + + CreateTextFieldL(aText, aConstraints, aMaxSize); + + UpdateLayout(); +} + +CMIDEdwin* CMIDTextFieldItem::TextComponent() const +{ + return iTextField; +} + +/** The minimum size is usually the full form width and the height of the label, plus + the minimum height of the editor (usually one line) plus 3 times the vertical margin. */ +TSize CMIDTextFieldItem::MinimumSize() +{ + TInt minHeight = + iEdwinMarginTop + + iEdwinMinHeight + + ItemContentBottomMargin(); + + if (iLabelControl && iLabelControl->Text()->Length()) + minHeight += OneLineLabelHeight(); + + return TSize(FormClientAreaWidth(), minHeight); +} + +TInt CMIDTextFieldItem::CountComponentControls() const +{ + return 2; +} + +CCoeControl* CMIDTextFieldItem::ComponentControl(TInt aIndex) const +{ + switch (aIndex) + { + case 0: + return iLabelControl; + case 1: + return iTextField; + } + return NULL; +} + +void CMIDTextFieldItem::Draw(const TRect& aRect) const +{ + CMIDControlItem::Draw(aRect); +} + +void CMIDTextFieldItem::SizeChanged() +{ + TPoint position = Position(); + + TRect labelRect(position, TSize(FormClientAreaWidth(), LabelHeight())); + + TPoint textTl = TPoint(position.iX, + LabelHeight() > 0 ? labelRect.iBr.iY : position.iY); + TPoint textBr = Rect().iBr - TPoint(0, ItemContentBottomMargin()); + + TRect textRect(textTl, textBr); + + if (LabelHeight() > 0) + { + iLabelControl->SetRect(labelRect); + } + + if (iTextField) + { + iTextField->DoLayout(textRect); + } + + CMIDControlItem::SizeChanged(); +} + +void CMIDTextFieldItem::SetContainerWindowL(const CCoeControl& aContainer) +{ + CMIDControlItem::SetContainerWindowL(aContainer); + + // Save the original cursor position. This is needed since SetContainerWindowL + // and ActivateL call lead into cursor position resetting, i.e. setting it to 0 pos. + TInt cursorPos = iTextField->CursorPos(); + + iTextField->SetContainerWindowL(*this); + + SetObserver(iForm); + + ActivateL(); + + // Restore original cursor position + iTextField->SetCursorPosL(cursorPos, EFalse); + +} + +void CMIDTextFieldItem::FocusChanged(TDrawNow aDrawNow) +{ + if (IsFocused()) + { + // Setting focus to iTextField changes the cursor visibility. This might cause + // a cursor flashing on the screen, if the focus is set to a TF that is not in the + // visible form area currently when a form is switched from background + // to foreground. To prevent this EAvkonDisableCursor is set temporarily. + iTextField->AddFlagToUserFlags(CEikEdwin::EAvkonDisableCursor); + iTextField->SetFocus(ETrue); + iTextField->RemoveFlagFromUserFlags(CEikEdwin::EAvkonDisableCursor); + SetCursorVisibility(IsVisible()); + } + else + { + iTextField->SetFocus(EFalse); + } + + CMIDControlItem::FocusChanged(aDrawNow); + // DoLayout and change text color when focused + SizeChanged(); + TRAP_IGNORE(UpdateTextColorsL()); +} + +void CMIDTextFieldItem::HandleCurrentL(TBool aCurrent) +{ + // set initial input modes when TextField becomes the focused item + iTextField->HandleCurrentL(aCurrent); +} + +void CMIDTextFieldItem::ResolutionChange(TInt /*aType*/) +{ + UpdateLayout(); +} + +void CMIDTextFieldItem::PostFocusTransferEvent(TBool aFocus, CMIDForm::TDirection /*aDirection*/) +{ + TRAP_IGNORE(HandleCurrentL(aFocus)); +} + +/** Basically pass the key event to the text box. Also check if the text has been +modified and if so report an item state change event. Attention must be taken here +because the text box may eat the EEventKey type so we must store the existing text +in the key down event and compare it in the key up event. */ +TKeyResponse CMIDTextFieldItem::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType) +{ + + if (aType == EEventKeyDown) + { + delete iText; + iText = NULL; + + iText = iTextField->GetTextInHBufL(); + } + return iTextField->OfferKeyEventL(aKeyEvent, aType); +} + +#ifdef RD_SCALABLE_UI_V2 +void CMIDTextFieldItem::HandlePointerEventL(const TPointerEvent& aPointerEvent) +{ + if (AknLayoutUtils::PenEnabled()) + { + if (!iForm->PhysicsScrolling()) + { + SetCursorVisibility(ETrue); + } + + //update focus + if (!iForm->TryDetectLongTapL(aPointerEvent)) + { +#ifdef RD_JAVA_S60_RELEASE_9_2 + // In single click UI VKB is opened with first tap. + if (!iForm->PhysicsScrolling()) +#else + // In non-single click UI, + // VKB is opened when tapping already focused item. + if (!iForm->IsFocusChangingWithPen() && IsFocused() && !iForm->PhysicsScrolling()) +#endif // RD_JAVA_S60_RELEASE_9_2 + { + TPointerEvent pEvent = aPointerEvent; + // If label area is tapped the coordinates are transferred to editor area. + // By doing coordinate switching VKB is launched also when label is tapped. + if (iLabelControl->Rect().Contains(pEvent.iPosition)) + { + pEvent.iPosition.iY = iTextField->Rect().iTl.iY; + } + CCoeControl::HandlePointerEventL(pEvent); + } + //else do not forward pointer event to CCoeControl as do not want to have any action + //on unfocused TextField. + } + } +} +#endif // RD_SCALABLE_UI_V2 + +void CMIDTextFieldItem::MakeVisible(TBool aVisible) +{ + CMIDControlItem::MakeVisible(aVisible); + SetCursorVisibility(aVisible); +} + +TSize CMIDTextFieldItem::ResetPreferredSize() const +{ + CMIDTextFieldItem* self = const_cast(this); + TRAP_IGNORE(self->SetPreferredSizeL(iRequestedPreferredSize)); + return iPreferredSize; +} + +/** This is called before the form is re-laid-out. See ResetPreferredSize(). + If we have a requested height we select the max between this height and our + minimum height. The width is always the form or screen width. Then we do layout. + + If we don't have a requested height, we do layout with a negative height + (-1) and this signals to CMIDEdwin to use whatever height correcsponds to the + number of formatted lines. See CMIDEdwin::DoLayout(). So, in this case iPreferredSize + is set after doing layout. + + The editor can be resized in HandleEdwinSizeEventL() only if the preferred height has + not been given. + + @note SetPreferredSize() always sets TextField's preferred size + (i.e. how much space it needs so all control (label+text) is visible) +*/ +void CMIDTextFieldItem::SetPreferredSizeL(const TSize& aSize) +{ + if (!iTextField) + return; + + iRequestedPreferredSize = CheckRequestedSize(aSize); + iPreferredSize = iRequestedPreferredSize; + + iPreferredSize.iWidth = FormClientAreaWidth(); //This is our fixed width, no less, no more + + TSize editorSize(iPreferredSize); + + // calculate the preferred size case + TRect rect(TPoint(0,0), editorSize); + iTextField->DoLayout(rect); + + iPreferredSize.iHeight = LabelHeight() + ItemPreferredHeightWithoutLabel(); +} + +TInt CMIDTextFieldItem::ItemPreferredHeightWithoutLabel() +{ + TInt height = ((CCoeControl*)iTextField)->Size().iHeight + + iEdwinMarginTop + ItemContentBottomMargin(); + + return height; +} + +TRect CMIDTextFieldItem::FocusableRect() +{ + return iTextField->Rect(); +} + +/** We set the new height of the textbox and form item by calling SetSize(). If we +are inside a form (which we most likely are) we then call CMIDForm::RefreshItemL(this). +This will take care of re-positioning all other items and updating the scroll bars. + +We will not resize the editor if the use has specified a preferrred height +(iRequestedPreferredSize.iHeight) in which case the editor must be either this height +or the minimum height. Also, if iPreferredSize.iHeight is -1, it means we are inside +a SetPreferredSizeL() call, so we mustn't call iForm->RequestLayoutL() because this +method ends up calling SetPreferredSizeL() and so we end up in infinite recursive calls. +So iPreferredSize.iHeight == -1 means do not do anything basically. */ +TBool CMIDTextFieldItem::HandleEdwinSizeEventL(CEikEdwin* /*aEdwin*/, + TEdwinSizeEvent /*aEventType*/, TSize aDesirableEdwinSize) +{ + if (iTextField->IsPartialFormatting()) + { + // ignore the asynchronous HandleEdwinSizeEvents (e.g TextLength() > 1900 chars) + // that will occur much later when Edwin finishes formatting. + // This is a protection against requesting form layout while form might be scrolling. + // In this partial formatting mode, the preferred size reflects only those number of lines + // that were reformatted when quering for the preferred size. + // This way, TextFieldItem will continue to have the preferred size (which does not show all visible lines). + + return EFalse; + } + + if (iPreferredSize.iHeight != -1) + { + TInt desiredHeight = + LabelHeight() + + iEdwinMarginTop + + aDesirableEdwinSize.iHeight + + ItemContentBottomMargin(); + + if (iPreferredSize.iHeight != desiredHeight) + { + if (iForm) + {//new layout for form, hence new edwin size will be taken into account + iForm->RequestLayoutL(ETrue); + } + } + } + + return EFalse; +} + + +TTypeUid::Ptr CMIDTextFieldItem::MopSupplyObject(TTypeUid aId) +{ + // Return the edwin drawing modifier, CAknEdwinDrawingModifier, if ID matches, see + // HandleEdwinSizeEventL(). Otherwise call CMIDControlItem::MopSupplyObject(). + if (aId.iUid == CAknEdwinDrawingModifier::ETypeId) + return aId.MakePtr(iDrawingModifier); + + return CMIDControlItem::MopSupplyObject(aId); +} + +void CMIDTextFieldItem::HandleEdwinEventL(CEikEdwin* /*aEdwin*/,TEdwinEvent /*aEventType*/) +{ + DoHandleEdwinEventL(); +} + +void CMIDTextFieldItem::HandleControlEventL(CCoeControl* /*aSource*/, + MCoeControlObserver::TCoeEvent aEventType) +{ + if (aEventType == MCoeControlObserver::EEventStateChanged) + { + DoHandleEdwinEventL(); + + // check if text has changed and eventually notify Java via + // itemStateChanged() + HBufC* newText = iTextField->GetTextInHBufL(); + TBool textChanged = EFalse; + + if ((!iText && newText) || (iText && !newText) || + (iText && newText && (*iText != *newText))) + { + textChanged = ETrue; + } + + delete iText; + iText = newText; + + if (textChanged) + { + ReportEventL(MCoeControlObserver::EEventStateChanged); + } + } + else if (aEventType == MCoeControlObserver::EEventRequestFocus) + { + static_cast(iForm)->HandleControlEventL(this, aEventType); + } +} + +void CMIDTextFieldItem::DoHandleEdwinEventL() +{ + TPoint point; + TBool success = GetCursorPosL(point); + if (success && iForm) + { + if (point.iY < 0) + { + iForm->ScrollRelative(-(point.iY - 10)); + iForm->UpdatePhysics(); + } + else if (point.iY >= iForm->Height()) + { + iForm->ScrollRelative((iForm->Height() - point.iY) - 10); + iForm->UpdatePhysics(); + } + } +} + +TBool CMIDTextFieldItem::GetCursorPosL(TPoint& aPoint) +{ + TInt pos = iTextField->CursorPos(); + CTextView* tv = iTextField->TextView(); + return tv->DocPosToXyPosL(pos, aPoint); +} + +void CMIDTextFieldItem::SetLabelL(const TDesC& aLabel) +{ + CMIDControlItem::SetLabelL(aLabel); +} + +void CMIDTextFieldItem::Dispose() +{ + delete this; +} + +void CMIDTextFieldItem::SetLayoutL(TLayout aLayout) +{ + CMIDItem::SetLayoutL(aLayout); +} + +void CMIDTextFieldItem::AddCommandL(MMIDCommand* aCommand) +{ + CMIDItem::AddCommandL(aCommand); +} + +void CMIDTextFieldItem::RemoveCommand(MMIDCommand* aCommand) +{ + CMIDItem::RemoveCommand(aCommand); +} + +void CMIDTextFieldItem::SetDefaultCommand(MMIDCommand* aCommand) +{ + CMIDItem::SetDefaultCommand(aCommand); +} + +TSize CMIDTextFieldItem::PreferredSize() const +{ + return iPreferredSize; +} + +TSize CMIDTextFieldItem::MinimumSize() const +{ + CCoeControl* control = const_cast(this); + return control->MinimumSize(); +} + +TCoeInputCapabilities CMIDTextFieldItem::InputCapabilities() const +{ + TCoeInputCapabilities inputCapabilities(TCoeInputCapabilities::ENone, NULL, + const_cast(this)); + inputCapabilities.MergeWith(iTextField->InputCapabilities()); + return inputCapabilities; +} + +void CMIDTextFieldItem::RestoreInnerFocus() +{ + // Restore active textfield line (with cursor) on screen by resetting + // the text selection and the cursor position + if (iTextField) + { + TCursorSelection sel = iTextField->Selection(); + // Exceptions can be ignored, because failing of SetSelectionL may cause + // only a cosmetic visual problems + TRAP_IGNORE(iTextField->SetSelectionL(sel.iCursorPos, sel.iAnchorPos)); + } +} + +void CMIDTextFieldItem::SetCursorVisibility(TBool aVisible) +{ + if (IsFocused()) + { + TCursor::TVisibility textCursor = + aVisible ? TCursor::EFCursorFlashing : TCursor::EFCursorInvisible; + + // lineCursor is not used in TextField, so it is set to TCursor::EFCursorInvisible always + TRAP_IGNORE(iTextField->TextView()->SetCursorVisibilityL(TCursor::EFCursorInvisible, + textCursor)); + } +} + +void CMIDTextFieldItem::UpdateTextColorsL() +{ + if (iTextField) + { + if (iHighlighted) + { + // Text colour from skin - highlighted + iTextField->SetTextSkinColorIdL(EAknsCIQsnTextColorsCG8); + } + else + { + // Text colour from skin - unfocused + iTextField->SetTextSkinColorIdL(EAknsCIQsnTextColorsCG6); + } + } +}