Index: AUTHORS
===================================================================
--- AUTHORS	(revision 1188197)
+++ AUTHORS	(working copy)
@@ -29,6 +29,8 @@
 Martin Koller <kollix@aon.at>
 Scanning Support
 
+Tasuku Suzuki <stasuku@gmail.com>
+InputMethod Support
 
 Thanks To
 =========
Index: kolourpaint.cpp
===================================================================
--- kolourpaint.cpp	(revision 1188197)
+++ kolourpaint.cpp	(working copy)
@@ -76,6 +76,7 @@
     // TODO: missing a lot of people who helped with the KDE 4 port.
     aboutData.addAuthor (ki18n ("Martin Koller"), ki18n ("Scanning Support"), "m.koller@surfeu.at");
 
+    aboutData.addAuthor (ki18n ("Tasuku Suzuki"), ki18n ("InputMethod Support"), "stasuku@gmail.com");
 
     aboutData.addCredit (ki18n ("Thanks to the many others who have helped to make this program possible."));
 
Index: tools/selection/text/kpToolText.h
===================================================================
--- tools/selection/text/kpToolText.h	(revision 1188197)
+++ tools/selection/text/kpToolText.h	(working copy)
@@ -714,8 +714,7 @@
 //
 
 protected:
-    // COMPAT: Need to update InputMethod support.
-    // virtual void inputMethodEvent (QInputMethodEvent *e);
+    virtual void inputMethodEvent (QInputMethodEvent *e);
 
 
 private:
Index: tools/selection/text/kpToolText_InputMethodEvents.cpp
===================================================================
--- tools/selection/text/kpToolText_InputMethodEvents.cpp	(revision 1188197)
+++ tools/selection/text/kpToolText_InputMethodEvents.cpp	(working copy)
@@ -2,6 +2,7 @@
 /*
    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
    Copyright (c) 2005 Kazuki Ohta <mover@hct.zaq.ne.jp>
+   Copyright (c) 2010 Tasuku Suzuki <stasuku@gmail.com>
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -52,22 +53,15 @@
 #include <kpView.h>
 #include <kpViewManager.h>
 
-
-// COMPAT: Need to update InputMethod support.
-//
-// This code needs lots of updating not just to Qt/KDE4 but also to changes
-// in KolourPaint internals.
-#if 0
-
-void kpToolText::imStartEvent (QIMEvent *e)
+void kpToolText::inputMethodEvent (QInputMethodEvent *e)
 {
 #if DEBUG_KP_TOOL_TEXT && 1
-    kDebug () << "kpToolText::imStartEvent() text='" << e->text ()
-               << " cursorPos=" << e->cursorPos ()
-               << " selectionLength=" << e->selectionLength ()
+    kDebug () << "kpToolText::inputMethodEvent() preeditString='" << e->preeditString ()
+               << "commitString = " << e->commitString ()
+               << " replacementStart=" << e->replacementStart ()
+               << " replacementLength=" << e->replacementLength ()
                << endl;
 #endif
-
     kpTextSelection *textSel = document ()->textSelection ();
     if (hasBegunDraw() || !textSel)
     {
@@ -75,137 +69,30 @@
         return;
     }
 
-    d->IMStartCursorRow = viewManager ()->textCursorRow ();
-    d->IMStartCursorCol = viewManager ()->textCursorCol ();
-    d->IMPreeditStr.clear ();
-}
+    kpPreeditText previous = textSel->preeditText ();
+    kpPreeditText next (e);
 
-void kpToolText::imComposeEvent (QIMEvent *e)
-{
-#if DEBUG_KP_TOOL_TEXT && 1
-    kDebug () << "kpToolText::imComposeEvent() text='" << e->text ()
-               << " cursorPos=" << e->cursorPos ()
-               << " selectionLength=" << e->selectionLength ()
-               << endl;
-#endif
-
-    kpTextSelection *textSel = document ()->textSelection ();
-    if (hasBegunDraw() || !textSel)
-    {
-        e->ignore();
-        return;
-    }
-
-    // remove old preedit
-    if (d->IMPreeditStr.length() > 0 )
-    {
-        // set cursor at the start input point
-        viewManager ()->setTextCursorPosition (d->IMStartCursorRow, d->IMStartCursorCol);
-        for (unsigned int i = 0; i < d->IMPreeditStr.length(); i++)
-        {
-            if (!d->deleteCommand)
-            {
-                if (hasBegunShape ())
-                    endShape (currentPoint (), normalizedRect ());
-
-                d->deleteCommand = new kpToolTextDeleteCommand (i18n ("Text: Delete"),
-                    viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
-                    kpToolTextDeleteCommand::AddDeleteNow,
-                    environ ()->commandEnvironment ());
-                commandHistory ()->addCommand (d->deleteCommand, false/*no exec*/);
-            }
-            else
-                d->deleteCommand->addDelete ();
+    int textCursorRow = viewManager ()->textCursorRow ();
+    int textCursorCol = viewManager ()->textCursorCol ();
+    if (!next.isEmpty ()) {
+        if (previous.position().x () < 0 && previous.position().y () < 0) {
+            next.setPosition (QPoint(textCursorCol, textCursorRow));
+        } else {
+            next.setPosition(previous.position ());
         }
     }
+    textSel->setPreeditText (next);
+    textCursorCol = textCursorCol - previous.cursorPosition () + next.cursorPosition ();
+    viewManager ()->setTextCursorPosition (textCursorRow, textCursorCol);
 
-    // insert new preedit
-    d->IMPreeditStr = e->text();
-    if (d->IMPreeditStr.length() > 0)
-    {
+    QString commitString = e->commitString ();
+    if (!commitString.isNull ()) {
+        // commit string
         if (!d->insertCommand)
-        {
-            if (hasBegunShape ())
-                endShape (currentPoint (), normalizedRect ());
+            addNewInsertCommand (&d->insertCommand);
 
-            d->insertCommand = new kpToolTextInsertCommand (i18n ("Text: Write"),
-                                                           viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
-                                                           d->IMPreeditStr,
-                                                           environ ()->commandEnvironment ());
-            commandHistory ()->addCommand (d->insertCommand, false/*no exec*/);
-        }
-        else
-            d->insertCommand->addText (d->IMPreeditStr);
+        d->insertCommand->addText (commitString);
     }
-
-    // set cursor pos
-    if (d->IMStartCursorRow >= 0)
-    {
-        int row = d->IMStartCursorRow;
-        int col = d->IMStartCursorCol + e->cursorPos () /* + e->selectionLength()*/;
-        viewManager ()->setTextCursorPosition (row, col, true /* update MicroFocusHint */);
-    }
+    textSel = document ()->textSelection ();
+    e->accept ();
 }
-
-void kpToolText::imEndEvent (QIMEvent *e)
-{
-#if DEBUG_KP_TOOL_TEXT && 1
-    kDebug () << "kpToolText::imEndEvent() text='" << e->text ()
-               << " cursorPos=" << e->cursorPos ()
-               << " selectionLength=" << e->selectionLength ()
-               << endl;
-#endif
-
-    kpTextSelection *textSel = document ()->textSelection ();
-    if (hasBegunDraw() || !textSel)
-    {
-        e->ignore();
-        return;
-    }
-
-    // remove old preedit
-    if (d->IMPreeditStr.length() > 0 )
-    {
-        // set cursor at the start input point
-        viewManager ()->setTextCursorPosition (d->IMStartCursorRow, d->IMStartCursorCol);
-        for (unsigned int i = 0; i < d->IMPreeditStr.length(); i++)
-        {
-            if (!d->deleteCommand)
-            {
-                if (hasBegunShape ())
-                    endShape (currentPoint (), normalizedRect ());
-
-                d->deleteCommand = new kpToolTextDeleteCommand (i18n ("Text: Delete"),
-                    viewManager ()->textCursorRow (),
-                    viewManager ()->textCursorCol (),
-                    kpToolTextDeleteCommand::AddDeleteNow,
-                    environ ()->commandEnvironment ());
-                commandHistory ()->addCommand (d->deleteCommand, false/*no exec*/);
-            }
-            else
-                d->deleteCommand->addDelete ();
-        }
-    }
-    d->IMPreeditStr.clear ();
-
-    // commit string
-    QString inputStr = e->text();
-    if (inputStr.length() > 0)
-    {
-        if (!d->insertCommand)
-        {
-            if (hasBegunShape ())
-                endShape (currentPoint (), normalizedRect ());
-
-            d->insertCommand = new kpToolTextInsertCommand (i18n ("Text: Write"),
-                                                           viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
-                                                           inputStr,
-                                                           environ ()->commandEnvironment ());
-            commandHistory ()->addCommand (d->insertCommand, false/*no exec*/);
-        }
-        else
-            d->insertCommand->addText (inputStr);
-    }
-}
-
-#endif  // COMPAT
Index: tools/selection/text/kpToolText.cpp
===================================================================
--- tools/selection/text/kpToolText.cpp	(revision 1188197)
+++ tools/selection/text/kpToolText.cpp	(working copy)
@@ -62,12 +62,6 @@
                        environ, parent, "tool_text"),
       d (new kpToolTextPrivate ())
 {
-// COMPAT: Need to update InputMethod support.
-#if 0
-    d->isIMStarted = false;
-    d->IMStartCursorRow = 0;
-    d->IMStartCursorCol = 0;
-#endif
 }
 
 kpToolText::~kpToolText ()
@@ -126,6 +120,7 @@
     // setSelectionBorderForHaventBegunDraw().  We leave this in for
     // consistency with end().
     viewManager ()->setTextCursorEnabled (true);
+    viewManager()->setInputMethodEnabled (true);
 
     endTypingCommands ();
 
@@ -141,6 +136,7 @@
 
     kpAbstractSelectionTool::end ();
 
+    viewManager()->setInputMethodEnabled (false);
     viewManager ()->setTextCursorEnabled (false);
     environ ()->enableTextToolBarActions (false);
 }
Index: tools/selection/text/kpToolTextPrivate.h
===================================================================
--- tools/selection/text/kpToolTextPrivate.h	(revision 1188197)
+++ tools/selection/text/kpToolTextPrivate.h	(working copy)
@@ -45,14 +45,6 @@
     kpToolTextEnterCommand *enterCommand;
     kpToolTextBackspaceCommand *backspaceCommand, *backspaceWordCommand;
     kpToolTextDeleteCommand *deleteCommand, *deleteWordCommand;
-
-// COMPAT: Need to update InputMethod support.
-#if 0
-    bool isIMStarted;
-    int IMStartCursorRow;
-    int IMStartCursorCol;
-    QString IMPreeditStr;
-#endif
 };
 
 
Index: tools/kpTool.h
===================================================================
--- tools/kpTool.h	(revision 1188197)
+++ tools/kpTool.h	(working copy)
@@ -370,8 +370,7 @@
     virtual void keyPressEvent (QKeyEvent *e);
     virtual void keyReleaseEvent (QKeyEvent *e);
 
-    // COMPAT: Need to update InputMethod support.
-    // virtual void inputMethodEvent (QInputMethodEvent *) {}
+    virtual void inputMethodEvent (QInputMethodEvent *e) {}
 
 private:
     void keyUpdateModifierState (QKeyEvent *e);
Index: COPYING
===================================================================
--- COPYING	(revision 1188197)
+++ COPYING	(working copy)
@@ -3,6 +3,7 @@
 Portions Copyright (c) 2006-2007 Mike Gashler <gashlerm@yahoo.com>
 Portions Copyright (c) 2007 Martin Koller <m.koller@surfeu.at>
 Portions Copyright (c) 2007 John Layt <john@layt.net>
+Portions Copyright (c) 2010 Tasuku Suzuki <stasuku@gmail.com>
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt	(revision 1188197)
+++ CMakeLists.txt	(working copy)
@@ -209,6 +209,7 @@
 ${CMAKE_CURRENT_SOURCE_DIR}/layers/selections/text/kpTextSelection_Cursor.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/layers/selections/text/kpTextSelection_Paint.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/layers/selections/text/kpTextStyle.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/layers/selections/text/kpPreeditText.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/layers/tempImage/kpTempImage.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/mainWindow/kpMainWindow_Colors.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/mainWindow/kpMainWindow.cpp
@@ -440,6 +441,7 @@
 ${CMAKE_CURRENT_SOURCE_DIR}/layers/selections/text/kpTextSelection_Cursor.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/layers/selections/text/kpTextSelection_Paint.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/layers/selections/text/kpTextStyle.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/layers/selections/text/kpPreeditText.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/layers/tempImage/kpTempImage.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/mainWindow/kpMainWindow_Colors.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/mainWindow/kpMainWindow.cpp
Index: views/kpView.cpp
===================================================================
--- views/kpView.cpp	(revision 1188197)
+++ views/kpView.cpp	(working copy)
@@ -2,6 +2,7 @@
 /*
    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
    Copyright (c) 2005 Kazuki Ohta <mover@hct.zaq.ne.jp>
+   Copyright (c) 2010 Tasuku Suzuki <stasuku@gmail.com>
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -110,9 +111,6 @@
     setFocusPolicy (Qt::WheelFocus);
     setMouseTracking (true);  // mouseMoveEvent's even when no mousebtn down
     setAttribute (Qt::WA_KeyCompression, true);
-
-    // COMPAT: Need to update InputMethod support.
-    //setAttribute (Qt::WA_InputMethodEnabled, true);  // ensure using InputMethod
 }
 
 kpView::~kpView ()
@@ -617,23 +615,7 @@
     invalidateQueuedArea ();
 }
 
-// COMPAT: Need to update InputMethod support.
-#if 0
 // public
-void kpView::updateMicroFocusHint (const QRect &microFocusHint)
-{
-    int x = microFocusHint.topLeft().x();
-    int y = microFocusHint.topLeft().y();
-    int width = microFocusHint.width();
-    int height = microFocusHint.height();
-
-    (void) x; (void) y; (void) width; (void) height;
-    setMicroFocusHint (x, y, width, height);
-}
-#endif
-
-
-// public
 QPoint kpView::mouseViewPoint (const QPoint &returnViewPoint) const
 {
     if (returnViewPoint != KP_INVALID_POINT)
@@ -646,6 +628,33 @@
     }
 }
 
+// public virtual
+QVariant kpView::inputMethodQuery (Qt::InputMethodQuery query) const
+{
+#if DEBUG_KP_VIEW && 1
+    kDebug () << "kpView(" << objectName () << ")::inputMethodQuery()";
+#endif
+    QVariant ret;
+    switch (query) {
+    case Qt::ImMicroFocus:
+    {
+        QRect r = d->viewManager->textCursorRect ();
+        r.setTopLeft (r.topLeft () + origin ());
+        r.setHeight (r.height() + 2);
+        r = transformDocToView (r);
+        ret = r;
+        break;
+    }
+    case Qt::ImFont:
+        if (textSelection ()) {
+            ret = textSelection ()->textStyle ().font ();
+        }
+        break;
+    default:
+        break;
+    }
+    return ret;
+}
 
 #include <kpView.moc>
 
Index: views/kpView.h
===================================================================
--- views/kpView.h	(revision 1188197)
+++ views/kpView.h	(working copy)
@@ -396,10 +396,8 @@
      */
     void updateQueuedArea ();
 
-    // COMPAT: Need to update InputMethod support.
-    //void updateMicroFocusHint (const QRect &microFocusHint);
+    QVariant inputMethodQuery (Qt::InputMethodQuery query) const;
 
-
 public slots:
     /**
      * Call this when the "environment" (e.g. document size) changes.  The
@@ -515,14 +513,9 @@
     virtual void keyPressEvent (QKeyEvent *e);
     virtual void keyReleaseEvent (QKeyEvent *e);
 
-
 protected:
-    // COMPAT: Need to update InputMethod Support
-    // virtual void imStartEvent (QIMEvent *e);
-    // virtual void imComposeEvent (QIMEvent *e);
-    // virtual void imEndEvent (QIMEvent *e);
+    virtual void inputMethodEvent (QInputMethodEvent *e);
 
-
 protected:
     virtual bool event (QEvent *e);
 
Index: views/kpView_Events.cpp
===================================================================
--- views/kpView_Events.cpp	(revision 1188197)
+++ views/kpView_Events.cpp	(working copy)
@@ -2,6 +2,7 @@
 /*
    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
    Copyright (c) 2005 Kazuki Ohta <mover@hct.zaq.ne.jp>
+   Copyright (c) 2010 Tasuku Suzuki <stasuku@gmail.com>
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -34,6 +35,10 @@
 #include <kpView.h>
 #include <kpViewPrivate.h>
 
+#if DEBUG_KP_VIEW
+#include <KDebug>
+#endif
+
 #include <QKeyEvent>
 #include <QMouseEvent>
 
@@ -130,48 +135,18 @@
 }
 
 
-// COMPAT: Need to update InputMethod support.
-#if 0
-
-// private virtual
-void kpView::imStartEvent (QIMEvent *e)
+// protected virtual [base QWidget]
+void kpView::inputMethodEvent (QInputMethodEvent *e)
 {
 #if DEBUG_KP_VIEW && 1
-    kDebug () << "kpView(" << objectName () << ")::imStartEvent";
+    kDebug () << "kpView(" << objectName () << ")::inputMethodEvent()";
 #endif
 
     if (tool ())
-        tool ()->imStartEvent (e);
+        tool ()->inputMethodEvent (e);
     e->accept ();
 }
 
-// private virtual
-void kpView::imComposeEvent (QIMEvent *e)
-{
-#if DEBUG_KP_VIEW && 1
-    kDebug () << "kpView(" << objectName () << ")::imComposeEvent";
-#endif
-
-    if (tool ())
-        tool ()->imComposeEvent (e);
-    e->accept ();
-}
-
-// private virtual
-void kpView::imEndEvent (QIMEvent *e)
-{
-#if DEBUG_KP_VIEW && 1
-    kDebug () << "kpView(" << objectName () << ")::imEndEvent";
-#endif
-
-    if (tool ())
-        tool ()->imEndEvent (e);
-    e->accept ();
-}
-
-#endif  // COMPAT
-
-
 // protected virtual [base QWidget]
 bool kpView::event (QEvent *e)
 {
Index: views/manager/kpViewManager.cpp
===================================================================
--- views/manager/kpViewManager.cpp	(revision 1188197)
+++ views/manager/kpViewManager.cpp	(working copy)
@@ -74,6 +74,8 @@
 
 
     d->queueUpdatesCounter = d->fastUpdatesCounter = 0;
+
+    d->inputMethodEnabled = false;
 }
 
 kpViewManager::~kpViewManager ()
@@ -155,8 +157,8 @@
 {
 #if DEBUG_KP_VIEW_MANAGER && 1
     kDebug () << "kpViewManager::setViewUnderCursor ("
-               << (view ? view->name () : "(none)") << ")"
-               << "  old=" << (d->viewUnderCursor ? d->viewUnderCursor->name () : "(none)")
+               << (view ? view->objectName () : "(none)") << ")"
+               << "  old=" << (d->viewUnderCursor ? d->viewUnderCursor->objectName () : "(none)")
                << endl;
 #endif
     if (view == d->viewUnderCursor)
@@ -164,6 +166,9 @@
 
     d->viewUnderCursor = view;
 
+    if (d->viewUnderCursor)
+        d->viewUnderCursor->setAttribute (Qt::WA_InputMethodEnabled, d->inputMethodEnabled);
+
     if (!d->viewUnderCursor)
     {
         // Hide the brush if the mouse cursor just left the view.
@@ -243,7 +248,7 @@
     kDebug () << "kpViewManager::setTempImage(isBrush="
                << tempImage.isBrush ()
                << ",topLeft=" << tempImage.topLeft ()
-               << ",pixmap.rect=" << tempImage.pixmap ().rect ()
+               << ",image.rect=" << tempImage.image ().rect ()
                << ")" << endl;
 #endif
 
@@ -319,5 +324,12 @@
         updateViews (document ()->selection ()->boundingRect ());
 }
 
+void kpViewManager::setInputMethodEnabled (bool inputMethodEnabled)
+{
+    d->inputMethodEnabled = inputMethodEnabled;
+    if (d->viewUnderCursor) {
+        d->viewUnderCursor->setAttribute (Qt::WA_InputMethodEnabled, inputMethodEnabled);
+    }
+}
 
 #include <kpViewManager.moc>
Index: views/manager/kpViewManagerPrivate.h
===================================================================
--- views/manager/kpViewManagerPrivate.h	(revision 1188197)
+++ views/manager/kpViewManagerPrivate.h	(working copy)
@@ -74,6 +74,12 @@
     //
 
     int queueUpdatesCounter, fastUpdatesCounter;
+
+    //
+    // Input Method
+    //
+
+    bool inputMethodEnabled;
 };
 
 
Index: views/manager/kpViewManager_TextCursor.cpp
===================================================================
--- views/manager/kpViewManager_TextCursor.cpp	(revision 1188197)
+++ views/manager/kpViewManager_TextCursor.cpp	(working copy)
@@ -18,6 +18,7 @@
 /*
    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
    Copyright (c) 2005 Kazuki Ohta <mover@hct.zaq.ne.jp>
+   Copyright (c) 2010 Tasuku Suzuki <stasuku@gmail.com>
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -52,6 +53,7 @@
 #include <qapplication.h>
 #include <qlist.h>
 #include <qtimer.h>
+#include <QInputContext>
 
 #include <kdebug.h>
 
@@ -138,7 +140,7 @@
 }
 
 // public
-void kpViewManager::setTextCursorPosition (int row, int col, bool isUpdateMicroFocusHint)
+void kpViewManager::setTextCursorPosition (int row, int col)
 {
     if (row == d->textCursorRow && col == d->textCursorCol)
         return;
@@ -160,34 +162,12 @@
     restoreQueueUpdates ();
     restoreFastUpdates ();
 
-// COMPAT: Need to update InputMethod support.
-#if 1
-    (void) isUpdateMicroFocusHint;
-#else
-    if (isUpdateMicroFocusHint)
-    {
-        const QRect r = textCursorRect ();
-        if (!r.isValid ())
-            return;
-
-        if (!d->viewUnderCursor)
-            return;
-
-        // TODO: I think you need to consider zooming e.g. try editing
-        //       text at 800% or with focus set to the thumbnail.
-        //       kpSelection/kpDocument works fully in unzoomed
-        //       coordinates unlike the view (which is zoomed and can
-        //       change size).
-        //
-        //       To fix it here, I think you should call
-        //       m_viewUnderCursor->transformDocToView(QRect).  However,
-        //       the rest of the InputMethod support still needs to
-        //       audited for this.
-        //
-        //       [Bug #27]
-        d->viewUnderCursor->updateMicroFocusHint (r);
+    if (d->viewUnderCursor) {
+        QInputContext *inputContext = d->viewUnderCursor->inputContext ();
+        if (inputContext) {
+            inputContext->update ();
+        }
     }
-#endif
 }
 
 
Index: views/manager/kpViewManager.h
===================================================================
--- views/manager/kpViewManager.h	(revision 1188197)
+++ views/manager/kpViewManager.h	(working copy)
@@ -166,8 +166,7 @@
     //          Always ensure that the text cursor position is valid.
     //          TODO: We need to check this in all source files.
     //                e.g. It's definitely wrong for kpToolTextBackspaceCommand.
-    void setTextCursorPosition (int row, int col,
-        bool isUpdateMicroFocusHint = false);
+    void setTextCursorPosition (int row, int col);
 
     // Returns the document rectangle where cursor would be placed, using
     // textCursorRow() and textCursorCol ().
@@ -246,6 +245,8 @@
 public slots:
     void adjustViewsToEnvironment ();
 
+public slots:
+    void setInputMethodEnabled (bool inputMethodEnabled);
 
 private:
     struct kpViewManagerPrivate * const d;
Index: layers/selections/text/kpTextSelection_Paint.cpp
===================================================================
--- layers/selections/text/kpTextSelection_Paint.cpp	(revision 1188197)
+++ layers/selections/text/kpTextSelection_Paint.cpp	(working copy)
@@ -3,6 +3,7 @@
 
 /*
    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
+   Copyright (c) 2010 Tasuku Suzuki <stasuku@gmail.com>
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -38,11 +39,13 @@
 #include <QFont>
 #include <QList>
 #include <QPainter>
+#include <QTextCharFormat>
 
 #include <KDebug>
 
 #include <kpPixmapFX.h>
 #include <kpTextStyle.h>
+#include <kpPreeditText.h>
 
 
 static void DebugAlpha (const QPixmap &pm)
@@ -63,8 +66,63 @@
 
     QList <QString> textLines;
     kpTextStyle textStyle;
+    kpPreeditText preeditText;
 };
 
+static void DrawPreeditString (QPainter *p, int &x, int y, const kpPreeditText &preeditText)
+{
+    int i = 0;
+    QString preeditString = preeditText.preeditString ();
+    QString str;
+    foreach (const QInputMethodEvent::Attribute &attr, preeditText.textFormatList ())
+    {
+        int start = attr.start;
+        int length = attr.length;
+        QTextCharFormat format = qvariant_cast<QTextFormat> (attr.value).toCharFormat ();
+
+        if (i > start) {
+            length = length - i + start;
+            start = i;
+        }
+        if (length <= 0) continue;
+
+        if (i < start) {
+            str = preeditString.mid (i, start - i);
+            p->drawText (x, y, str);
+            x += p->fontMetrics ().width (str);
+        }
+
+        p->save();
+        str = preeditString.mid (start, length);
+        int width = p->fontMetrics().width (str);
+        if (format.background ().color () != Qt::black) {
+            p->save ();
+            p->setPen (format.background ().color ());
+            p->setBrush (format.background());
+            p->drawRect (x, y - p->fontMetrics ().ascent (), width, p->fontMetrics ().height ());
+            p->restore ();
+        }
+        if (format.foreground ().color () != Qt::black) {
+            p->setBrush (format.foreground ());
+            p->setPen (format.foreground ().color ());
+        }
+        if (format.underlineStyle ()) {
+            p->drawLine (x, y + p->fontMetrics ().descent (), x + width, y + p->fontMetrics ().descent ());
+        }
+        p->drawText (x, y, str);
+
+        x += width;
+        p->restore ();
+
+        i = start + length;
+    }
+    if (i < preeditString.length ()) {
+        str = preeditString.mid (i);
+        p->drawText (x, y, str);
+        x += p->fontMetrics ().width (str);
+    }
+}
+
 // TODO: QPainter::drawText() draws the same text with the same font differently
 //       on the RGB and mask layers.  The effect of this can be best seen by
 //       contrasting the rendering of a text box with opaque text but a
@@ -123,12 +181,35 @@
         // Else, the line heights become >QFontMetrics::height() if you type Chinese
         // characters (!) and then the cursor gets out of sync.
         int baseLine = pack->textAreaRect.y () + fontMetrics.ascent ();
-        foreach (const QString &str, pack->textLines)
-        {
-            // Note: It seems text does not antialias without XRENDER.
-            p->drawText (pack->textAreaRect.x (), baseLine, str);
+        if (pack->textLines.isEmpty ()) {
+            if (!pack->preeditText.isEmpty ()) {
+                int x = pack->textAreaRect.x ();
+                DrawPreeditString (p, x, baseLine, pack->preeditText);
+            }
+        } else {
+            int i = 0;
+            int row = pack->preeditText.position ().y ();
+            int col = pack->preeditText.position ().x ();
+            foreach (const QString &str, pack->textLines)
+            {
+                // Note: It seems text does not antialias without XRENDER.
+                if (row == i && !pack->preeditText.isEmpty ()) {
+                    QString left = str.left (col);
+                    QString right = str.mid (col);
+                    int x = pack->textAreaRect.x ();
+                    p->drawText (x, baseLine, left);
+                    x += fontMetrics.width (left);
 
-            baseLine += fontMetrics.lineSpacing ();
+                    DrawPreeditString (p, x, baseLine, pack->preeditText);
+
+                    p->drawText (x, baseLine, right);
+
+                } else {
+                    p->drawText (pack->textAreaRect.x (), baseLine, str);
+                }
+                baseLine += fontMetrics.lineSpacing ();
+                i++;
+            }
         }
     }
 }
@@ -208,6 +289,7 @@
     pack.textAreaRect = textAreaRect ().translated (-docRect.topLeft ());
     pack.textLines = textLines ();
     pack.textStyle = textStyle ();
+    pack.preeditText = preeditText ();
 
     kpPixmapFX::draw (destPixmap, &::DrawTextHelper,
         textStyle ().foregroundColor ().isOpaque () ||
Index: layers/selections/text/kpPreeditText.h
===================================================================
--- layers/selections/text/kpPreeditText.h	(revision 0)
+++ layers/selections/text/kpPreeditText.h	(revision 0)
@@ -0,0 +1,65 @@
+
+/*
+   Copyright (c) 2010 Tasuku Suzuki <stasuku@gmail.com>
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef kpPreeditText_H
+#define kpPreeditText_H
+
+#include <QColor>
+#include <QInputMethodEvent>
+#include <QPoint>
+
+class kpPreeditText
+{
+public:
+    kpPreeditText ();
+    kpPreeditText (const QInputMethodEvent *event);
+
+    bool isEmpty () const;
+
+    const QString &preeditString () const;
+    int cursorPosition () const;
+    bool cursorVisible () const;
+    const QColor &cursorColor () const;
+    int selectionStart () const;
+    int selectionLength () const;
+    const QList<QInputMethodEvent::Attribute> &textFormatList () const;
+
+    const QPoint &position () const;
+    void setPosition (const QPoint &position);
+
+private:
+    QString m_preeditString;
+    int m_cursorPosition;
+    QColor m_cursorColor;
+    int m_selectionStart;
+    int m_selectionLength;
+    QList<QInputMethodEvent::Attribute> m_textFormatList;
+    QPoint m_position;
+};
+
+#endif  // kpPreeditText_H
Index: layers/selections/text/kpTextSelection_Cursor.cpp
===================================================================
--- layers/selections/text/kpTextSelection_Cursor.cpp	(revision 1188197)
+++ layers/selections/text/kpTextSelection_Cursor.cpp	(working copy)
@@ -1,6 +1,7 @@
 
 /*
    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
+   Copyright (c) 2010 Tasuku Suzuki <stasuku@gmail.com>
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -39,6 +40,7 @@
 
 #include <kpDefs.h>
 #include <kpTextStyle.h>
+#include <kpPreeditText.h>
 
 
 // public
@@ -89,24 +91,30 @@
 // public
 QPoint kpTextSelection::pointForTextRowCol (int row, int col) const
 {
-    if (row < 0 || row >= (int) d->textLines.size () ||
-        col < 0 || col > (int) d->textLines [row].length ())
+    kpPreeditText preeditText = d->preeditText;
+    if ((row < 0 || col < 0) ||
+        (preeditText.isEmpty () &&
+            (row >= (int) d->textLines.size () || col > (int) d->textLines [row].length ())))
     {
-    #if DEBUG_KP_SELECTION && 1
-        kDebug () << "kpTextSelection::pointForTextRowCol("
-                   << row << ","
-                   << col << ") out of range"
-                   << " textLines='"
-                   << text ()
-                   << "'"
-                   << endl;
-    #endif
+#if DEBUG_KP_SELECTION && 1
+    kDebug () << "kpTextSelection::pointForTextRowCol("
+               << row << ","
+               << col << ") out of range"
+               << " textLines='"
+               << text ()
+               << "'"
+               << endl;
+#endif
         return KP_INVALID_POINT;
     }
 
     const QFontMetrics fontMetrics (d->textStyle.fontMetrics ());
 
-    const int x = fontMetrics.width (d->textLines [row], col);
+    QString line = (d->textLines.count () > row) ? d->textLines[row] : QString::null;
+    if (row == preeditText.position ().y ()) {
+        line.insert (preeditText.position ().x (), preeditText.preeditString ());
+    }
+    const int x = fontMetrics.width (line.left (col));
     const int y = row * fontMetrics.height () +
                   (row >= 1 ? row * fontMetrics.leading () : 0);
 
Index: layers/selections/text/kpTextSelection.cpp
===================================================================
--- layers/selections/text/kpTextSelection.cpp	(revision 1188197)
+++ layers/selections/text/kpTextSelection.cpp	(working copy)
@@ -1,6 +1,7 @@
 
 /*
    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
+   Copyright (c) 2010 Tasuku Suzuki <stasuku@gmail.com>
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -76,6 +77,7 @@
 
     d->textLines = rhs.d->textLines;
     d->textStyle = rhs.d->textStyle;
+    d->preeditText = rhs.d->preeditText;
 
     return *this;
 }
@@ -332,5 +334,15 @@
     emit changed (boundingRect ());
 }
 
+kpPreeditText kpTextSelection::preeditText () const
+{
+    return d->preeditText;
+}
 
+void kpTextSelection::setPreeditText (const kpPreeditText &preeditText)
+{
+    d->preeditText = preeditText;
+    emit changed (boundingRect ());
+}
+
 #include <kpTextSelection.moc>
Index: layers/selections/text/kpTextSelectionPrivate.h
===================================================================
--- layers/selections/text/kpTextSelectionPrivate.h	(revision 1188197)
+++ layers/selections/text/kpTextSelectionPrivate.h	(working copy)
@@ -34,12 +34,13 @@
 
 #include <kpImage.h>
 #include <kpTextStyle.h>
+#include <kpPreeditText.h>
 
-
 struct kpTextSelectionPrivate
 {
     QList <QString> textLines;
     kpTextStyle textStyle;
+    kpPreeditText preeditText;
 };
 
 
Index: layers/selections/text/kpTextSelection.h
===================================================================
--- layers/selections/text/kpTextSelection.h	(revision 1188197)
+++ layers/selections/text/kpTextSelection.h	(working copy)
@@ -33,8 +33,8 @@
 #include <kpAbstractSelection.h>
 #include <kpImage.h>
 #include <kpTextStyle.h>
+#include <kpPreeditText.h>
 
-
 //
 // A rectangular text box containing lines of text, rendered in a given text
 // style.
@@ -227,6 +227,14 @@
 
 
 //
+// Preedit Text
+//
+
+public:
+    kpPreeditText preeditText () const;
+    void setPreeditText (const kpPreeditText &preeditText);
+
+//
 // Cursor
 //
 // A text cursor position is the row and column of a character in
Index: layers/selections/text/kpPreeditText.cpp
===================================================================
--- layers/selections/text/kpPreeditText.cpp	(revision 0)
+++ layers/selections/text/kpPreeditText.cpp	(revision 0)
@@ -0,0 +1,113 @@
+
+/*
+   Copyright (c) 2010 Tasuku Suzuki <stasuku@gmail.com>
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <kpPreeditText.h>
+
+bool attributeLessThan (const QInputMethodEvent::Attribute &a1, const QInputMethodEvent::Attribute &a2)
+{
+    return a1.start < a2.start;
+}
+
+kpPreeditText::kpPreeditText ()
+    : m_cursorPosition (0), m_cursorColor (Qt::transparent),
+      m_selectionStart (0), m_selectionLength (0),
+      m_position (-1, -1)
+{
+}
+
+kpPreeditText::kpPreeditText (const QInputMethodEvent *event)
+    : m_cursorPosition (0), m_cursorColor (Qt::transparent),
+      m_selectionStart (0), m_selectionLength (0),
+      m_position (-1, -1)
+{
+    m_preeditString = event->preeditString ();
+    foreach (const QInputMethodEvent::Attribute &attr, event->attributes ()) {
+        switch (attr.type) {
+        case QInputMethodEvent::TextFormat:
+            m_textFormatList.append (attr);
+            break;
+        case QInputMethodEvent::Cursor:
+            m_cursorPosition = attr.start;
+            if (attr.length > 0) {
+                m_cursorColor = attr.value.value<QColor> ();
+            }
+            break;
+        case QInputMethodEvent::Selection:
+            m_selectionStart = attr.start;
+            m_selectionLength = attr.length;
+            break;
+        default:
+            break;
+        }
+    }
+    qSort (m_textFormatList.begin (), m_textFormatList.end (), attributeLessThan);
+}
+
+bool kpPreeditText::isEmpty () const
+{
+    return m_preeditString.isEmpty ();
+}
+
+const QString &kpPreeditText::preeditString () const
+{
+    return m_preeditString;
+}
+
+int kpPreeditText::cursorPosition () const
+{
+    return m_cursorPosition;
+}
+
+const QColor &kpPreeditText::cursorColor () const
+{
+    return m_cursorColor;
+}
+
+int kpPreeditText::selectionStart () const
+{
+    return m_selectionStart;
+}
+
+int kpPreeditText::selectionLength () const
+{
+    return m_selectionLength;
+}
+
+const QList<QInputMethodEvent::Attribute> &kpPreeditText::textFormatList () const
+{
+    return m_textFormatList;
+}
+
+const QPoint &kpPreeditText::position () const
+{
+    return m_position;
+}
+
+void kpPreeditText::setPosition (const QPoint &position)
+{
+    m_position = position;
+}
