emailuis/emailui/src/FreestyleEmailUiShortcutBinding.cpp
changeset 0 8466d47a6819
child 8 e1b6206813b4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/emailuis/emailui/src/FreestyleEmailUiShortcutBinding.cpp	Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,539 @@
+/*
+* Copyright (c) 2008 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: This file implements class CFSEmailUiShortcutBinding.
+ *
+ */
+
+
+#include "emailtrace.h"
+#include <PtiEngine.h>
+#include <PtiKeyMappings.h>
+#include <centralrepository.h>
+#include <AvkonInternalCRKeys.h>
+#include <eikmenup.h>
+
+#include "FreestyleEmailUiShortcutBinding.h"
+#include "FSEmail.pan"
+
+
+//////////////////////////////
+// The shortcut binding tables
+// ---------------------------
+// In case the same shortcut is assigned for multiple commands, the shortcut to 
+// command conversion will always return the first mapping.
+//
+// Shortcuts with modifiers must be listed before unmodifed shortcuts, at least when
+// the same key has different meaning as plain key and with modifier. Otherwise,
+// the unmodified mapping will be used also for the modified key.
+
+// Shortcuts for the mail list view
+const CFSEmailUiShortcutBinding::TShortcutBinding KMailListShortcuts[] = 
+    {
+        { 0,  'A', 0,     EFsEmailUiCmdActionsReplyAll },
+        { 0,  'R', 0,     EFsEmailUiCmdActionsReply },
+        { 0,  'F', 0,     EFsEmailUiCmdActionsForward }, 
+        { 0,  'M', 0,     EFsEmailUiCmdActionsMove },
+        { 0,    'Y', 0,     EFsEmailUiCmdActionsCopyMessage },
+        { 0,    'D', 0,     EFsEmailUiCmdActionsDelete },
+        { 0, EStdKeyBackspace, 0, EFsEmailUiCmdActionsDelete },
+        { 0,  'T', 0,     EFsEmailUiCmdGoToTop },
+        { 0,  'B', 0,     EFsEmailUiCmdGoToBottom },
+        { 0,    'J', 0,     EFsEmailUiCmdPageUp },
+        { 0,    'K', 0,     EFsEmailUiCmdPageDown },
+        { 0,    'L', 0,     EFsEmailUiCmdActionsFlag },
+        { 0,  'C', 0,     EFsEmailUiCmdCompose },
+        { 0,    'E', 0,     EFsEmailUiCmdCalActionsAccept }, 
+        { 0,    'G', 0,     EFsEmailUiCmdCalActionsTentative },
+        { 0,    'V', 0,     EFsEmailUiCmdCalActionsDecline },
+        { 0,    'O', 0,     EFsEmailUiCmdActionsOpen },
+        { 0,  'Z', 0,     EFsEmailUiCmdSync },
+        { 0,    'S', 0,     EFsEmailUiCmdSearch },
+        { 0,    'Q', 0,     EFsEmailUiCmdGoToSwitchFolder },
+        { 0,    'W', 0,     EFsEmailUiCmdGoToSwitchSorting },
+        { 0,    'H', 0,     EFsEmailUiCmdHelp },
+        
+        { 0,  'U', 0,     EFsEmailUiCmdMarkAsReadUnreadToggle },
+        { 0,  'U', 0,     EFsEmailUiCmdMarkAsRead },   
+        { 0,  'U', 0,     EFsEmailUiCmdMarkAsUnread },
+        
+        { 0,    'I', 0,     EFsEmailUiCmdActionsCollapseExpandAllToggle },
+        { 0,    'I', 0,     EFsEmailUiCmdActionsCollapseAll },
+        { 0,    'I', 0,     EFsEmailUiCmdActionsExpandAll },
+        
+        { 0,  0, 0,       EFsEmailUiCmdMarkUnmarkToggle },
+        { 0,  0, 0,       EFsEmailUiCmdMarkMark }, 
+        { 0,  0, 0,       EFsEmailUiCmdMarkUnmark }
+    };
+
+// Shortcuts for the mail viewer
+const CFSEmailUiShortcutBinding::TShortcutBinding KMailViewerShortcuts[] = 
+    {
+        { 0,    'C', EModifierCtrl, EFsEmailUiCmdActionsCopyToClipboard },
+
+        { 0,  'A', 0,     EFsEmailUiCmdActionsReplyAll },
+        { 0,  'R', 0,     EFsEmailUiCmdActionsReply },
+        { 0,  'F', 0,     EFsEmailUiCmdActionsForward }, 
+        { 0,  'F', 0,     EFsEmailUiCmdActionsForward2 }, 
+        { 0,  'M', 0,     EFsEmailUiCmdActionsMoveMessage },
+        { 0,    'Y', 0,     EFsEmailUiCmdActionsCopyMessage },
+        { 0,    'D', 0,     EFsEmailUiCmdActionsDelete },
+        { 0, EStdKeyBackspace, 0, EFsEmailUiCmdActionsDelete },
+        { 0,  'T', 0,     EFsEmailUiCmdGoToTop },
+        { 0,  'B', 0,     EFsEmailUiCmdGoToBottom },
+        { 0,    'J', 0,     EFsEmailUiCmdPageUp },
+        { 0,    'K', 0,     EFsEmailUiCmdPageDown },
+        { 0,  'N', 0,     EFsEmailUiCmdNextMessage },
+        { 0,  'P', 0,     EFsEmailUiCmdPreviousMessage },
+        { 0,    'L', 0,     EFsEmailUiCmdActionsFlag },
+        { 0,  'C', 0,     EFsEmailUiCmdCompose },
+        { 0,    'H', 0,     EFsEmailUiCmdHelp },
+        
+        { 0,  'U', 0,     EFsEmailUiCmdMarkAsReadUnreadToggle },
+        { 0,  'U', 0,     EFsEmailUiCmdMarkAsRead },   
+        { 0,  'U', 0,     EFsEmailUiCmdMarkAsUnread }
+    };
+
+// Shortcuts for the HTML viewer
+const CFSEmailUiShortcutBinding::TShortcutBinding KHtmlViewerShortcuts[] = 
+    {
+        { 0,  'A', 0,     EFsEmailUiCmdActionsReplyAll },
+        { 0,  'R', 0,     EFsEmailUiCmdActionsReply },
+        { 0,  'F', 0,     EFsEmailUiCmdActionsForward }, 
+        { 0,    'D', 0,     EFsEmailUiCmdActionsDelete },
+        { 0, EStdKeyBackspace, 0, EFsEmailUiCmdActionsDelete },
+        { 0,    'H', 0,     EFsEmailUiCmdHelp },
+        { 0,  '+', 0,     EFsEmailUiCmdZoomIn },
+        { 0,  '-', 0,     EFsEmailUiCmdZoomOut }
+    };
+
+// Shortcuts for the search results view    
+const CFSEmailUiShortcutBinding::TShortcutBinding KSearchResultsShortcuts[] = 
+    {
+        { 0,    'O', 0,     EFsEmailUiCmdOpen },
+        { 0,    'S', 0,     EFsEmailUiCmdSearch },
+        { 0,    'S', 0,     EFsEmailUiCmdNewSearch },
+        { 0,    'H', 0,     EFsEmailUiCmdHelp },
+        { 0,  'T', 0,     EFsEmailUiCmdGoToTop },
+        { 0,  'B', 0,     EFsEmailUiCmdGoToBottom },
+        { 0,    'J', 0,     EFsEmailUiCmdPageUp },
+        { 0,    'K', 0,     EFsEmailUiCmdPageDown },
+        { 0,  'A', 0,     EFsEmailUiCmdActionsReplyAll },
+        { 0,  'R', 0,     EFsEmailUiCmdActionsReply },
+        { 0,  'F', 0,     EFsEmailUiCmdActionsForward }, 
+        { 0,    'D', 0,     EFsEmailUiCmdActionsDelete },
+        { 0, EStdKeyBackspace, 0, EFsEmailUiCmdActionsDelete },
+        { 0,    'E', 0,     EFsEmailUiCmdCalActionsAccept }, 
+        { 0,    'G', 0,     EFsEmailUiCmdCalActionsTentative },
+        { 0,    'V', 0,     EFsEmailUiCmdCalActionsDecline },        
+        { 0,  'U', 0,     EFsEmailUiCmdMarkAsReadUnreadToggle },
+        { 0,  'U', 0,     EFsEmailUiCmdMarkAsRead },   
+        { 0,  'U', 0,     EFsEmailUiCmdMarkAsUnread }
+    };
+
+// Shortcuts for generic list views. These are used with Mail details, attachment list, etc.    
+const CFSEmailUiShortcutBinding::TShortcutBinding KGenericListShortcuts[] = 
+    {
+        { 0,    'C', EModifierCtrl, EFsEmailUiCmdActionsCopyToClipboard },
+
+        { 0,    'O', 0,     EFsEmailUiCmdOpen },
+        { 0,    'D', 0,     EFsEmailUiCmdActionsDelete },
+        { 0, EStdKeyBackspace, 0, EFsEmailUiCmdActionsDelete },
+        { 0,  'T', 0,     EFsEmailUiCmdGoToTop },
+        { 0,  'B', 0,     EFsEmailUiCmdGoToBottom },
+        { 0,    'J', 0,     EFsEmailUiCmdPageUp },
+        { 0,    'K', 0,     EFsEmailUiCmdPageDown },
+        { 0,    'H', 0,     EFsEmailUiCmdHelp },
+
+        { 0,    'I', 0,     EFsEmailUiCmdActionsCollapseExpandAllToggle },
+        { 0,    'I', 0,     EFsEmailUiCmdActionsCollapseAll },
+        { 0,    'I', 0,     EFsEmailUiCmdActionsExpandAll }
+    };
+
+// Shortcuts for the main grid
+const CFSEmailUiShortcutBinding::TShortcutBinding KMainGridShortcuts[] = 
+    {
+        { 0,    'O', 0,     EFsEmailUiCmdOpen },
+        { 0,  'Z', 0,     EFsEmailUiCmdSync },
+        { 0,  'Z', 0,     EFsEmailUiCmdSyncAll },
+        { 0,    'H', 0,     EFsEmailUiCmdHelp },
+    };
+
+// Shortcuts for send attachments list view
+const CFSEmailUiShortcutBinding::TShortcutBinding KSendAttachmentListShortcuts[] =
+    {
+        { 0,    'O', 0,     ESendAttachmentMenuOpen },
+        { 0,    'D', 0,     ESendAttachmentMenuRemoveAttachment },
+        { 0, EStdKeyBackspace, 0, ESendAttachmentMenuRemoveAttachment },
+        { 0,  'T', 0,     EFsEmailUiCmdGoToTop },
+        { 0,  'B', 0,     EFsEmailUiCmdGoToBottom },
+        { 0,    'J', 0,     EFsEmailUiCmdPageUp },
+        { 0,    'K', 0,     EFsEmailUiCmdPageDown },
+        { 0,    'H', 0,     ESendAttachmentMenuHelp },
+        { 0,    'I', 0,     EFsEmailUiCmdActionsCollapseExpandAllToggle }
+    };
+    
+// Shortcuts for settings and global settings views
+const CFSEmailUiShortcutBinding::TShortcutBinding KSettingsShortcuts[] =
+    {
+        { 0,    'O', 0,     EFsEmailUiCmdOpen },
+        { 0,  'T', 0,     EFsEmailUiCmdGoToTop },
+        { 0,  'B', 0,     EFsEmailUiCmdGoToBottom },
+        { 0,    'J', 0,     EFsEmailUiCmdPageUp },
+        { 0,    'K', 0,     EFsEmailUiCmdPageDown },
+        { 0,    'H', 0,     EFsEmailUiCmdHelp }
+    };
+
+///////////////////////
+// The class definition 
+CFSEmailUiShortcutBinding* CFSEmailUiShortcutBinding::NewL()
+    {
+    FUNC_LOG;
+    CFSEmailUiShortcutBinding* self = new (ELeave) CFSEmailUiShortcutBinding();
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+    
+// ----------------------------------------------------------------------------    
+CFSEmailUiShortcutBinding::~CFSEmailUiShortcutBinding()
+    {
+    FUNC_LOG;
+    delete iPtiEngine;
+    iQwertyMappings = NULL; // owned by iPtiEngine
+    iHalfQwertyMappings = NULL; // ownned by iPtiEngine
+    iKbLayoutProperty.Close();
+    }
+        
+        
+// ----------------------------------------------------------------------------    
+TInt CFSEmailUiShortcutBinding::CommandForShortcutKey( const TKeyEvent& aKey, 
+                                                       TShortcutContext aContext ) const
+    {
+    FUNC_LOG;
+    TText shortcut = aKey.iScanCode;
+    TBuf<1> keyData; // we are only interested about the first char of the key
+    
+    TKeyBoardType kbType = KeyBoardType();
+
+    if ( kbType == EQwerty4x12 || kbType == EQwerty4x10 || 
+         kbType == EQwerty3x11 || kbType == ECustomQwerty )
+        {
+        // One of the QWERTY modes
+        // Map the key to the corresponding character on the current keyboard
+        // If Fn is held depressed, use the Fn mappings, otherwise use upper case mappings.
+        TPtiTextCase caseMode = EPtiCaseUpper;
+#ifdef RD_INTELLIGENT_TEXT_INPUT        
+        if ( aKey.iModifiers&EModifierRightFunc )
+            {
+            caseMode = EPtiCaseFnLower;
+            }
+#endif // RD_INTELLIGENT_TEXT_INPUT
+        if ( iQwertyMappings )
+            {
+            iQwertyMappings->GetDataForKey( static_cast<TPtiKey>(aKey.iScanCode), 
+                    keyData, caseMode );
+            }
+        }
+    else if ( kbType == EHalfQwerty )
+        {
+        // Half-QWERTY mode
+        // Map the key to the corresponding character in the Fn mode
+        if ( iHalfQwertyMappings )
+            {
+#ifdef RD_INTELLIGENT_TEXT_INPUT        
+            iHalfQwertyMappings->GetDataForKey( static_cast<TPtiKey>(aKey.iScanCode), 
+                    keyData, EPtiCaseFnLower );
+#endif // RD_INTELLIGENT_TEXT_INPUT
+            }
+        }
+    else
+        {
+        // ITU-T mode, use scancode directly without mapping
+        }
+    
+    // Substitute the scan code with the mapped character if available
+    if ( keyData.Length() )
+        {
+        shortcut = keyData[0];
+        }
+    // Map hash and asterisk keys separately if they have not been mapped in PtiEngine
+    else if ( shortcut == EStdKeyHash )
+        {
+        shortcut = '#';
+        }
+    else if ( shortcut == EStdKeyNkpAsterisk )
+        {
+        shortcut = '*';
+        }
+
+    return CommandForShortcut( shortcut, aContext, aKey.iModifiers );
+    }
+        
+        
+// ----------------------------------------------------------------------------    
+TInt CFSEmailUiShortcutBinding::CommandForShortcut( TText aShortcut, 
+                                                    TShortcutContext aContext,
+                                                    TUint32 aModifiers )
+    {
+    FUNC_LOG;
+    TInt command = KErrNotFound;
+    
+    if ( aShortcut ) // value 0 is used as mark for no shortcut
+        {
+        TInt count = 0;
+        const TShortcutBinding* bindings = NULL;
+
+        // Select appropriate binding table    
+        GetBindingsForContext( bindings, count, aContext );
+            
+        // Search command from the binding table
+        for ( TInt i=0 ; i<count && command==KErrNotFound  ; ++i )
+            {
+            TBool isItutShortcut = ( aShortcut == bindings[i].iItutShortcut );
+            
+            TBool isQwertyShortcut = ( aShortcut == bindings[i].iQwertyShortcut );
+            // Check the modifier keys for the QWERTY shortcut
+            if ( isQwertyShortcut )
+                {
+                TUint32 matchingModifiers = ( aModifiers & bindings[i].iQwertyModifiers );
+                if ( matchingModifiers != bindings[i].iQwertyModifiers )
+                    {
+                    isQwertyShortcut = EFalse;
+                    }
+                }
+                                       
+            if ( isItutShortcut || isQwertyShortcut )
+                {
+                command = bindings[i].iCommandId;
+                }
+            }
+        }
+        
+    return command;
+    }
+    
+    
+// ----------------------------------------------------------------------------    
+TText CFSEmailUiShortcutBinding::ShortcutForCommand( TInt aCommandId, 
+                                                     TShortcutContext aContext, 
+                                                     TBool aQwertyMode )
+    {
+    FUNC_LOG;
+    TText shortcut = 0;
+    TInt count = 0;
+    const TShortcutBinding* bindings = NULL;
+    
+    // Select appropriate binding table
+    GetBindingsForContext( bindings, count, aContext );
+        
+    // Search shortcut from the binding table
+    for ( TInt i=0 ; i<count && !shortcut  ; ++i )
+        {
+        if ( aCommandId == bindings[i].iCommandId )
+            {
+            if ( aQwertyMode )
+                {
+                // Only single-key shortcuts are supported here.
+                if ( !bindings[i].iQwertyModifiers )
+                    {
+                    shortcut = bindings[i].iQwertyShortcut;
+                    }
+                }
+            else
+                {
+                shortcut = bindings[i].iItutShortcut;
+                }
+            }
+        }
+        
+    return shortcut;
+    }
+    
+    
+// ----------------------------------------------------------------------------    
+void CFSEmailUiShortcutBinding::AppendShortcutHintsL(
+	CEikMenuPane& aMenuPane,
+	TShortcutContext aContext ) const
+    {
+    FUNC_LOG;
+    TKeyBoardType kbType = KeyBoardType();
+    TBool isQwerty = 
+        ( kbType != ENoKeyboard && kbType != EItutKeyPad && kbType != EHalfQwerty );
+    
+    // Browse through the commands in the menu pane and append shortcuts
+    // where available.
+    TInt count = aMenuPane.NumberOfItemsInPane();
+    
+    for ( TInt i = 0; i < count; ++i )
+        {
+        CEikMenuPaneItem::SData& itemData = aMenuPane.ItemDataByIndexL( i );
+        TText hint = ShortcutForCommand(
+        	itemData.iCommandId, aContext, isQwerty );        
+        if ( hint )
+            {
+            AppendHintToCaption( itemData.iText, hint );
+            }
+        }
+    }
+    
+    
+// ----------------------------------------------------------------------------    
+CFSEmailUiShortcutBinding::CFSEmailUiShortcutBinding()
+    {
+    FUNC_LOG;
+    }
+	
+	
+// ----------------------------------------------------------------------------    
+void CFSEmailUiShortcutBinding::ConstructL()
+    {
+    FUNC_LOG;
+    iPtiEngine = CPtiEngine::NewL();
+    
+    // Always use English mappings for QWERTY keyboards. This is because it is not 
+    // certain that the mappings of the current language hold latin alphabet at all.
+    // English should be available in all device variants as an optional input language.
+    CPtiCoreLanguage* lang = 
+        static_cast<CPtiCoreLanguage*>( iPtiEngine->GetLanguage( ELangEnglish ) );
+    if (lang)
+        {
+        iQwertyMappings = static_cast<CPtiKeyMappings*>( lang->GetQwertyKeymappings() );
+#ifdef RD_INTELLIGENT_TEXT_INPUT        
+        iHalfQwertyMappings = static_cast<CPtiKeyMappings*>( lang->GetHalfQwertyKeymappings() );
+#endif // RD_INTELLIGENT_TEXT_INPUT        
+        }
+    lang = NULL; // owned by iPtiEngine
+    
+    
+    if ( !iQwertyMappings && !iHalfQwertyMappings )
+        {
+        // In non-QWERTY devices we can free up PtiEngine right away, because
+        // it is not needed anyway.
+        delete iPtiEngine;
+        iPtiEngine = NULL;
+        }
+
+    iKbLayoutProperty.Attach( KCRUidAvkon, KAknKeyBoardLayout );
+    }
+	
+	
+// ----------------------------------------------------------------------------    
+CFSEmailUiShortcutBinding::TKeyBoardType CFSEmailUiShortcutBinding::KeyBoardType() const
+    {
+    FUNC_LOG;
+    TInt keyboardType = ENoKeyboard;
+
+    // RProperty does not define Get() as a constant function. This is
+    // probably just a flaw in the interface. Cast away constness to
+    // circumvent this.
+    RProperty& kbProperty = const_cast<RProperty&>(iKbLayoutProperty);
+    kbProperty.Get( keyboardType );
+    return static_cast<TKeyBoardType>( keyboardType );
+    }
+
+	
+// ----------------------------------------------------------------------------    
+void CFSEmailUiShortcutBinding::GetBindingsForContext( const TShortcutBinding*& aBindingArray, 
+                                                       TInt& aBindingCount,
+                                                       TShortcutContext aContext )
+    {
+    FUNC_LOG;
+    switch (aContext)
+        {
+        case EContextMailList:
+            {
+            aBindingCount = sizeof(KMailListShortcuts) / sizeof(TShortcutBinding);
+            aBindingArray = KMailListShortcuts;
+            }
+        break;
+
+        case EContextSearchResults:
+            {
+            aBindingCount = sizeof(KSearchResultsShortcuts) / sizeof(TShortcutBinding);
+            aBindingArray = KSearchResultsShortcuts;
+            }
+        break;
+
+        case EContextMailViewer:
+            {
+            aBindingCount = sizeof(KMailViewerShortcuts) / sizeof(TShortcutBinding);
+            aBindingArray = KMailViewerShortcuts;
+            }
+        break;
+
+        case EContextHtmlViewer:
+            {
+            aBindingCount = sizeof(KHtmlViewerShortcuts) / sizeof(TShortcutBinding);
+            aBindingArray = KHtmlViewerShortcuts;
+            }
+        break;
+        
+        case EContextMailDetails:
+        case EContextFolderList:
+        case EContextAttachmentList:
+        case EContextDownloadManager:
+            {
+            aBindingCount = sizeof(KGenericListShortcuts) / sizeof(TShortcutBinding);
+            aBindingArray = KGenericListShortcuts;
+            }
+        break;
+
+        case EContextMainGrid:
+            {
+            aBindingCount = sizeof(KMainGridShortcuts) / sizeof(TShortcutBinding);
+            aBindingArray = KMainGridShortcuts;
+            }
+        break;
+
+        case EContextSendAttachmentList:
+            {
+            aBindingCount = sizeof(KSendAttachmentListShortcuts) / sizeof(TShortcutBinding);
+            aBindingArray = KSendAttachmentListShortcuts;
+            }
+        break;
+        
+        case EContextSettings:
+            {
+            aBindingCount = sizeof(KSettingsShortcuts) / sizeof(TShortcutBinding);
+            aBindingArray = KSettingsShortcuts;
+            }
+        break;
+        
+        default:
+            {
+            Panic( EFSEmailUiUnexpectedValue );
+            }
+        break;
+        }
+    }                                         
+
+
+// ----------------------------------------------------------------------------    
+void CFSEmailUiShortcutBinding::AppendHintToCaption( TDes& aCaption, 
+                                                     TText aHint )
+    {
+    FUNC_LOG;
+    static const TInt KHintLength = 4; // e.g. " [X]"
+    _LIT( KLeadingSeparator, " [" );
+    _LIT( KTailingSeparator, "]" );
+    
+    if ( aCaption.MaxLength() >= aCaption.Length() + KHintLength )
+        {
+        aCaption.Append( KLeadingSeparator );
+        aCaption.Append( aHint );
+        aCaption.Append( KTailingSeparator );
+        }
+    }
+