Adding new test harness
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit / dali-toolkit-test-utils / toolkit-imf-manager.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://floralicense.org/license/
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 // CLASS HEADER
18 #include "toolkit-imf-manager.h"
19
20 // EXTERNAL INCLUDES
21 #include <boost/bind.hpp>
22 #include <Ecore_IMF.h>
23 #include <Ecore_X.h>
24
25 #include <dali/dali.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/integration-api/events/key-event-integ.h>
28
29 namespace Dali
30 {
31 namespace Internal
32 {
33 namespace Adaptor
34 {
35 class RenderSurface;
36
37
38 class ImfManager : public Dali::BaseObject
39 {
40 public:
41   typedef Dali::ImfManager::ImfManagerSignalV2 ImfManagerSignalV2;
42   typedef Dali::ImfManager::ImfEventSignalV2 ImfEventSignalV2;
43
44 public:
45   static Dali::ImfManager Get();
46
47   ImfManager( /* Ecore_X_Window ecoreXwin */ );
48   void ConnectCallbacks();
49   void DisconnectCallbacks();
50   void Activate();
51   void Deactivate();
52   void Reset();
53
54   Ecore_IMF_Context* GetContext();
55   bool RestoreAfterFocusLost() const;
56   void SetRestoreAferFocusLost( bool toggle );
57   void PreEditChanged( void *data, Ecore_IMF_Context *imfContext, void *event_info );
58   void CommitReceived( void *data, Ecore_IMF_Context *imfContext, void *event_info );
59   Eina_Bool RetrieveSurrounding( void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition );
60   void DeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info );
61   void NotifyCursorPosition();
62   int GetCursorPosition();
63   void SetCursorPosition( unsigned int cursorPosition );
64   void SetSurroundingText( std::string text );
65   std::string GetSurroundingText();
66
67 public:  // Signals
68   ImfManagerSignalV2& ActivatedSignal() { return mActivatedSignalV2; }
69   ImfEventSignalV2& EventReceivedSignal() { return mEventSignalV2; }
70
71 protected:
72   virtual ~ImfManager();
73
74 private:
75   void CreateContext( /*Ecore_X_Window ecoreXwin*/ );
76   void DeleteContext();
77
78 private:
79   // Undefined
80   ImfManager( const ImfManager& );
81   ImfManager& operator=( ImfManager& );
82
83 private:
84   Ecore_IMF_Context* mIMFContext;
85   int mIMFCursorPosition;
86   std::string mSurroundingText;
87   bool mRestoreAfterFocusLost:1;             ///< Whether the keyboard needs to be restored (activated ) after focus regained.
88   bool mIdleCallbackConnected:1;             ///< Whether the idle callback is already connected.
89
90   std::vector<Dali::Integration::KeyEvent> mKeyEvents; ///< Stores key events to be sent from idle call-back.
91   ImfManagerSignalV2      mActivatedSignalV2;
92   ImfEventSignalV2        mEventSignalV2;
93
94
95   static Dali::ImfManager mToolkitImfManager;
96
97 public:
98
99 inline static Internal::Adaptor::ImfManager& GetImplementation(Dali::ImfManager& imfManager)
100 {
101   Dali::ImfManager actualImfManager = ImfManager::Get();
102
103   BaseObject& handle = actualImfManager.GetBaseObject();
104   return static_cast<Internal::Adaptor::ImfManager&>(handle);
105 }
106
107 inline static const  Internal::Adaptor::ImfManager& GetImplementation(const Dali::ImfManager& imfManager)
108 {
109   Dali::ImfManager actualImfManager = ImfManager::Get();
110
111   const BaseObject& handle = imfManager.GetBaseObject();
112   return static_cast<const Internal::Adaptor::ImfManager&>(handle);
113 }
114
115 };
116
117
118 namespace
119 {
120
121 // Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
122 size_t Utf8SequenceLength(const unsigned char leadByte)
123 {
124   size_t length = 0;
125
126   if ((leadByte & 0x80) == 0 )          //ASCII character (lead bit zero)
127   {
128     length = 1;
129   }
130   else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
131   {
132     length = 2;
133   }
134   else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
135   {
136     length = 3;
137   }
138   else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
139   {
140     length = 4;
141   }
142
143   return length;
144 }
145
146 // Static function calls used by ecore 'c' style callback registration
147 void Commit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
148 {
149   if ( data )
150   {
151     ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
152     imfManager->CommitReceived( data, imfContext, event_info );
153   }
154 }
155
156 void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
157 {
158   if ( data )
159   {
160     ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
161     imfManager->PreEditChanged( data, imfContext, event_info );
162   }
163 }
164
165 Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
166 {
167   if ( data )
168   {
169     ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
170     return imfManager->RetrieveSurrounding( data, imfContext, text, cursorPosition );
171   }
172   else
173   {
174     return false;
175   }
176 }
177
178 /**
179  * Called when an IMF delete surrounding event is received.
180  * Here we tell the application that it should delete a certain range.
181  */
182 void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
183 {
184   if ( data )
185   {
186     ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
187     imfManager->DeleteSurrounding( data, imfContext, event_info );
188   }
189 }
190
191 } // unnamed namespace
192
193 Dali::ImfManager Dali::Internal::Adaptor::ImfManager::mToolkitImfManager;
194
195
196 Dali::ImfManager ImfManager::Get()
197 {
198   Dali::ImfManager manager;
199
200   if( ! mToolkitImfManager )
201   {
202     mToolkitImfManager = Dali::ImfManager( new Dali::Internal::Adaptor::ImfManager() );
203   }
204   return mToolkitImfManager;
205 }
206
207 ImfManager::ImfManager( /*Ecore_X_Window ecoreXwin*/ )
208 : mIMFContext(),
209   mIMFCursorPosition( 0 ),
210   mSurroundingText(""),
211   mRestoreAfterFocusLost( false ),
212   mIdleCallbackConnected( false ),
213   mKeyEvents()
214 {
215   //ecore_imf_init();
216   CreateContext( /*ecoreXwin*/ );
217   ConnectCallbacks();
218   //VirtualKeyboard::ConnectCallbacks( mIMFContext );
219 }
220
221 ImfManager::~ImfManager()
222 {
223   //VirtualKeyboard::DisconnectCallbacks( mIMFContext );
224   DisconnectCallbacks();
225   DeleteContext();
226   //ecore_imf_shutdown();
227 }
228
229 void ImfManager::CreateContext( /*Ecore_X_Window ecoreXwin*/ )
230 {
231 }
232
233 void ImfManager::DeleteContext()
234 {
235 }
236
237 // Callbacks for predicitive text support.
238 void ImfManager::ConnectCallbacks()
239 {
240   //if ( mIMFContext )  {
241   //ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,    PreEdit,    this );
242   //ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,             Commit,     this );
243   //ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this );
244   //}
245 }
246
247 void ImfManager::DisconnectCallbacks()
248 {
249   // if ( mIMFContext )
250   // {
251   //   ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,    PreEdit );
252   //   ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,             Commit );
253   //   ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding );
254   // }
255 }
256
257 void ImfManager::Activate()
258 {
259   // // Reset mIdleCallbackConnected
260   // mIdleCallbackConnected = false;
261
262   // if ( mIMFContext )
263   // {
264   //   ecore_imf_context_focus_in( mIMFContext );
265   //   // emit keyboard activated signal
266   //   Dali::ImfManager handle( this );
267   //   mActivatedSignalV2.Emit( handle );
268   // }
269 }
270
271 void ImfManager::Deactivate()
272 {
273   // if( mIMFContext )
274   // {
275   //   Reset();
276   //   ecore_imf_context_focus_out( mIMFContext );
277   // }
278   // // Reset mIdleCallbackConnected
279   // mIdleCallbackConnected = false;
280 }
281
282 void ImfManager::Reset()
283 {
284   // if ( mIMFContext )
285   // {
286   //   ecore_imf_context_reset( mIMFContext );
287   // }
288 }
289
290 Ecore_IMF_Context* ImfManager::GetContext()
291 {
292   //return mIMFContext;
293   return NULL;
294 }
295
296 bool ImfManager::RestoreAfterFocusLost() const
297 {
298   return mRestoreAfterFocusLost;
299 }
300
301 void ImfManager::SetRestoreAferFocusLost( bool toggle )
302 {
303   mRestoreAfterFocusLost = toggle;
304 }
305
306 void ImfManager::PreEditChanged( void *, Ecore_IMF_Context *imfContext, void *event_info )
307 {
308   // char *preEditString( NULL );
309   // int cursorPosition( 0 );
310   // Eina_List *attrs = NULL;
311   // Eina_List *l = NULL;
312
313   // Ecore_IMF_Preedit_Attr *attr;
314
315   // // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
316   // // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
317   // ecore_imf_context_preedit_string_with_attributes_get( imfContext, &preEditString, &attrs, &cursorPosition );
318   // if ( attrs )
319   // {
320   //   // iterate through the list of attributes getting the type, start and end position.
321   //   for ( l = attrs, (attr =  (Ecore_IMF_Preedit_Attr*)eina_list_data_get(l) ); l; l = eina_list_next(l), ( attr = (Ecore_IMF_Preedit_Attr*)eina_list_data_get(l) ))
322   //   {
323   //     if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB4 ) // (Ecore_IMF)
324   //     {
325   //       // check first byte so know how many bytes a character is represented by as keyboard returns cursor position in bytes. Which is different for some languages.
326   //       size_t visualCharacterIndex = 0;
327   //       size_t byteIndex = 0;
328   //       // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
329   //       while ( preEditString[byteIndex] != '\0' )
330   //       {
331   //         // attr->end_index is provided as a byte position not character and we need to know the character position.
332   //         size_t currentSequenceLength = Utf8SequenceLength(preEditString[byteIndex]); // returns number of bytes used to represent character.
333   //         if ( byteIndex == attr->end_index )
334   //         {
335   //           cursorPosition = visualCharacterIndex;
336   //           break;
337   //           // end loop as found cursor position that matches byte position
338   //         }
339   //         else
340   //         {
341   //           byteIndex += currentSequenceLength; // jump to next character
342   //           visualCharacterIndex++;  // increment character count so we know our position for when we get a match
343   //         }
344   //         DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
345   //       }
346   //     }
347   //   }
348   // }
349   // if ( Dali::Adaptor::IsAvailable() )
350   // {
351   //   std::string keyString ( preEditString );
352   //   int numberOfChars( 0 );
353   //   Dali::ImfManager handle( this );
354   //   Dali::ImfManager::ImfEventData imfEventData ( Dali::ImfManager::PREEDIT, keyString, cursorPosition, numberOfChars );
355   //   Dali::ImfManager::ImfCallbackData callbackData = mEventSignalV2.Emit( handle, imfEventData );
356   //   if ( callbackData.update )
357   //   {
358   //     SetCursorPosition( callbackData.cursorPosition );
359   //     SetSurroundingText( callbackData.currentText );
360   //     NotifyCursorPosition();
361   //   }
362   //   if ( callbackData.preeditResetRequired )
363   //   {
364   //     Reset();
365   //   }
366   // }
367   // free( preEditString );
368 }
369
370 void ImfManager::CommitReceived( void *, Ecore_IMF_Context *imfContext, void *event_info )
371 {
372   // if ( Dali::Adaptor::IsAvailable() )
373   // {
374   //   const std::string keyString( (char *)event_info );
375   //   const int cursorOffset( 0 );
376   //   const int numberOfChars( 0 );
377
378   //   Dali::ImfManager handle( this );
379   //   Dali::ImfManager::ImfEventData imfEventData ( Dali::ImfManager::COMMIT, keyString, cursorOffset, numberOfChars );
380   //   Dali::ImfManager::ImfCallbackData callbackData = mEventSignalV2.Emit( handle, imfEventData );
381
382   //   if ( callbackData.update )
383   //   {
384   //     SetCursorPosition( callbackData.cursorPosition );
385   //     SetSurroundingText( callbackData.currentText );
386
387   //     NotifyCursorPosition();
388   //   }
389   // }
390 }
391
392 /**
393  * Called when an IMF retrieve surround event is received.
394  * Here the IMF module wishes to know the string we are working with and where within the string the cursor is
395  * We need to signal the application to tell us this information.
396  */
397 Eina_Bool ImfManager::RetrieveSurrounding( void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
398 {
399   // std::string keyString ( "" );
400   // int cursorOffset( 0 );
401   // int numberOfChars( 0 );
402   // Dali::ImfManager::ImfEventData imfData ( Dali::ImfManager::GETSURROUNDING , keyString, cursorOffset, numberOfChars );
403   // Dali::ImfManager handle( this );
404   // mEventSignalV2.Emit( handle, imfData );
405   // if ( text )
406   // {
407   //   std::string surroundingText( GetSurroundingText() );
408   //   if ( !surroundingText.empty() )
409   //   {
410   //     *text = strdup( surroundingText.c_str() );
411   //   }
412   //   else
413   //   {
414   //     *text = strdup( "" );
415   //   }
416   // }
417   // if ( cursorPosition )
418   // {
419   //   *cursorPosition = GetCursorPosition();
420   // }
421   return EINA_TRUE;
422 }
423
424 /**
425  * Called when an IMF delete surrounding event is received.
426  * Here we tell the application that it should delete a certain range.
427  */
428 void ImfManager::DeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
429 {
430   // if ( Dali::Adaptor::IsAvailable() )
431   // {
432   //   Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = (Ecore_IMF_Event_Delete_Surrounding*) event_info;
433   //   const std::string keyString( "" );
434   //   const int cursorOffset( deleteSurroundingEvent->offset );
435   //   const int numberOfChars( deleteSurroundingEvent->n_chars );
436   //   Dali::ImfManager::ImfEventData imfData ( Dali::ImfManager::DELETESURROUNDING , keyString, cursorOffset, numberOfChars );
437   //   Dali::ImfManager handle( this );
438   //   mEventSignalV2.Emit( handle, imfData );
439   // }
440 }
441
442 void ImfManager::NotifyCursorPosition()
443 {
444   // if ( mIMFContext )
445   // {
446   //   ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
447   // }
448 }
449
450 int ImfManager::GetCursorPosition()
451 {
452   return mIMFCursorPosition;
453 }
454
455 void ImfManager::SetCursorPosition( unsigned int cursorPosition )
456 {
457   mIMFCursorPosition = ( int )cursorPosition;
458 }
459
460 void ImfManager::SetSurroundingText( std::string text )
461 {
462   mSurroundingText = text;
463 }
464
465 std::string ImfManager::GetSurroundingText()
466 {
467   return mSurroundingText;
468 }
469
470 } // Adaptor
471
472 } // Internal
473
474
475 /********************************************************************************/
476 /*********************************  PUBLIC CLASS  *******************************/
477 /********************************************************************************/
478
479 ImfManager::ImfManager()
480 {
481 }
482
483 ImfManager::~ImfManager()
484 {
485 }
486
487 ImfManager ImfManager::Get()
488 {
489   return Internal::Adaptor::ImfManager::Get();
490 }
491
492 ImfContext ImfManager::GetContext()
493 {
494   return reinterpret_cast<ImfContext>( Internal::Adaptor::ImfManager::GetImplementation(*this).GetContext() );
495 }
496
497 void ImfManager::Activate()
498 {
499   Internal::Adaptor::ImfManager::GetImplementation(*this).Activate();
500 }
501
502 void ImfManager::Deactivate()
503 {
504   Internal::Adaptor::ImfManager::GetImplementation(*this).Deactivate();
505 }
506
507 bool ImfManager::RestoreAfterFocusLost() const
508 {
509   return Internal::Adaptor::ImfManager::GetImplementation(*this).RestoreAfterFocusLost();
510 }
511
512 void ImfManager::SetRestoreAferFocusLost( bool toggle )
513 {
514   Internal::Adaptor::ImfManager::GetImplementation(*this).SetRestoreAferFocusLost( toggle );
515 }
516
517 void ImfManager::Reset()
518 {
519   Internal::Adaptor::ImfManager::GetImplementation(*this).Reset();
520 }
521
522 void ImfManager::NotifyCursorPosition()
523 {
524   Internal::Adaptor::ImfManager::GetImplementation(*this).NotifyCursorPosition();
525 }
526
527 void ImfManager::SetCursorPosition( unsigned int SetCursorPosition )
528 {
529   Internal::Adaptor::ImfManager::GetImplementation(*this).SetCursorPosition( SetCursorPosition );
530 }
531
532 int ImfManager::GetCursorPosition()
533 {
534   return Internal::Adaptor::ImfManager::GetImplementation(*this).GetCursorPosition();
535 }
536
537 void ImfManager::SetSurroundingText( std::string text )
538 {
539   Internal::Adaptor::ImfManager::GetImplementation(*this).SetSurroundingText( text );
540 }
541
542 std::string ImfManager::GetSurroundingText()
543 {
544   return Internal::Adaptor::ImfManager::GetImplementation(*this).GetSurroundingText();
545 }
546
547 ImfManager::ImfManagerSignalV2& ImfManager::ActivatedSignal()
548 {
549   return Internal::Adaptor::ImfManager::GetImplementation(*this).ActivatedSignal();
550 }
551
552 ImfManager::ImfEventSignalV2& ImfManager::EventReceivedSignal()
553 {
554   return Internal::Adaptor::ImfManager::GetImplementation(*this).EventReceivedSignal();
555 }
556
557 ImfManager::ImfManager(Internal::Adaptor::ImfManager *impl)
558   : BaseHandle(impl)
559 {
560 }
561
562 } // namespace Dali