1 /*
2 
3 Copyright (c) 2006-2013 uim Project https://github.com/uim/uim
4 
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10 
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. Neither the name of authors nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 SUCH DAMAGE.
31 
32 */
33 #include <config.h>
34 #include <stdlib.h>
35 
36 #include <qwidget.h>
37 #include <qlineedit.h>
38 #include <qtextedit.h>
39 #include <qapplication.h>
40 #include <qclipboard.h>
41 
42 #include "uim/uim.h"
43 
44 #include "qtextutil.h"
45 #include "quiminputcontext.h"
46 
47 
QUimTextUtil(QObject * parent)48 QUimTextUtil::QUimTextUtil( QObject *parent )
49         : QObject( parent )
50 {
51     mIc = (QUimInputContext *)parent;
52     mPreeditSaved = false;
53 }
54 
~QUimTextUtil()55 QUimTextUtil::~QUimTextUtil()
56 {
57 }
58 
59 int
acquire_text_cb(void * ptr,enum UTextArea text_id,enum UTextOrigin origin,int former_req_len,int latter_req_len,char ** former,char ** latter)60 QUimTextUtil::acquire_text_cb( void *ptr, enum UTextArea text_id,
61                                enum UTextOrigin origin,
62                                int former_req_len, int latter_req_len,
63                                char **former, char **latter )
64 {
65     int err;
66     QUimInputContext *ic = (QUimInputContext *)ptr;
67     QUimTextUtil *tu = ic->textUtil();
68 
69     switch ( text_id ) {
70     case UTextArea_Primary:
71         err = tu->acquirePrimaryText( origin, former_req_len, latter_req_len,
72                                       former, latter );
73         break;
74     case UTextArea_Selection:
75         err = tu->acquireSelectionText( origin, former_req_len, latter_req_len,
76                                         former, latter );
77         break;
78     case UTextArea_Clipboard:
79         err = tu->acquireClipboardText( origin, former_req_len, latter_req_len,
80                                         former, latter );
81         break;
82     case UTextArea_Unspecified:
83     default:
84         err = -1;
85     }
86 
87     return err;
88 }
89 
90 int
delete_text_cb(void * ptr,enum UTextArea text_id,enum UTextOrigin origin,int former_req_len,int latter_req_len)91 QUimTextUtil::delete_text_cb( void *ptr, enum UTextArea text_id,
92                               enum UTextOrigin origin,
93                               int former_req_len, int latter_req_len )
94 {
95     int err;
96     QUimInputContext *ic = (QUimInputContext *)ptr;
97     QUimTextUtil *tu = ic->textUtil();
98 
99     switch ( text_id ) {
100     case UTextArea_Primary:
101         err = tu->deletePrimaryText( origin, former_req_len, latter_req_len );
102         break;
103     case UTextArea_Selection:
104         err = tu->deleteSelectionText( origin, former_req_len, latter_req_len );
105         break;
106     case UTextArea_Clipboard:
107     case UTextArea_Unspecified:
108     default:
109         err = -1;
110         break;
111     }
112 
113     return err;
114 }
115 
116 int
acquirePrimaryText(enum UTextOrigin origin,int former_req_len,int latter_req_len,char ** former,char ** latter)117 QUimTextUtil::acquirePrimaryText( enum UTextOrigin origin,
118                                   int former_req_len, int latter_req_len,
119                                   char **former, char **latter )
120 {
121     int err;
122 #if defined(Q_WS_X11)
123     mWidget = mIc->focusWidget();
124 #else
125     return -1;
126 #endif
127 
128     if ( mWidget->inherits( "QLineEdit" ) )
129         err = acquirePrimaryTextInQLineEdit( origin, former_req_len,
130                                              latter_req_len, former, latter );
131     else if ( mWidget->inherits( "QTextEdit" ) )
132         err = acquirePrimaryTextInQTextEdit( origin, former_req_len,
133                                              latter_req_len, former, latter );
134     else
135         // FIXME other widgets?
136         err = -1;
137 
138     return err;
139 }
140 
141 int
acquirePrimaryTextInQLineEdit(enum UTextOrigin origin,int former_req_len,int latter_req_len,char ** former,char ** latter)142 QUimTextUtil::acquirePrimaryTextInQLineEdit( enum UTextOrigin origin,
143                                              int former_req_len,
144                                              int latter_req_len,
145                                              char **former, char **latter )
146 {
147     QLineEdit *edit = (QLineEdit *)mWidget;
148     QString text, former_text, latter_text;
149     int cursor_index, len, precedence_len, following_len, offset;
150     int preedit_len, preedit_cursor_pos;
151 
152     preedit_len = mIc->getPreeditString().length();
153     preedit_cursor_pos = mIc->getPreeditCursorPosition();
154 
155     text = edit->text(); // including preedit string
156     len = text.length();
157     cursor_index = edit->cursorPosition();
158 
159     precedence_len = cursor_index - preedit_cursor_pos;
160     following_len = len - precedence_len - preedit_len;
161 
162     switch ( origin ) {
163     case UTextOrigin_Cursor:
164         offset = 0;
165         if ( former_req_len >= 0 ) {
166             if ( precedence_len > former_req_len )
167               offset = precedence_len - former_req_len;
168         } else {
169             if (! ( ~former_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
170                 return -1;
171         }
172         *former = strdup( text.mid( offset, precedence_len - offset ).utf8() );
173 
174         offset = 0;
175         if ( latter_req_len >= 0 ) {
176             if ( following_len > latter_req_len )
177                 offset = following_len - latter_req_len;
178         } else {
179             if (! ( ~latter_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) ) {
180                 free( *former );
181                 return -1;
182             }
183         }
184         *latter = strdup( text.mid( precedence_len + preedit_len, following_len - offset ).utf8() );
185         break;
186 
187     case UTextOrigin_Beginning:
188         *former = NULL;
189         if ( latter_req_len >= 0 ) {
190             if ( precedence_len >= latter_req_len )
191                 text = text.left( latter_req_len );
192             else {
193                 former_text = text.left( precedence_len );
194                 if ( following_len >= ( latter_req_len - precedence_len ) )
195                     latter_text = text.mid( precedence_len + preedit_len, ( latter_req_len - precedence_len ) );
196                 else
197                     latter_text = text.mid( precedence_len + preedit_len, following_len );
198                 text = former_text + latter_text;
199             }
200         } else {
201             if (! ( ~latter_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
202                 return -1;
203 
204             former_text = text.left( precedence_len );
205             latter_text = text.mid( precedence_len + preedit_len, following_len );
206             text = former_text + latter_text;
207         }
208         *latter = strdup( text.utf8() );
209         break;
210 
211     case UTextOrigin_End:
212         if ( former_req_len >= 0 ) {
213             if ( following_len >= former_req_len )
214                 text = text.right( former_req_len );
215             else {
216                     latter_text = text.right( following_len );
217                 if ( precedence_len >= ( former_req_len - following_len ) )
218                     former_text = text.mid( precedence_len - ( former_req_len - following_len ), former_req_len - following_len );
219                 else
220                     former_text = text.left( precedence_len );
221                 text = former_text + latter_text;
222             }
223         } else {
224             if (! ( ~former_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
225                 return -1;
226 
227             former_text = text.left( precedence_len );
228             latter_text = text.right( following_len );
229             text = former_text + latter_text;
230         }
231         *former = strdup( text.utf8() );
232         *latter = NULL;
233         break;
234 
235     case UTextOrigin_Unspecified:
236     default:
237         return -1;
238     }
239 
240     return 0;
241 }
242 
243 int
acquirePrimaryTextInQTextEdit(enum UTextOrigin origin,int former_req_len,int latter_req_len,char ** former,char ** latter)244 QUimTextUtil::acquirePrimaryTextInQTextEdit( enum UTextOrigin origin,
245                                              int former_req_len,
246                                              int latter_req_len,
247                                              char **former, char **latter )
248 {
249     QTextEdit *edit = (QTextEdit *)mWidget;
250     QString text;
251 
252     int i;
253     int start_para, start_index, end_para, end_index, para, index;
254     int n_para;
255     int preedit_len, preedit_cursor_pos;
256     int sel_start_para, sel_start_index, sel_end_para, sel_end_index;
257     TextFormat format;
258 
259     format = edit->textFormat();
260     edit->setTextFormat( Qt::PlainText );
261 
262     edit->getCursorPosition( &para, &index ); // including preedit string
263 
264     // keep current selection
265     edit->getSelection( &sel_start_para, &sel_start_index, &sel_end_para,
266                         &sel_end_index, 0 );
267 
268     preedit_len = mIc->getPreeditString().length();
269     preedit_cursor_pos = mIc->getPreeditCursorPosition();
270     n_para = edit->paragraphs();
271 
272     switch ( origin ) {
273     case UTextOrigin_Cursor:
274         start_index = index - preedit_cursor_pos;
275         start_para = para;
276         end_index = start_index + preedit_len;
277         end_para = para;
278 
279         if ( former_req_len >= 0 ) {
280             for ( i = 0; i < former_req_len; i++ )
281                 QTextEditPositionBackward( &start_para, &start_index );
282         } else {
283             if ( former_req_len == UTextExtent_Line )
284                 start_index = 0;
285             else if ( former_req_len == UTextExtent_Full ) {
286                 start_para = 0;
287                 start_index = 0;
288             } else {
289                 edit->setTextFormat( format );
290                 return -1;
291             }
292         }
293         edit->setSelection( start_para, start_index, para, index - preedit_cursor_pos, 0 );
294         *former = strdup( edit->selectedText().utf8() );
295 
296         if ( latter_req_len >= 0 ) {
297             for ( i = 0; i < latter_req_len; i++ )
298                 QTextEditPositionForward( &end_para, &end_index );
299         } else {
300             if ( latter_req_len == UTextExtent_Line ) {
301                 end_index = edit->paragraphLength( end_para );
302             } else if ( latter_req_len == UTextExtent_Full ) {
303                 end_para = n_para - 1;
304                 end_index = edit->paragraphLength( end_para );
305             } else {
306                 edit->setTextFormat( format );
307                 return -1;
308             }
309         }
310         edit->setSelection( para, index - preedit_cursor_pos + preedit_len,
311                             end_para, end_index, 0 );
312         *latter = strdup( edit->selectedText().utf8() );
313         break;
314 
315     case UTextOrigin_Beginning:
316         *former = NULL;
317 
318         start_para = 0;
319         start_index = 0;
320         end_para = start_para;
321         end_index = start_index;
322 
323         if ( latter_req_len >= 0 ) {
324             for ( i = 0; i < latter_req_len; i++ )
325                 QTextEditPositionForward( &end_para, &end_index );
326         } else {
327             if ( latter_req_len == UTextExtent_Line )
328                 end_index = edit->paragraphLength( end_para );
329             else if ( latter_req_len == UTextExtent_Full ) {
330                 end_para = n_para - 1;
331                 end_index = edit->paragraphLength( end_para );
332             } else {
333                 edit->setTextFormat( format );
334                 return -1;
335             }
336         }
337         if ( end_para < para || ( end_para == para && end_index <= ( index - preedit_cursor_pos ) ) ) {
338             edit->setSelection( start_para, start_index, end_para, end_index, 0 );
339             text = edit->selectedText();
340         } else {
341             edit->setSelection( start_para, start_index, para, index - preedit_cursor_pos, 0 );
342             text = edit->selectedText();
343             edit->setSelection( para, index - preedit_cursor_pos + preedit_len, end_para, end_index, 0 );
344             text += edit->selectedText();
345         }
346         *latter = strdup( text.utf8() );
347         break;
348 
349     case UTextOrigin_End:
350 
351         end_para = n_para - 1;
352         end_index = edit->paragraphLength( end_para );
353         start_para = end_para;
354         start_index = end_index;
355 
356         if ( former_req_len >= 0 ) {
357             for ( i = 0; i < former_req_len; i++ )
358                 QTextEditPositionBackward( &start_para, &start_index );
359         } else {
360             if ( former_req_len == UTextExtent_Line )
361                 start_index = 0;
362             else if ( former_req_len == UTextExtent_Full ) {
363                 start_para = 0;
364                 start_index = 0;
365             } else {
366                 edit->setTextFormat( format );
367                 return -1;
368             }
369         }
370         if ( start_para > para || ( start_para == para && start_index >= ( index - preedit_cursor_pos + preedit_len ) ) ) {
371             edit->setSelection( start_para, start_index, end_para, end_index, 0 );
372             text = edit->selectedText();
373         } else {
374 
375             edit->setSelection( start_para, start_index, para, index - preedit_cursor_pos, 0 );
376             text = edit->selectedText();
377 
378             edit->setSelection( para, index - preedit_cursor_pos + preedit_len, end_para, end_index, 0 );
379             text += edit->selectedText();
380         }
381         *former = strdup( text.utf8() );
382         *latter = NULL;
383         break;
384 
385     case UTextOrigin_Unspecified:
386     default:
387         edit->setTextFormat( format );
388         return -1;
389     }
390 
391     if ( sel_start_para != -1 && sel_start_index != -1 && sel_end_para != -1 &&
392          sel_end_index != -1 )
393         edit->setSelection( sel_start_index, sel_start_index, sel_end_para, sel_end_index, 0 );
394     else
395         edit->removeSelection( 0 );
396 
397     edit->setCursorPosition( para, index );
398 
399     edit->setTextFormat( format );
400     return 0;
401 }
402 
403 int
acquireSelectionText(enum UTextOrigin origin,int former_req_len,int latter_req_len,char ** former,char ** latter)404 QUimTextUtil::acquireSelectionText( enum UTextOrigin origin,
405                                     int former_req_len, int latter_req_len,
406                                     char **former, char **latter )
407 {
408     int err;
409 #if defined(Q_WS_X11)
410     mWidget = mIc->focusWidget();
411 #else
412     return -1;
413 #endif
414 
415     if ( mWidget->inherits( "QLineEdit" ) )
416         err = acquireSelectionTextInQLineEdit( origin, former_req_len,
417                                                latter_req_len, former, latter );
418     else if ( mWidget->inherits( "QTextEdit" ) )
419         err = acquireSelectionTextInQTextEdit( origin, former_req_len,
420                                                latter_req_len, former, latter );
421     else
422         // FIXME other widgets?
423         err = -1;
424 
425     return err;
426 }
427 
428 int
acquireSelectionTextInQLineEdit(enum UTextOrigin origin,int former_req_len,int latter_req_len,char ** former,char ** latter)429 QUimTextUtil::acquireSelectionTextInQLineEdit( enum UTextOrigin origin,
430                                                int former_req_len,
431                                                int latter_req_len,
432                                                char **former, char **latter )
433 {
434     QLineEdit *edit = (QLineEdit *)mWidget;
435     QString text;
436     int len, offset, start, current;
437     bool cursor_at_beginning = false;
438 
439     if ( ! edit->hasSelectedText() )
440         return -1;
441 
442     current = edit->cursorPosition();
443     start = edit->selectionStart();
444 
445     if ( current == start )
446         cursor_at_beginning = true;
447 
448     text = edit->selectedText();
449     len = text.length();
450 
451     if ( origin == UTextOrigin_Beginning ||
452          ( origin == UTextOrigin_Cursor && cursor_at_beginning ) ) {
453         *former = NULL;
454         offset = 0;
455         if ( latter_req_len >= 0 ) {
456             if ( len > latter_req_len )
457                 offset = len - latter_req_len;
458         } else {
459             if (! ( ~latter_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
460                 return -1;
461         }
462         *latter = strdup( text.left( len - offset ).utf8() );
463     } else if ( origin == UTextOrigin_End ||
464                 ( origin == UTextOrigin_Cursor && !cursor_at_beginning ) ) {
465         offset = 0;
466         if ( former_req_len >= 0 ) {
467             if ( len > former_req_len )
468                 offset = len - former_req_len;
469         } else {
470             if (! ( ~former_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
471                 return -1;
472         }
473         *former = strdup( text.mid( offset, len - offset ).utf8() );
474         *latter = NULL;
475     } else {
476         return -1;
477     }
478 
479     return 0;
480 }
481 
482 int
acquireSelectionTextInQTextEdit(enum UTextOrigin origin,int former_req_len,int latter_req_len,char ** former,char ** latter)483 QUimTextUtil::acquireSelectionTextInQTextEdit( enum UTextOrigin origin,
484                                                int former_req_len,
485                                                int latter_req_len,
486                                                char **former, char **latter )
487 {
488     QTextEdit *edit = (QTextEdit *)mWidget;
489     QString text;
490     int len, offset, newline;
491     int start_para, start_index, end_para, end_index;
492     int para, index;
493     bool cursor_at_beginning = false;
494     TextFormat format;
495 
496     if ( ! edit->hasSelectedText() )
497         return -1;
498 
499     format = edit->textFormat();
500     edit->setTextFormat( Qt::PlainText );
501 
502     edit->getCursorPosition( &para, &index );
503     edit->getSelection(&start_para, &start_index, &end_para, &end_index, 0 );
504 
505     if ( para == start_para && index == start_index )
506         cursor_at_beginning = true;
507 
508     text = edit->selectedText();
509     len = text.length();
510 
511     if ( origin == UTextOrigin_Beginning ||
512          ( origin == UTextOrigin_Cursor && cursor_at_beginning ) ) {
513         *former = NULL;
514         offset = 0;
515         if ( latter_req_len >= 0 ) {
516             if ( len > latter_req_len )
517                 offset = len - latter_req_len;
518         } else {
519             if (! ( ~latter_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) ) {
520                 edit->setTextFormat( format );
521                 return -1;
522             }
523 
524             if ( latter_req_len == UTextExtent_Line && ( ( newline = text.find( '\n' ) ) != -1 ) )
525                 offset = len - newline;
526         }
527         *latter = strdup( text.left( len - offset ).utf8() );
528     } else if ( origin == UTextOrigin_End ||
529                 ( origin == UTextOrigin_Cursor && !cursor_at_beginning ) ) {
530         offset = 0;
531         if ( former_req_len >= 0 ) {
532             if ( len > former_req_len )
533                 offset = len - former_req_len;
534         } else {
535             if (! ( ~former_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) ) {
536                 edit->setTextFormat( format );
537                 return -1;
538             }
539 
540             if ( former_req_len == UTextExtent_Line && ( ( newline = text.findRev( '\n' ) ) != -1 ) )
541                 offset = newline + 1;
542         }
543         *former = strdup( text.mid( offset, len - offset ).utf8() );
544         *latter = NULL;
545     } else {
546         edit->setTextFormat( format );
547         return -1;
548     }
549 
550     edit->setTextFormat( format );
551     return 0;
552 }
553 
554 int
acquireClipboardText(enum UTextOrigin origin,int former_req_len,int latter_req_len,char ** former,char ** latter)555 QUimTextUtil::acquireClipboardText( enum UTextOrigin origin,
556                                     int former_req_len, int latter_req_len,
557                                     char **former, char **latter )
558 {
559     QClipboard *cb = QApplication::clipboard();
560     QString text = cb->text( QClipboard::Clipboard );
561     int len, offset, newline;
562 
563     if ( text.isNull() )
564         return -1;
565 
566     len = text.length();
567 
568     /* Cursor position is assumed to be at the end */
569     switch ( origin ) {
570     case UTextOrigin_Cursor:
571     case UTextOrigin_End:
572         offset = 0;
573         if ( former_req_len >= 0 ) {
574             if ( former_req_len < len )
575                 offset = len - former_req_len;
576         } else {
577             if (! ( ~former_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
578                 return -1;
579 
580             if ( former_req_len == UTextExtent_Line && ( ( newline = text.findRev( '\n' ) ) != -1 ) )
581                 offset = newline + 1;
582         }
583         *former = strdup( text.mid( offset, len - offset ).utf8() );
584         *latter = NULL;
585         break;
586 
587     case UTextOrigin_Beginning:
588         *former = NULL;
589         offset = 0;
590         if ( latter_req_len >= 0 ) {
591             if ( latter_req_len < len )
592                 offset = len - latter_req_len;
593         } else {
594             if (! ( ~latter_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
595                 return -1;
596 
597             if ( latter_req_len == UTextExtent_Line && ( ( newline = text.find( '\n' ) ) != -1 ) )
598                 offset = len - newline;
599         }
600         *latter = strdup( text.left( len - offset ).utf8() );
601         break;
602 
603     case UTextOrigin_Unspecified:
604     default:
605         return -1;
606     }
607 
608     return 0;
609 }
610 
611 int
deletePrimaryText(enum UTextOrigin origin,int former_req_len,int latter_req_len)612 QUimTextUtil::deletePrimaryText( enum UTextOrigin origin, int former_req_len,
613                                  int latter_req_len )
614 {
615     int err;
616 #if defined(Q_WS_X11)
617     mWidget = mIc->focusWidget();
618 #else
619     return -1;
620 #endif
621 
622     if ( mWidget->inherits( "QLineEdit" ) )
623         err = deletePrimaryTextInQLineEdit( origin, former_req_len,
624                                             latter_req_len );
625     else if ( mWidget->inherits( "QTextEdit" ) )
626         err = deletePrimaryTextInQTextEdit( origin, former_req_len,
627                                             latter_req_len );
628     else
629         // FIXME other widgets?
630         err = -1;
631 
632     return err;
633 }
634 
635 int
deletePrimaryTextInQLineEdit(enum UTextOrigin origin,int former_req_len,int latter_req_len)636 QUimTextUtil::deletePrimaryTextInQLineEdit( enum UTextOrigin origin,
637                                             int former_req_len,
638                                             int latter_req_len )
639 {
640     QLineEdit *edit = (QLineEdit *)mWidget;
641     QString text;
642     int cursor_index, len, precedence_len, following_len;
643     int preedit_len, preedit_cursor_pos;
644     int former_del_start;
645     int latter_del_end;
646 
647     preedit_len = mIc->getPreeditString().length();
648     preedit_cursor_pos = mIc->getPreeditCursorPosition();
649 
650     text = edit->text(); // including preedit string
651     len = text.length();
652     cursor_index = edit->cursorPosition();
653 
654     precedence_len = cursor_index - preedit_cursor_pos;
655     following_len = len - precedence_len - preedit_len;
656 
657     switch ( origin ) {
658     case UTextOrigin_Cursor:
659         former_del_start = 0;
660         if ( former_req_len >= 0 ) {
661             if ( precedence_len > former_req_len )
662                 former_del_start = precedence_len - former_req_len;
663         } else {
664             if (! ( ~former_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
665                 return -1;
666         }
667         latter_del_end = len;
668         if ( latter_req_len >= 0 ) {
669             if ( following_len > latter_req_len )
670                 latter_del_end = precedence_len + preedit_len + latter_req_len;
671         } else {
672             if (! ( ~latter_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
673                 return -1;
674         }
675         break;
676 
677     case UTextOrigin_Beginning:
678         former_del_start = 0;
679         latter_del_end = precedence_len + preedit_len;
680         if ( latter_req_len >= 0 ) {
681             if ( precedence_len < latter_req_len ) {
682                 if ( following_len >= ( latter_req_len - precedence_len ) )
683                     latter_del_end = preedit_len + latter_req_len;
684                 else
685                     latter_del_end = len;
686             }
687         } else {
688             if (! ( ~latter_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
689                 return -1;
690             latter_del_end = len;
691         }
692         break;
693 
694     case UTextOrigin_End:
695         former_del_start = precedence_len;
696         latter_del_end = len;
697         if ( former_req_len < 0 ) {
698             if (! ( ~former_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
699                 return -1;
700 
701             former_del_start = 0;
702         }
703         break;
704 
705     case UTextOrigin_Unspecified:
706     default:
707         return -1;
708     }
709 
710     edit->setText( text.left( former_del_start ) + text.right( len - latter_del_end ) );
711     edit->setCursorPosition( former_del_start );
712 
713     return 0;
714 }
715 
716 int
deletePrimaryTextInQTextEdit(enum UTextOrigin origin,int former_req_len,int latter_req_len)717 QUimTextUtil::deletePrimaryTextInQTextEdit( enum UTextOrigin origin,
718                                             int former_req_len,
719                                             int latter_req_len )
720 {
721     QTextEdit *edit = (QTextEdit *)mWidget;
722     int i;
723     int start_para, start_index, end_para, end_index, para, index;
724     int n_para;
725 
726     savePreedit();
727 
728     edit->getCursorPosition( &para, &index );
729     n_para = edit->paragraphs();
730 
731     switch ( origin ) {
732     case UTextOrigin_Cursor:
733         start_index = index;
734         start_para = para;
735         end_index = start_index;
736         end_para = para;
737 
738         if ( former_req_len >= 0 ) {
739             for ( i = 0; i < former_req_len; i++ )
740                 QTextEditPositionBackward( &start_para, &start_index );
741         } else {
742             if ( former_req_len == UTextExtent_Line ) {
743                 start_index = 0;
744             } else if ( former_req_len == UTextExtent_Full ) {
745                 start_para = 0;
746                 start_index = 0;
747             } else {
748                 restorePreedit();
749                 return -1;
750             }
751         }
752         if ( latter_req_len >= 0 ) {
753             for ( i = 0; i < latter_req_len; i++ )
754                 QTextEditPositionForward( &end_para, &end_index );
755         } else {
756             if ( latter_req_len == UTextExtent_Line ) {
757                 end_index = edit->paragraphLength( end_para );
758             } else if ( latter_req_len == UTextExtent_Full ) {
759                 end_para = n_para - 1;
760                 end_index = edit->paragraphLength( end_para );
761             } else {
762                 restorePreedit();
763                 return -1;
764             }
765         }
766         break;
767 
768     case UTextOrigin_Beginning:
769         start_para = 0;
770         start_index = 0;
771         end_para = start_para;
772         end_index = start_index;
773 
774         if ( latter_req_len >= 0 ) {
775             for ( i = 0; i < latter_req_len; i++ )
776                 QTextEditPositionForward( &end_para, &end_index );
777         } else {
778             if ( latter_req_len == UTextExtent_Line ) {
779                 end_index = edit->paragraphLength( end_para );
780             } else if ( latter_req_len == UTextExtent_Full ) {
781                 end_para = n_para - 1;
782                 end_index = edit->paragraphLength( end_para );
783             } else {
784                 restorePreedit();
785                 return -1;
786             }
787         }
788         break;
789 
790     case UTextOrigin_End:
791         end_para = n_para - 1;
792         end_index = edit->paragraphLength( end_para );
793         start_para = end_para;
794         start_index = end_index;
795 
796         if ( former_req_len >= 0 ) {
797             for ( i = 0; i < former_req_len; i++ )
798                 QTextEditPositionBackward( &start_para, &start_index );
799         } else {
800             if ( former_req_len == UTextExtent_Line )
801                 start_index = 0;
802             else if ( former_req_len == UTextExtent_Full ) {
803                 start_para = 0;
804                 start_index = 0;
805             } else {
806                 restorePreedit();
807                 return -1;
808             }
809         }
810         break;
811 
812     case UTextOrigin_Unspecified:
813     default:
814         restorePreedit();
815         return -1;
816     }
817     edit->setSelection( start_para, start_index, end_para, end_index, 1 );
818     edit->removeSelectedText( 1 );
819     edit->setCursorPosition( start_para, start_index );
820     restorePreedit();
821 
822     return 0;
823 }
824 
825 int
deleteSelectionText(enum UTextOrigin origin,int former_req_len,int latter_req_len)826 QUimTextUtil::deleteSelectionText( enum UTextOrigin origin,
827                                    int former_req_len, int latter_req_len )
828 {
829     int err;
830 #if defined(Q_WS_X11)
831     mWidget = mIc->focusWidget();
832 #else
833     return -1;
834 #endif
835 
836     if ( mWidget->inherits( "QLineEdit" ) )
837         err = deleteSelectionTextInQLineEdit( origin, former_req_len,
838                                               latter_req_len );
839     else if ( mWidget->inherits( "QTextEdit" ) )
840         err = deleteSelectionTextInQTextEdit( origin, former_req_len,
841                                               latter_req_len );
842     else
843         // FIXME other widgets?
844         err = -1;
845 
846     return err;
847 }
848 
849 int
deleteSelectionTextInQLineEdit(enum UTextOrigin origin,int former_req_len,int latter_req_len)850 QUimTextUtil::deleteSelectionTextInQLineEdit( enum UTextOrigin origin,
851                                               int former_req_len,
852                                               int latter_req_len )
853 {
854     QLineEdit *edit = (QLineEdit *)mWidget;
855     QString text;
856     int len, start, end, current;
857     bool cursor_at_beginning = false;
858 
859     if ( ! edit->hasSelectedText() )
860         return -1;
861 
862     current = edit->cursorPosition();
863     start = edit->selectionStart();
864     if ( current == start )
865         cursor_at_beginning = true;
866 
867     text = edit->selectedText();
868     len = text.length();
869     end = start + len;
870 
871     if ( origin == UTextOrigin_Beginning ||
872          ( origin == UTextOrigin_Cursor && cursor_at_beginning ) ) {
873         if ( latter_req_len >= 0 ) {
874             if ( len > latter_req_len )
875                 end = start + latter_req_len;
876         } else {
877             if (! ( ~latter_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
878                 return -1;
879         }
880     } else if ( origin == UTextOrigin_End ||
881                 ( origin == UTextOrigin_Cursor && !cursor_at_beginning ) ) {
882         if ( former_req_len >= 0 ) {
883             if ( len > former_req_len )
884                 start = end - former_req_len;
885         } else {
886             if (! ( ~former_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
887                 return -1;
888         }
889     } else {
890         return -1;
891     }
892     edit->setSelection( start, end - start );
893     edit->del();
894 
895     return 0;
896 }
897 
898 int
deleteSelectionTextInQTextEdit(enum UTextOrigin origin,int former_req_len,int latter_req_len)899 QUimTextUtil::deleteSelectionTextInQTextEdit( enum UTextOrigin origin,
900                                               int former_req_len,
901                                               int latter_req_len )
902 {
903     QTextEdit *edit = (QTextEdit *)mWidget;
904     QString text;
905     int len, newline, i;
906     int para, index;
907     int sel_para_from, sel_index_from, sel_para_to, sel_index_to;
908     int start_para, start_index, end_para, end_index;
909     bool cursor_at_beginning = false;
910 
911     if ( ! edit->hasSelectedText() )
912         return -1;
913 
914     edit->getCursorPosition( &para, &index );
915     edit->getSelection( &sel_para_from, &sel_index_from, &sel_para_to, &sel_index_to, 0 );
916 
917     if ( para == sel_para_from && index == sel_index_from )
918         cursor_at_beginning = true;
919 
920     text = edit->selectedText();
921     len = text.length();
922 
923     start_para = sel_para_from;
924     start_index = sel_index_from;
925     end_para = sel_para_to;
926     end_index = sel_index_to;
927 
928     if ( origin == UTextOrigin_Beginning ||
929          ( origin == UTextOrigin_Cursor && cursor_at_beginning ) ) {
930         edit->setCursorPosition( sel_para_from, sel_index_from );
931         if ( latter_req_len >= 0 ) {
932             if ( len > latter_req_len ) {
933                 end_para = sel_para_from;
934                 end_index = sel_index_from;
935                 for ( i = 0; i < latter_req_len; i++)
936                     QTextEditPositionForward( &end_para, &end_index );
937             }
938         } else {
939             if (! ( ~latter_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
940                 return -1;
941 
942             if ( latter_req_len == UTextExtent_Line && ( ( newline = text.find('\n') ) != -1 ) ) {
943                 end_para = sel_para_from;
944                 end_index = sel_index_from + newline;
945             }
946         }
947     } else if ( origin == UTextOrigin_End ||
948                 ( origin == UTextOrigin_Cursor && !cursor_at_beginning ) ) {
949         if ( former_req_len >= 0 ) {
950             if ( len > former_req_len ) {
951                 start_para = sel_para_to;
952                 start_index = sel_index_to;
953                 for ( i = 0; i < former_req_len; i++)
954                     QTextEditPositionBackward( &start_para, &start_index );
955             }
956         } else {
957             if (! ( ~former_req_len & ( ~UTextExtent_Line | ~UTextExtent_Full ) ) )
958                 return -1;
959 
960             if ( former_req_len == UTextExtent_Line && ( ( newline = text.findRev( '\n' ) ) != -1 ) ) {
961                 start_para = sel_para_to;
962                 start_index = 0;
963             }
964         }
965     } else {
966         return -1;
967     }
968     edit->setSelection( start_para, start_index, end_para, end_index, 1 );
969     edit->removeSelectedText( 1 );
970 
971     return 0;
972 }
973 
974 void
QTextEditPositionBackward(int * cursor_para,int * cursor_index)975 QUimTextUtil::QTextEditPositionBackward( int *cursor_para, int *cursor_index )
976 {
977     QTextEdit *edit = (QTextEdit *)mWidget;
978     int preedit_len, preedit_cursor_pos;
979     int para, index;
980     int current_para, current_index;
981 
982     current_para = *cursor_para;
983     current_index = *cursor_index;
984 
985     if ( ! mPreeditSaved ) {
986         preedit_len = mIc->getPreeditString().length();
987         preedit_cursor_pos = mIc->getPreeditCursorPosition();
988     } else {
989         preedit_len = 0;
990         preedit_cursor_pos = 0;
991     }
992     edit->getCursorPosition( &para, &index );
993 
994     if ( current_para == para && current_index > ( index - preedit_cursor_pos ) && ( current_index <= ( index - preedit_cursor_pos + preedit_len ) ) )
995         current_index = index - preedit_cursor_pos;
996 
997     if ( current_index > 0 )
998         current_index--;
999     else {
1000         if ( current_para > 0 ) {
1001             current_para--;
1002             current_index = edit->paragraphLength( current_para );
1003         }
1004     }
1005 
1006     *cursor_para = current_para;
1007     *cursor_index = current_index;
1008 }
1009 
1010 void
QTextEditPositionForward(int * cursor_para,int * cursor_index)1011 QUimTextUtil::QTextEditPositionForward( int *cursor_para, int *cursor_index )
1012 {
1013     QTextEdit *edit = (QTextEdit *)mWidget;
1014     int n_para = edit->paragraphs();
1015     int preedit_len, preedit_cursor_pos;
1016     int current_para_len;
1017     int para, index;
1018     int current_para, current_index;
1019 
1020     current_para = *cursor_para;
1021     current_index = *cursor_index;
1022 
1023     current_para_len = edit->paragraphLength( current_para );
1024     if ( ! mPreeditSaved ) {
1025         preedit_len = mIc->getPreeditString().length();
1026         preedit_cursor_pos = mIc->getPreeditCursorPosition();
1027     } else {
1028         preedit_len = 0;
1029         preedit_cursor_pos = 0;
1030     }
1031     edit->getCursorPosition( &para, &index );
1032 
1033     if ( current_para == para && current_index >= ( index - preedit_cursor_pos ) && current_index < ( index - preedit_cursor_pos + preedit_len ) )
1034         current_index = index - preedit_cursor_pos + preedit_len;
1035 
1036     if ( current_para == n_para - 1 ) {
1037         if ( current_index < current_para_len )
1038             current_index++;
1039     } else {
1040         if ( current_index < current_para_len )
1041             current_index++;
1042         else {
1043             current_para++;
1044             current_index = 0;
1045         }
1046     }
1047 
1048     *cursor_para = current_para;
1049     *cursor_index = current_index;
1050 }
1051 
savePreedit()1052 void QUimTextUtil::savePreedit()
1053 {
1054     mIc->saveContext();
1055     mPreeditSaved = true;
1056 }
1057 
restorePreedit()1058 void QUimTextUtil::restorePreedit()
1059 {
1060     mIc->restoreContext();
1061     mPreeditSaved = false;
1062 }
1063 
1064 #include "qtextutil.moc"
1065