1 /*
2 
3  Copyright (c) 2003-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 "customwidgets.h"
34 
35 #include <cstdlib>
36 #include <cctype>
37 
38 #include "qtgettext.h"
39 
40 #include <QtCore/QPointer>
41 #if QT_VERSION < 0x050000
42 # include <QtGui/QFileDialog>
43 # include <QtGui/QHeaderView>
44 # include <QtGui/QLabel>
45 # include <QtGui/QPushButton>
46 # include <QtGui/QTableWidget>
47 # include <QtGui/QTreeWidget>
48 # include <QtGui/QTreeWidgetItem>
49 # include <QtGui/QVBoxLayout>
50 #else
51 # include <QtWidgets/QFileDialog>
52 # include <QtWidgets/QHeaderView>
53 # include <QtWidgets/QLabel>
54 # include <QtWidgets/QPushButton>
55 # include <QtWidgets/QTableWidget>
56 # include <QtWidgets/QTreeWidget>
57 # include <QtWidgets/QTreeWidgetItem>
58 # include <QtWidgets/QVBoxLayout>
59 #endif
60 
_FU8(const char string[])61 inline static QString _FU8( const char string[] )
62 {
63     return QString::fromUtf8(string);
64 }
65 
66 static const int DEBUG_KEY_EDIT = 0;
67 static QString unicodeKeyToSymStr( QChar c );
68 
CustomCheckBox(struct uim_custom * c,QWidget * parent)69 CustomCheckBox::CustomCheckBox( struct uim_custom *c, QWidget *parent )
70     : QCheckBox( parent ),
71       UimCustomItemIface( c )
72 {
73     connect( this, SIGNAL(toggled(bool)),
74                       this, SLOT(slotCustomToggled(bool)) );
75 
76     update();
77 }
78 
update()79 void CustomCheckBox::update()
80 {
81     if( !m_custom || m_custom->type != UCustom_Bool )
82         return;
83 
84     setText( _FU8(m_custom->label) );
85     setChecked( m_custom->value->as_bool );
86 
87     setEnabled( m_custom->is_active );
88 }
89 
setDefault()90 void CustomCheckBox::setDefault()
91 {
92     m_custom->value->as_bool = m_custom->default_value->as_bool;
93 
94     setCustom( m_custom );
95     update();
96 }
97 
slotCustomToggled(bool check)98 void CustomCheckBox::slotCustomToggled( bool check )
99 {
100     Q_ASSERT( m_custom->type == UCustom_Bool );
101 
102     m_custom->value->as_bool = check;
103     setCustom( m_custom );
104 }
105 
106 //----------------------------------------------------------------------------------------
CustomSpinBox(struct uim_custom * c,QWidget * parent)107 CustomSpinBox::CustomSpinBox( struct uim_custom *c, QWidget *parent )
108     : QSpinBox( parent ),
109       UimCustomItemIface( c )
110 {
111     setMinimum( c->range->as_int.min );
112     setMaximum( c->range->as_int.max );
113     setSingleStep( 1 );
114     connect( this, SIGNAL(valueChanged(int)),
115                       this, SLOT(slotCustomValueChanged(int)) );
116     update();
117 }
118 
update()119 void CustomSpinBox::update()
120 {
121     if( !m_custom || m_custom->type != UCustom_Int )
122         return;
123 
124     setValue( m_custom->value->as_int );
125     setMinimum( m_custom->range->as_int.min );
126     setMaximum( m_custom->range->as_int.max );
127 
128     /* sync with Label */
129     parentWidget()->setEnabled( m_custom->is_active );
130 }
131 
setDefault()132 void CustomSpinBox::setDefault()
133 {
134     m_custom->value->as_int = m_custom->default_value->as_int;
135 
136     setCustom( m_custom );
137     update();
138 }
139 
slotCustomValueChanged(int value)140 void CustomSpinBox::slotCustomValueChanged( int value )
141 {
142     Q_ASSERT( m_custom->type == UCustom_Int );
143 
144     m_custom->value->as_int = value;
145     setCustom( m_custom );
146 }
147 
148 //----------------------------------------------------------------------------------------
CustomLineEdit(struct uim_custom * c,QWidget * parent)149 CustomLineEdit::CustomLineEdit( struct uim_custom *c, QWidget *parent )
150     : QLineEdit( parent ),
151       UimCustomItemIface( c )
152 {
153     connect( this, SIGNAL(textChanged(const QString&)),
154                       this, SLOT(slotCustomTextChanged(const QString&)) );
155 
156     setAttribute( Qt::WA_InputMethodEnabled, false );
157     update();
158 }
159 
update()160 void CustomLineEdit::update()
161 {
162     if( !m_custom || m_custom->type != UCustom_Str )
163         return;
164 
165     setText( _FU8(m_custom->value->as_str) );
166 
167     /* sync with Label */
168     parentWidget()->setEnabled( m_custom->is_active );
169 }
170 
setDefault()171 void CustomLineEdit::setDefault()
172 {
173     free( m_custom->value->as_str );
174     m_custom->value->as_str = strdup( m_custom->default_value->as_str );
175 
176     setCustom( m_custom );
177     update();
178 }
179 
slotCustomTextChanged(const QString & text)180 void CustomLineEdit::slotCustomTextChanged( const QString &text )
181 {
182     Q_ASSERT( m_custom->type == UCustom_Str );
183 
184     free( m_custom->value->as_str );
185     m_custom->value->as_str = strdup( text.toUtf8().data() );
186 
187     setCustom( m_custom );
188 }
189 
190 //----------------------------------------------------------------------------------------
CustomPathnameEdit(struct uim_custom * c,QWidget * parent)191 CustomPathnameEdit::CustomPathnameEdit( struct uim_custom *c, QWidget *parent )
192     : QFrame( parent ),
193       UimCustomItemIface( c )
194 {
195     const char *button;
196 
197     m_lineEdit = new QLineEdit( this );
198     connect( m_lineEdit, SIGNAL(textChanged(const QString &)),
199                       this, SLOT(slotCustomTextChanged(const QString &)) );
200 
201     m_fileButton = new QPushButton( this );
202     /* Since both pathname type opens the file dialog to select an item rather
203      * than open it, the label should always be "Select..." here.  The type is
204      * obvious for uses even if the button label does not indicate
205      * it. Information about the action the button causes is more important.
206      *   -- YamaKen 2006-01-21 */
207     switch (m_custom->value->as_pathname->type) {
208     case UCustomPathnameType_Directory:
209         button = N_( "Select..." );
210         break;
211     case UCustomPathnameType_RegularFile:
212     default:
213         button = N_( "Select..." );
214         break;
215     }
216     m_fileButton->setText( mygettext(button) );
217     connect( m_fileButton, SIGNAL(clicked()),
218                       this, SLOT(slotPathnameButtonClicked()) );
219 
220     QHBoxLayout *layout = new QHBoxLayout;
221     layout->setMargin( 0 );
222     layout->setSpacing( 3 );
223     layout->addWidget( m_lineEdit );
224     layout->addWidget( m_fileButton );
225 
226     setLayout( layout );
227 
228     update();
229 }
230 
update()231 void CustomPathnameEdit::update()
232 {
233     if( !m_custom || m_custom->type != UCustom_Pathname )
234         return;
235 
236     m_lineEdit->setText( _FU8(m_custom->value->as_pathname->str) );
237 
238     /* sync with Label */
239     parentWidget()->setEnabled( m_custom->is_active );
240 }
241 
setDefault()242 void CustomPathnameEdit::setDefault()
243 {
244     free( m_custom->value->as_pathname->str );
245     m_custom->value->as_pathname->str = strdup( m_custom->default_value->as_pathname->str );
246     m_custom->value->as_pathname->type = m_custom->default_value->as_pathname->type;
247 
248     setCustom( m_custom );
249     update();
250 }
251 
slotPathnameButtonClicked()252 void CustomPathnameEdit::slotPathnameButtonClicked()
253 {
254     m_fileDialog = new QFileDialog( this, _("Specify file") );
255 
256     switch (m_custom->value->as_pathname->type) {
257     case UCustomPathnameType_Directory:
258         m_fileDialog->setFileMode( QFileDialog::Directory );
259         break;
260     case UCustomPathnameType_RegularFile:
261     default:
262          m_fileDialog->setFileMode( QFileDialog::ExistingFile );
263          break;
264     }
265     if ( m_fileDialog->exec() == QDialog::Accepted )
266     {
267         QString fileName = m_fileDialog->selectedFiles()[ 0 ];
268         m_lineEdit->setText( fileName );
269     }
270     delete m_fileDialog;
271 }
272 
slotCustomTextChanged(const QString & text)273 void CustomPathnameEdit::slotCustomTextChanged( const QString & text )
274 {
275     Q_ASSERT( m_custom->type == UCustom_Pathname );
276 
277     free( m_custom->value->as_pathname->str );
278     m_custom->value->as_pathname->str = strdup( text.toUtf8().data() );
279 
280     setCustom( m_custom );
281 }
282 
283 //----------------------------------------------------------------------------------------
CustomChoiceCombo(struct uim_custom * c,QWidget * parent)284 CustomChoiceCombo::CustomChoiceCombo( struct uim_custom *c, QWidget *parent )
285     : QComboBox( parent ),
286       UimCustomItemIface( c )
287 {
288     setEditable( false );
289     connect( this, SIGNAL(activated(int)),
290                       this, SLOT(slotActivated(int)) );
291 
292     update();
293 }
294 
update()295 void CustomChoiceCombo::update()
296 {
297     if( !m_custom || m_custom->type != UCustom_Choice )
298         return;
299 
300     clear();
301     char *default_symbol = m_custom->value->as_choice->symbol;
302     int default_index = -1;
303     int index = 0;
304     struct uim_custom_choice **item = m_custom->range->as_choice.valid_items;
305     while( *item )
306     {
307         int count = this->count();
308         insertItem( count, _FU8((*item)->label) ); // insert item at last
309 
310         if( QString::compare( default_symbol, (*item)->symbol ) == 0 )
311             default_index = index;
312 
313         index++;
314         item++;
315     }
316     setCurrentIndex( default_index );
317 
318     /* sync with Label */
319     parentWidget()->setEnabled( m_custom->is_active );
320 }
321 
setDefault()322 void CustomChoiceCombo::setDefault()
323 {
324     free( m_custom->value->as_choice->symbol );
325     free( m_custom->value->as_choice->label );
326     free( m_custom->value->as_choice->desc );
327 
328     m_custom->value->as_choice->symbol = strdup( m_custom->default_value->as_choice->symbol );
329     m_custom->value->as_choice->label  = strdup( m_custom->default_value->as_choice->label );
330     m_custom->value->as_choice->desc   = strdup( m_custom->default_value->as_choice->desc );
331 
332     setCustom( m_custom );
333     update();
334 }
335 
slotActivated(int index)336 void CustomChoiceCombo::slotActivated( int index )
337 {
338     Q_ASSERT( m_custom->type == UCustom_Choice );
339 
340     struct uim_custom_choice **valid_items = m_custom->range->as_choice.valid_items;
341     struct uim_custom_choice *choice = 0;
342     if( valid_items )
343     {
344         for( int i = 0; valid_items[i]; i++ )
345         {
346             if( i == index )
347                 choice = valid_items[i];
348         }
349     }
350 
351     free( m_custom->value->as_choice->symbol );
352     free( m_custom->value->as_choice->label );
353     free( m_custom->value->as_choice->desc );
354 
355     if ( choice ) {
356         m_custom->value->as_choice->symbol = strdup( choice->symbol );
357         m_custom->value->as_choice->label  = strdup( choice->label );
358         m_custom->value->as_choice->desc   = strdup( choice->desc );
359     } else {
360         m_custom->value->as_choice->symbol = strdup( "" );
361         m_custom->value->as_choice->label  = strdup( "" );
362         m_custom->value->as_choice->desc   = strdup( "" );
363     }
364 
365     setCustom( m_custom );
366 }
367 
368 //----------------------------------------------------------------------------------------
CustomOrderedListEdit(struct uim_custom * c,QWidget * parent)369 CustomOrderedListEdit::CustomOrderedListEdit( struct uim_custom *c, QWidget *parent )
370     : QFrame( parent ),
371       UimCustomItemIface( c )
372 {
373 
374     m_lineEdit = new QLineEdit( this );
375     m_lineEdit->setAttribute( Qt::WA_InputMethodEnabled, false );
376     m_lineEdit->setReadOnly( true );
377 
378     m_editButton = new QPushButton( this );
379     m_editButton->setText( _("Edit...") );
380     connect( m_editButton, SIGNAL(clicked()),
381                       this, SLOT(slotEditButtonClicked()) );
382 
383     QHBoxLayout *layout = new QHBoxLayout;
384     layout->setMargin( 0 );
385     layout->setSpacing( 3 );
386     layout->addWidget( m_lineEdit );
387     layout->addWidget( m_editButton );
388 
389     setLayout( layout );
390 
391     update();
392 }
393 
update()394 void CustomOrderedListEdit::update()
395 {
396     if( !m_custom || m_custom->type != UCustom_OrderedList )
397         return;
398 
399     updateText();
400 
401     /* sync with Label */
402     parentWidget()->setEnabled( m_custom->is_active );
403 }
404 
setDefault()405 void CustomOrderedListEdit::setDefault()
406 {
407     /* free old items */
408     int num = 0;
409     for( num = 0; m_custom->value->as_olist[num]; num++ )
410         ;
411 
412     for( int i = 0; i < num; i++ )
413     {
414         free( m_custom->value->as_olist[i]->symbol );
415         free( m_custom->value->as_olist[i]->label );
416         free( m_custom->value->as_olist[i]->desc );
417         free( m_custom->value->as_olist[i] );
418     }
419 
420     /* copy default_value to value */
421     int default_num = 0;
422     for( default_num = 0; m_custom->default_value->as_olist[default_num]; default_num++ )
423         ;
424 
425     m_custom->value->as_olist = (struct uim_custom_choice **)realloc( m_custom->value->as_olist,
426                                                                       sizeof(struct uim_custom_choice *) * (default_num + 1) );
427 
428     for( int i = 0; i < default_num; i++ )
429     {
430         struct uim_custom_choice *default_item = m_custom->default_value->as_olist[i];
431         struct uim_custom_choice *item = (struct uim_custom_choice *)malloc(sizeof(struct uim_custom_choice));
432 
433         item->symbol = default_item->symbol ? strdup(default_item->symbol) : 0;
434         item->label  = default_item->label  ? strdup(default_item->label)  : 0;
435         item->desc   = default_item->desc   ? strdup(default_item->desc)   : 0;
436 
437         m_custom->value->as_olist[i] = item;
438     }
439     m_custom->value->as_olist[default_num] = 0; /* NULL-terminated */
440 
441     setCustom( m_custom );
442     initPtrList();
443     update();
444 }
445 
initPtrList()446 void CustomOrderedListEdit::initPtrList()
447 {
448     m_itemList.clear();
449     m_validItemList.clear();
450 
451     if( m_custom->value->as_olist )
452     {
453         struct uim_custom_choice *item = 0;
454         int i = 0;
455         for( item = m_custom->value->as_olist[0], i = 0;
456              item;
457              item = m_custom->value->as_olist[++i] )
458         {
459             m_itemList.append( item );
460         }
461     }
462 
463     if( m_custom->value->as_olist && m_custom->range->as_olist.valid_items )
464     {
465         struct uim_custom_choice *item = 0;
466         int i = 0;
467         for( item = m_custom->range->as_olist.valid_items[0], i = 0;
468              item;
469              item = m_custom->range->as_olist.valid_items[++i] )
470         {
471             m_validItemList.append( item );
472         }
473     }
474 }
475 
slotEditButtonClicked()476 void CustomOrderedListEdit::slotEditButtonClicked()
477 {
478     OListEditForm *d = new OListEditForm( this );
479     d->setWindowTitle( _FU8( m_custom->label ) );
480     initPtrList();
481 
482     /*
483      * Adding Enabled Items
484      */
485     foreach( const struct uim_custom_choice *item, m_itemList )
486     {
487         d->addCheckItem( true, _FU8(item->label) );
488     }
489     /*
490      * Adding Disabled Items
491      */
492     foreach ( const struct uim_custom_choice *valid_item, m_validItemList )
493     {
494         /* Exclude Enabled Item */
495         bool isActive = false;
496         foreach ( const struct uim_custom_choice *item, m_itemList )
497         {
498             if( QString::compare( valid_item->symbol, item->symbol ) == 0 )
499             {
500                 isActive = true;
501                 break;
502             }
503         }
504 
505         if( isActive == false )
506         {
507             d->addCheckItem( false, _FU8(valid_item->label) );
508         }
509     }
510 
511     /* Exec Dialog */
512     if( d->exec() == OListEditForm::Accepted )
513     {
514         /* search active item's ptr, realloc it, and store in activeItemList */
515         QList<struct uim_custom_choice *> activeItemList;
516 
517         QStringList activeItemLabelList = d->activeItemLabels();
518         for( int i = 0; i < activeItemLabelList.count(); i++ )
519         {
520             struct uim_custom_choice *item = 0;
521             int j = 0;
522             for( item = m_custom->range->as_olist.valid_items[0], j = 0;
523                  item;
524                  item = m_custom->range->as_olist.valid_items[++j] )
525             {
526                 if( QString::compare( activeItemLabelList[i], _FU8(item->label) ) == 0 )
527                 {
528                     /* allocate new struct because we will free the old struct */
529                     struct uim_custom_choice *activeItem = (struct uim_custom_choice *)malloc(sizeof(struct uim_custom_choice));
530                     activeItem->symbol = item->symbol ? strdup(item->symbol) : 0;
531                     activeItem->label  = item->label  ? strdup(item->label)  : 0;
532                     activeItem->desc   = item->desc   ? strdup(item->desc)   : 0;
533                     activeItemList.append( activeItem );
534                     break;
535                 }
536             }
537         }
538 
539         /* free old items */
540         for( int i = 0; i < m_itemList.count(); i++ )
541         {
542             free( m_custom->value->as_olist[i]->symbol );
543             free( m_custom->value->as_olist[i]->label );
544             free( m_custom->value->as_olist[i]->desc );
545             free( m_custom->value->as_olist[i] );
546         }
547 
548         /* create null-terminated new olist */
549         m_custom->value->as_olist = (struct uim_custom_choice **)realloc( m_custom->value->as_olist,
550                                                                          sizeof(struct uim_custom_choice *) * (activeItemList.count() + 1) );
551         for( int i = 0; i < activeItemList.count(); i++ )
552         {
553             m_custom->value->as_olist[i] = activeItemList.at(i);
554         }
555         m_custom->value->as_olist[activeItemList.count()] = 0;
556 
557         /* save */
558         setCustom( m_custom );
559 
560         /* reload */
561         update();
562     }
563 
564     delete d;
565 }
566 
updateText()567 void CustomOrderedListEdit::updateText()
568 {
569     QString str;
570     if( m_custom->value->as_olist )
571     {
572         struct uim_custom_choice *item = 0;
573         int i = 0;
574         for( item = m_custom->value->as_olist[0], i = 0;
575              item;
576              item = m_custom->value->as_olist[++i] )
577         {
578             if( i != 0 )
579                 str.append(", ");
580             str.append( _FU8(item->label) );
581         }
582     }
583     m_lineEdit->setText( str );
584 }
585 
OListEditForm(QWidget * parent)586 OListEditForm::OListEditForm( QWidget *parent ) : OListEditFormBase( parent )
587 {
588     m_listView->setRootIsDecorated( false );
589     connect( m_upButton, SIGNAL(clicked()),
590                       this, SLOT(upItem()) );
591     connect( m_downButton, SIGNAL(clicked()),
592                       this, SLOT(downItem()) );
593 }
594 
~OListEditForm()595 OListEditForm::~OListEditForm()
596 {
597 }
598 
addCheckItem(bool isActive,const QString & str)599 void OListEditForm::addCheckItem( bool isActive, const QString &str )
600 {
601     QTreeWidgetItem *item = new QTreeWidgetItem( QStringList() << str );
602     m_listView->addTopLevelItem( item );
603 
604     if( item )
605         item->setCheckState( 0, isActive ? Qt::Checked : Qt::Unchecked );
606 }
607 
upItem()608 void OListEditForm::upItem()
609 {
610     QList<QTreeWidgetItem *> items = m_listView->selectedItems();
611     if ( items.isEmpty() )
612         return;
613     QTreeWidgetItem *item = items[ 0 ];
614     int index = m_listView->indexOfTopLevelItem( item );
615     if ( index == 0 )
616         return;
617     m_listView->takeTopLevelItem( index );
618     m_listView->insertTopLevelItem ( index - 1, item );
619     m_listView->setCurrentItem( item );
620 }
621 
downItem()622 void OListEditForm::downItem()
623 {
624     QList<QTreeWidgetItem *> items = m_listView->selectedItems();
625     if ( items.isEmpty() )
626         return;
627     QTreeWidgetItem *item = items[ 0 ];
628     int index = m_listView->indexOfTopLevelItem( item );
629     if ( index == m_listView->topLevelItemCount() - 1 )
630         return;
631     m_listView->takeTopLevelItem( index );
632     m_listView->insertTopLevelItem ( index + 1, item );
633     m_listView->setCurrentItem( item );
634 }
635 
activeItemLabels() const636 QStringList OListEditForm::activeItemLabels() const
637 {
638     QStringList activeItemLabelList;
639     for ( int i = 0; i < m_listView->topLevelItemCount(); i++)
640     {
641         QTreeWidgetItem *item = m_listView->topLevelItem( i );
642         if ( item->checkState( 0 ) == Qt::Checked )
643             activeItemLabelList << item->text ( 0 );
644     }
645     return activeItemLabelList;
646 }
647 
648 //----------------------------------------------------------------------------------------
CustomKeyEdit(struct uim_custom * c,QWidget * parent)649 CustomKeyEdit::CustomKeyEdit( struct uim_custom *c, QWidget *parent )
650     : QFrame( parent ),
651       UimCustomItemIface( c )
652 {
653     m_lineEdit = new QLineEdit( this );
654     m_lineEdit->setAttribute( Qt::WA_InputMethodEnabled, false );
655     m_lineEdit->setReadOnly( true );
656 
657     m_editButton = new QPushButton( this );
658     m_editButton->setText( _("Edit...") );
659     connect( m_editButton, SIGNAL(clicked()),
660                       this, SLOT(slotKeyButtonClicked()) );
661 
662     QHBoxLayout *layout = new QHBoxLayout;
663     layout->setMargin( 0 );
664     layout->setSpacing( 3 );
665     layout->addWidget( m_lineEdit );
666     layout->addWidget( m_editButton );
667 
668     setLayout( layout );
669 
670     update();
671 }
672 
update()673 void CustomKeyEdit::update()
674 {
675     if( !m_custom || m_custom->type != UCustom_Key )
676         return;
677 
678     updateText();
679 
680     /* sync with Label */
681     parentWidget()->setEnabled( m_custom->is_active );
682 }
683 
updateText()684 void CustomKeyEdit::updateText()
685 {
686     QString str;
687     if (m_custom->value->as_key) {
688         struct uim_custom_key *key = 0;
689         int i = 0;
690         for (key = m_custom->value->as_key[0], i = 0;
691              key;
692              key = m_custom->value->as_key[++i])
693         {
694             if( i != 0 )
695                 str.append(", ");
696             str.append( key->literal );
697         }
698     } else {
699         /* error message */
700     }
701     m_lineEdit->setText( str );
702 }
703 
704 
setDefault()705 void CustomKeyEdit::setDefault()
706 {
707     /* free old items */
708     int num = 0;
709     for( num = 0; m_custom->value->as_key[num]; num++ )
710         ;
711 
712     for( int i = 0; i < num; i++ )
713     {
714         free( m_custom->value->as_key[i]->literal );
715         free( m_custom->value->as_key[i]->label );
716         free( m_custom->value->as_key[i]->desc );
717         free( m_custom->value->as_key[i] );
718     }
719 
720     /* copy default_value to value */
721     int default_num = 0;
722     for( default_num = 0; m_custom->default_value->as_key[default_num]; default_num++ )
723         ;
724 
725     m_custom->value->as_key = (struct uim_custom_key **)realloc( m_custom->value->as_key,
726                                                                  sizeof(struct uim_custom_key *) * (default_num + 1) );
727 
728     for( int i = 0; i < default_num; i++ )
729     {
730         struct uim_custom_key *default_item = m_custom->default_value->as_key[i];
731         struct uim_custom_key *item = (struct uim_custom_key *)malloc(sizeof(struct uim_custom_key));
732 
733         item->type        = default_item->type;
734         item->editor_type = default_item->editor_type;
735         item->literal     = default_item->literal ? strdup(default_item->literal) : 0;
736         item->label       = default_item->label   ? strdup(default_item->label)   : 0;
737         item->desc        = default_item->desc    ? strdup(default_item->desc)    : 0;
738 
739         m_custom->value->as_key[i] = item;
740     }
741     m_custom->value->as_key[default_num] = 0; /* NULL-terminated */
742 
743     setCustom( m_custom );
744     update();
745 }
746 
slotKeyButtonClicked()747 void CustomKeyEdit::slotKeyButtonClicked()
748 {
749     KeyEditForm *d = new KeyEditForm( this );
750     d->setWindowTitle(
751             _( "%1 - key configuration" ).arg( _FU8( m_custom->label ) ) );
752 
753     /* add items */
754     QString str;
755     if (m_custom->value->as_key) {
756         struct uim_custom_key *key = 0;
757         int i = 0;
758         for (key = m_custom->value->as_key[0], i = 0;
759              key;
760              key = m_custom->value->as_key[++i])
761         {
762             d->addKeyItem( key->literal );
763         }
764     }
765 
766     if( d->exec() == KeyEditForm::Accepted )
767     {
768         const QStringList keyStrList = d->getKeyStrList();
769 
770         /* free old items */
771         int num = 0;
772         for( num = 0; m_custom->value->as_key[num]; num++ )
773             ;
774 
775         for( int i = 0; i < num; i++ )
776         {
777             free( m_custom->value->as_key[i]->literal );
778             free( m_custom->value->as_key[i]->label );
779             free( m_custom->value->as_key[i]->desc );
780             free( m_custom->value->as_key[i] );
781         }
782 
783 
784         /* add new items */
785         num = keyStrList.count();
786         m_custom->value->as_key = (struct uim_custom_key **)realloc( m_custom->value->as_key,
787                                                                      sizeof(struct uim_custom_key *) * (num + 1) );
788 
789         for( int i = 0; i < num; i++ )
790         {
791             const char *keystr = keyStrList[i].toLatin1().data();
792 
793             struct uim_custom_key *item = (struct uim_custom_key *)malloc(sizeof(struct uim_custom_key));
794             item->type        = UCustomKey_Regular;
795             item->editor_type = UCustomKeyEditor_Basic;
796             item->literal     = strdup( keystr );
797             item->label       = strdup( "" );
798             item->desc        = strdup( "" );
799 
800             m_custom->value->as_key[i] = item;
801         }
802         m_custom->value->as_key[num] = 0;
803 
804         setCustom( m_custom );
805         update();
806     }
807 
808     delete d;
809 }
810 
KeyEditForm(QWidget * parent)811 KeyEditForm::KeyEditForm( QWidget *parent ) : KeyEditFormBase( parent )
812 {
813     m_listView->setRootIsDecorated( false );
814     m_removeButton->setEnabled( false );
815     m_editButton->setEnabled( false );
816 
817     connect( m_addButton, SIGNAL(clicked()),
818                       this, SLOT(slotAddClicked()) );
819     connect( m_removeButton, SIGNAL(clicked()),
820                       this, SLOT(slotRemoveClicked()) );
821     connect( m_editButton, SIGNAL(clicked()),
822                       this, SLOT(slotEditClicked()) );
823 
824     connect( m_listView, SIGNAL(itemSelectionChanged()),
825                       this, SLOT(slotItemSelectionChanged()) );
826 }
827 
~KeyEditForm()828 KeyEditForm::~KeyEditForm()
829 {
830 }
831 
addKeyItem(const QString & str)832 void KeyEditForm::addKeyItem( const QString &str )
833 {
834     QTreeWidgetItem *item = new QTreeWidgetItem( QStringList() << str );
835     m_listView->addTopLevelItem( item );
836 }
837 
getKeyStrList()838 const QStringList KeyEditForm::getKeyStrList()
839 {
840     QStringList keyStrList;
841     for ( int i = 0; i < m_listView->topLevelItemCount(); i++)
842     {
843         keyStrList << m_listView->topLevelItem( i )->text ( 0 );
844     }
845     return keyStrList;
846 }
847 
slotAddClicked()848 void KeyEditForm::slotAddClicked()
849 {
850     QPointer<KeyGrabDialog> d = new KeyGrabDialog( this );
851     if( d->exec() == KeyGrabDialog::Accepted )
852     {
853         QString keystr = d->getKeyStr();
854         if( !keystr.isEmpty() )
855         {
856             addKeyItem( keystr );
857         }
858     }
859     delete d;
860 }
861 
slotRemoveClicked()862 void KeyEditForm::slotRemoveClicked()
863 {
864     QList<QTreeWidgetItem *> selectedItems = m_listView->selectedItems();
865     if( !selectedItems.isEmpty() )
866     {
867         m_listView->takeTopLevelItem(
868             m_listView->indexOfTopLevelItem( selectedItems[ 0 ] ) );
869     }
870 }
871 
slotEditClicked()872 void KeyEditForm::slotEditClicked()
873 {
874     QList<QTreeWidgetItem *> selectedItems = m_listView->selectedItems();
875     if( selectedItems.isEmpty() )
876         return;
877     QPointer<KeyGrabDialog> d = new KeyGrabDialog( this );
878     if( d->exec() == KeyGrabDialog::Accepted )
879     {
880         QString keystr = d->getKeyStr();
881         if( !keystr.isEmpty() )
882         {
883             selectedItems[ 0 ]->setText( 0, keystr );
884         }
885     }
886     delete d;
887 }
888 
slotItemSelectionChanged()889 void KeyEditForm::slotItemSelectionChanged()
890 {
891     QList<QTreeWidgetItem *> selectedItems = m_listView->selectedItems();
892     if( !selectedItems.isEmpty() )
893     {
894         m_removeButton->setEnabled( true );
895         m_editButton->setEnabled( true );
896     }
897     else
898     {
899         m_removeButton->setEnabled( false );
900         m_editButton->setEnabled( false );
901     }
902 }
903 
KeyGrabDialog(QWidget * parent)904 KeyGrabDialog::KeyGrabDialog( QWidget *parent )
905     : QDialog( parent ),
906       pressed_keyval( 0 ),
907       pressed_keystate( Qt::NoModifier ),
908       pressed_unichar ( 0 )
909 {
910     QLabel *l = new QLabel( _("Press keys to grab (e.g. <Control>a)"), this );
911 
912     QVBoxLayout *vboxLayout = new QVBoxLayout( this );
913     vboxLayout->addWidget( l );
914 
915     setWindowTitle( _("Key Grab Dialog") );
916 }
917 
keyPressEvent(QKeyEvent * e)918 void KeyGrabDialog::keyPressEvent( QKeyEvent *e )
919 {
920     pressed_keyval = e->key();
921     pressed_keystate = e->modifiers();
922     pressed_unichar = e->text().at(0);
923 }
924 
keyReleaseEvent(QKeyEvent * e)925 void KeyGrabDialog::keyReleaseEvent( QKeyEvent *e )
926 {
927     Q_UNUSED( e )
928     // create keystr
929     setKeyStr();
930 
931     // end this dialog
932     accept();
933 }
934 
setKeyStr()935 void KeyGrabDialog::setKeyStr()
936 {
937     QString keystr;
938     int keyval = pressed_keyval;
939     Qt::KeyboardModifiers mod = pressed_keystate;
940 
941     /*
942      * Ignore Shift modifier for printable char keys for
943      * easy-to-recognize key configuration.  uim-custom performs
944      * implicit shift key encoding/decoding appropriately.
945      */
946     if( ((keyval >= 256) || !isgraph(keyval)) &&
947         (mod & Qt::ShiftModifier) )
948         keystr += "<Shift>";
949     if( mod & Qt::ControlModifier )
950         keystr += "<Control>";
951     if( mod & Qt::AltModifier )
952         keystr += "<Alt>";
953     if( mod & Qt::MetaModifier )
954         keystr += "<Meta>";
955 
956     switch( keyval ) {
957     case Qt::Key_Space:
958         keystr += "space";
959         break;
960     case Qt::Key_Backspace:
961         keystr += "backspace";
962         break;
963     case Qt::Key_Delete:
964         keystr += "delete";
965         break;
966     case Qt::Key_Insert:
967         keystr += "insert";
968         break;
969     case Qt::Key_Escape:
970         keystr += "escape";
971         break;
972     case Qt::Key_Tab:
973         keystr += "tab";
974         break;
975     case Qt::Key_Return:
976         keystr += "return";
977         break;
978     case Qt::Key_Left:
979         keystr += "left";
980         break;
981     case Qt::Key_Up:
982         keystr += "up";
983         break;
984     case Qt::Key_Right:
985         keystr += "right";
986         break;
987     case Qt::Key_Down:
988         keystr += "down";
989         break;
990     case Qt::Key_PageUp:
991         keystr += "prior";
992         break;
993     case Qt::Key_PageDown:
994         keystr += "next";
995         break;
996     case Qt::Key_Home:
997         keystr += "home";
998         break;
999     case Qt::Key_End:
1000         keystr += "end";
1001         break;
1002 #ifdef QT4_IMMODULE
1003     case Qt::Key_Multi_key:
1004         keystr += "Multi_key";
1005         break;
1006     case Qt::Key_Codeinput:
1007         keystr += "codeinput";
1008         break;
1009     case Qt::Key_SingleCandidate:
1010         keystr += "single-candidate";
1011         break;
1012     case Qt::Key_MultipleCandidate:
1013         keystr += "multiple-candidate";
1014         break;
1015     case Qt::Key_PreviousCandidate:
1016         keystr += "previous-candidate";
1017         break;
1018     case Qt::Key_Mode_switch:
1019         keystr += "Mode_switch";
1020         break;
1021     case Qt::Key_Kanji:
1022         keystr += "Kanji";
1023         break;
1024     case Qt::Key_Muhenkan:
1025         keystr += "Muhenkan";
1026         break;
1027     case Qt::Key_Henkan:
1028         keystr += "Henkan_Mode";
1029         break;
1030     case Qt::Key_Romaji:
1031         keystr += "romaji";
1032         break;
1033     case Qt::Key_Hiragana:
1034         keystr += "hiragana";
1035         break;
1036     case Qt::Key_Katakana:
1037         keystr += "katakana";
1038         break;
1039     case Qt::Key_Hiragana_Katakana:
1040         keystr += "hiragana-katakana";
1041         break;
1042     case Qt::Key_Zenkaku:
1043         keystr += "zenkaku";
1044         break;
1045     case Qt::Key_Hankaku:
1046         keystr += "hankaku";
1047         break;
1048     case Qt::Key_Zenkaku_Hankaku:
1049         keystr += "zenkaku-hankaku";
1050         break;
1051     case Qt::Key_Touroku:
1052         keystr += "touroku";
1053         break;
1054     case Qt::Key_Massyo:
1055         keystr += "massyo";
1056         break;
1057     case Qt::Key_Kana_Lock:
1058         keystr += "kana-lock";
1059         break;
1060     case Qt::Key_Kana_Shift:
1061         keystr += "kana-shift";
1062         break;
1063     case Qt::Key_Eisu_Shift:
1064         keystr += "eisu-shift";
1065         break;
1066     case Qt::Key_Eisu_toggle:
1067         keystr += "eisu-toggle";
1068         break;
1069     case Qt::Key_Hangul:
1070         keystr += "hangul";
1071         break;
1072     case Qt::Key_Hangul_Start:
1073         keystr += "hangul-start";
1074         break;
1075     case Qt::Key_Hangul_End:
1076         keystr += "hangul-end";
1077         break;
1078     case Qt::Key_Hangul_Hanja:
1079         keystr += "hangul-hanja";
1080         break;
1081     case Qt::Key_Hangul_Jamo:
1082         keystr += "hangul-jamo";
1083         break;
1084     case Qt::Key_Hangul_Romaja:
1085         keystr += "hangul-romaja";
1086         break;
1087     case Qt::Key_Hangul_Jeonja:
1088         keystr += "hangul-jeonja";
1089         break;
1090     case Qt::Key_Hangul_Banja:
1091         keystr += "hangul-banja";
1092         break;
1093     case Qt::Key_Hangul_PreHanja:
1094         keystr += "hangul-prehanja";
1095         break;
1096     case Qt::Key_Hangul_PostHanja:
1097         keystr += "hangul-prosthanja";
1098         break;
1099     case Qt::Key_Hangul_Special:
1100         keystr += "hangul-special";
1101         break;
1102     case Qt::Key_Dead_Grave:
1103         keystr += "dead-grave";
1104         break;
1105     case Qt::Key_Dead_Acute:
1106         keystr += "dead-acute";
1107         break;
1108     case Qt::Key_Dead_Circumflex:
1109         keystr += "dead-circumflex";
1110         break;
1111     case Qt::Key_Dead_Tilde:
1112         keystr += "dead-tilde";
1113         break;
1114     case Qt::Key_Dead_Macron:
1115         keystr += "dead-macron";
1116         break;
1117     case Qt::Key_Dead_Breve:
1118         keystr += "dead-breve";
1119         break;
1120     case Qt::Key_Dead_Abovedot:
1121         keystr += "dead-abovedot";
1122         break;
1123     case Qt::Key_Dead_Diaeresis:
1124         keystr += "dead-diaeresis";
1125         break;
1126     case Qt::Key_Dead_Abovering:
1127         keystr += "dead-abovering";
1128         break;
1129     case Qt::Key_Dead_Doubleacute:
1130         keystr += "dead-doubleacute";
1131         break;
1132     case Qt::Key_Dead_Caron:
1133         keystr += "dead-caron";
1134         break;
1135     case Qt::Key_Dead_Cedilla:
1136         keystr += "dead-cedilla";
1137         break;
1138     case Qt::Key_Dead_Ogonek:
1139         keystr += "dead-ogonek";
1140         break;
1141     case Qt::Key_Dead_Iota:
1142         keystr += "dead-iota";
1143         break;
1144     case Qt::Key_Dead_Voiced_Sound:
1145         keystr += "dead-voiced-sound";
1146         break;
1147     case Qt::Key_Dead_Semivoiced_Sound:
1148         keystr += "dead-semivoiced-sound";
1149         break;
1150     case Qt::Key_Dead_Belowdot:
1151         keystr += "dead-belowdot";
1152         break;
1153     case Qt::Key_Dead_Hook:
1154         keystr += "dead-hook";
1155         break;
1156     case Qt::Key_Dead_Horn:
1157         keystr += "dead-horn";
1158         break;
1159 #endif /* Def: QT4_IMMODULE */
1160     case Qt::Key_Shift:
1161         keystr += "Shift_key";
1162         break;
1163     case Qt::Key_Control:
1164         keystr += "Control_key";
1165         break;
1166     case Qt::Key_Alt:
1167         keystr += "Alt_key";
1168         break;
1169     case Qt::Key_Meta:
1170         keystr += "Meta_key";
1171         break;
1172     case Qt::Key_Super_L:
1173     case Qt::Key_Super_R:
1174         keystr += "Super_key";
1175         break;
1176     case Qt::Key_Hyper_L:
1177     case Qt::Key_Hyper_R:
1178         keystr += "Hyper_key";
1179         break;
1180     case Qt::Key_CapsLock:
1181         keystr += "caps-lock";
1182         break;
1183     case Qt::Key_NumLock:
1184         keystr += "num-lock";
1185         break;
1186     case Qt::Key_ScrollLock:
1187         keystr += "scroll-lock";
1188         break;
1189     case Qt::Key_unknown:
1190         keystr += unicodeKeyToSymStr ( pressed_unichar );
1191         break;
1192     default:
1193         if( keyval >= Qt::Key_F1 && keyval <= Qt::Key_F35 )
1194         {
1195             keystr += 'F' + QString::number( keyval - Qt::Key_F1 + 1 );
1196             break;
1197         }
1198         else if( keyval < 256 )
1199         {
1200             QChar ch = QChar( keyval );
1201 
1202             if( mod & Qt::ShiftModifier )
1203                 ch = ch.toUpper();
1204             else
1205                 ch = ch.toLower();
1206 
1207             keystr += ch;
1208         }
1209     }
1210 
1211     m_keystr = keystr;
1212 
1213 }
1214 
1215 //----------------------------------------------------------------------------------------
CustomTable(struct uim_custom * c,QWidget * parent)1216 CustomTable::CustomTable( struct uim_custom *c, QWidget *parent )
1217     : QFrame( parent ),
1218       UimCustomItemIface( c )
1219 {
1220     QPushButton *editButton = new QPushButton;
1221     editButton->setText( _("Edit...") );
1222     connect( editButton, SIGNAL(clicked()),
1223             this, SLOT(slotEditButtonClicked()) );
1224 
1225     QHBoxLayout *layout = new QHBoxLayout;
1226     layout->setMargin( 0 );
1227     layout->setSpacing( 3 );
1228     layout->addStretch();
1229     layout->addWidget( editButton );
1230 
1231     setLayout( layout );
1232 
1233     update();
1234 }
1235 
update()1236 void CustomTable::update()
1237 {
1238     if( !m_custom || m_custom->type != UCustom_Table )
1239         return;
1240     /* sync with Label */
1241     parentWidget()->setEnabled( m_custom->is_active );
1242 }
1243 
setDefault()1244 void CustomTable::setDefault()
1245 {
1246     char ***custom_table = m_custom->value->as_table;
1247     for ( int row = 0; custom_table[row]; row++ ) {
1248         for ( int column = 0; custom_table[row][column]; column++ ) {
1249             free( custom_table[row][column] );
1250         }
1251         free( custom_table[row] );
1252     }
1253     char ***default_table = m_custom->default_value->as_table;
1254     int row;
1255     for ( row = 0; default_table[row]; row++ )
1256         ;
1257     custom_table = (char ***)malloc( sizeof(char **) * ( row + 1 ) );
1258     custom_table[row] = 0;
1259 
1260     m_custom->value->as_table = custom_table;
1261 
1262     for ( int row = 0; default_table[row]; row++ ) {
1263         int column;
1264         // the number of column may differ from row to row
1265         for ( column = 0; default_table[row][column]; column++ )
1266             ;
1267         custom_table[row] = (char **)malloc( sizeof(char *) * ( column + 1 ) );
1268         custom_table[row][column] = 0;
1269         for ( int column = 0; default_table[row][column]; column++ )
1270             custom_table[row][column] = strdup( default_table[row][column] );
1271     }
1272 
1273     setCustom( m_custom );
1274     update();
1275 }
1276 
slotEditButtonClicked()1277 void CustomTable::slotEditButtonClicked()
1278 {
1279     QPointer<TableEditForm> d = new TableEditForm( this );
1280     d->setWindowTitle( _FU8( m_custom->label ) );
1281     d->setTable( m_custom->value->as_table );
1282     int column = 0;
1283     for ( struct uim_custom_choice **item
1284             = m_custom->range->as_table_header.valid_items;
1285             *item; item++ ) {
1286         d->setTableHeaderItem( _FU8( ( *item )->label ), column );
1287         column++;
1288     }
1289     if ( d->exec() == QDialog::Accepted ) {
1290         m_custom->value->as_table = d->table();
1291         setCustom( m_custom );
1292         update();
1293     }
1294     delete d;
1295 }
1296 
TableEditForm(QWidget * parent)1297 TableEditForm::TableEditForm( QWidget *parent )
1298     : QDialog( parent )
1299 {
1300     m_table = new QTableWidget;
1301     m_table->setSelectionMode( QAbstractItemView::SingleSelection );
1302     QHeaderView *verticalHeader = m_table->verticalHeader();
1303     verticalHeader->setVisible( false );
1304     verticalHeader->setDefaultSectionSize(
1305             QFontMetrics( m_table->font() ).height() + 2 );
1306     QHeaderView *horizontalHeader = m_table->horizontalHeader();
1307 #if QT_VERSION < 0x050000
1308     horizontalHeader->setResizeMode( QHeaderView::ResizeToContents );
1309 #else
1310     horizontalHeader->setSectionResizeMode( QHeaderView::ResizeToContents );
1311 #endif
1312     horizontalHeader->setStretchLastSection( true );
1313     connect( m_table, SIGNAL( itemSelectionChanged() ),
1314             this, SLOT( slotItemSelectionChanged() ) );
1315 
1316     QPushButton *addButton = new QPushButton;
1317     addButton->setText( _("Add") );
1318     connect( addButton, SIGNAL( clicked() ),
1319             this, SLOT( slotAddClicked() ) );
1320 
1321     m_removeButton = new QPushButton;
1322     m_removeButton->setEnabled( false );
1323     m_removeButton->setText( _("Remove") );
1324     connect( m_removeButton, SIGNAL( clicked() ),
1325             this, SLOT( slotRemoveClicked() ) );
1326 
1327     m_upButton = new QPushButton;
1328     m_upButton->setEnabled( false );
1329     m_upButton->setText( _("Up") );
1330     connect( m_upButton, SIGNAL( clicked() ),
1331             this, SLOT( slotUpClicked() ) );
1332 
1333     m_downButton = new QPushButton;
1334     m_downButton->setEnabled( false );
1335     m_downButton->setText( _("Down") );
1336     connect( m_downButton, SIGNAL( clicked() ),
1337             this, SLOT( slotDownClicked() ) );
1338 
1339     QPushButton *okButton = new QPushButton;
1340     okButton->setText( _("OK") );
1341     connect( okButton, SIGNAL( clicked() ), this, SLOT( accept() ) );
1342 
1343     QPushButton *cancelButton = new QPushButton;
1344     cancelButton->setText( _("Cancel") );
1345     connect( cancelButton, SIGNAL( clicked() ), this, SLOT( reject() ) );
1346 
1347     QVBoxLayout *buttonLayout = new QVBoxLayout;
1348     buttonLayout->addWidget( addButton );
1349     buttonLayout->addWidget( m_removeButton );
1350     buttonLayout->addWidget( m_upButton );
1351     buttonLayout->addWidget( m_downButton );
1352     buttonLayout->addStretch();
1353     buttonLayout->addWidget( okButton );
1354     buttonLayout->addWidget( cancelButton );
1355 
1356     QHBoxLayout *layout = new QHBoxLayout;
1357     layout->addWidget( m_table );
1358     layout->addLayout( buttonLayout );
1359 
1360     setLayout( layout );
1361 
1362     m_table->horizontalHeader()->adjustSize();
1363 }
1364 
setTable(char *** custom_table)1365 void TableEditForm::setTable( char ***custom_table )
1366 {
1367     if ( !custom_table )
1368         return;
1369     // the number of column may differ from row to row
1370     int max_column = -1;
1371     int row;
1372     for ( row = 0; custom_table[row]; row++ ) {
1373         for ( int column = 0; custom_table[row][column]; column++ ) {
1374             if ( max_column < column )
1375                 max_column = column;
1376         }
1377     }
1378     m_table->setRowCount( row );
1379     m_table->setColumnCount( max_column + 1 );
1380 
1381     for ( int row = 0; custom_table[row]; row++ ) {
1382         bool expanded = false;
1383         for ( int column = 0; column < max_column + 1; column++ ) {
1384             if ( !custom_table[row][column] )
1385                 expanded = true;
1386             QTableWidgetItem *item = new QTableWidgetItem( expanded ?
1387                 "" : _FU8( custom_table[row][column] ) );
1388             if ( expanded )
1389                 item->setFlags( Qt::NoItemFlags );
1390             m_table->setItem( row, column, item );
1391         }
1392     }
1393     m_customTable = custom_table;
1394 }
1395 
table() const1396 char ***TableEditForm::table() const
1397 {
1398     char ***custom_table = m_customTable;
1399     for ( int row = 0; custom_table[row]; row++ ) {
1400         for ( int column = 0; custom_table[row][column]; column++ ) {
1401             free( custom_table[row][column] );
1402         }
1403         free( custom_table[row] );
1404     }
1405 
1406     int rowCount = m_table->rowCount();
1407     custom_table = (char ***)malloc( sizeof(char **) * ( rowCount + 1 ) );
1408     custom_table[rowCount] = 0;
1409 
1410     int columnCount = m_table->columnCount();
1411 
1412     for ( int row = 0; row < rowCount; row++ ) {
1413         int columnCountForRow = columnCount;
1414         // the number of column may differ from row to row
1415         for ( int column = 0; column < columnCount; column++ ) {
1416             if ( !( m_table->item( row, column )->flags() ) ) {
1417                 columnCountForRow = column;
1418                 break;
1419             }
1420         }
1421         custom_table[row]
1422             = (char **)malloc( sizeof(char *) * ( columnCountForRow + 1 ) );
1423         custom_table[row][columnCountForRow] = 0;
1424         for ( int column = 0; column < columnCountForRow; column++ )
1425             custom_table[row][column] = strdup(
1426                 m_table->item( row, column )->text().toUtf8().data() );
1427     }
1428 
1429     return custom_table;
1430 }
1431 
setTableHeaderItem(const QString & item,int column)1432 void TableEditForm::setTableHeaderItem( const QString &item, int column )
1433 {
1434     if ( column < m_table->columnCount() ) {
1435         m_table->setHorizontalHeaderItem( column,
1436                 new QTableWidgetItem( item ) );
1437     }
1438 }
1439 
slotItemSelectionChanged()1440 void TableEditForm::slotItemSelectionChanged()
1441 {
1442     bool itemSelected = ( m_table->selectedItems().count() == 1 );
1443     m_removeButton->setEnabled( itemSelected );
1444     m_upButton->setEnabled( itemSelected );
1445     m_downButton->setEnabled( itemSelected );
1446 }
1447 
slotAddClicked()1448 void TableEditForm::slotAddClicked()
1449 {
1450     QList<QTableWidgetItem *> items = m_table->selectedItems();
1451     int row = ( items.count() > 0 ) ? items[0]->row() + 1 : m_table->rowCount();
1452     m_table->insertRow( row );
1453     for ( int i = 0; i < m_table->columnCount(); i++ )
1454         m_table->setItem( row, i, new QTableWidgetItem( "" ) );
1455     m_table->scrollToItem( m_table->item( row, 0 ) );
1456 }
1457 
slotRemoveClicked()1458 void TableEditForm::slotRemoveClicked()
1459 {
1460     QList<QTableWidgetItem *> items = m_table->selectedItems();
1461     if ( items.count() != 1 )
1462         return;
1463     m_table->removeRow( items[0]->row() );
1464 }
1465 
slotUpClicked()1466 void TableEditForm::slotUpClicked()
1467 {
1468     QList<QTableWidgetItem *> items = m_table->selectedItems();
1469     if ( items.count() != 1 )
1470         return;
1471     QTableWidgetItem *item = items[0];
1472     const int row = item->row();
1473     if ( row < 1 || row > m_table->rowCount() - 1 )
1474         return;
1475     const int newRow = row - 1;
1476     m_table->insertRow( newRow );
1477     for ( int column = 0; column < m_table->columnCount(); column++ ) {
1478         m_table->setItem( newRow, column,
1479                 m_table->takeItem( row + 1, column ) );
1480     }
1481     m_table->removeRow( row + 1 );
1482 
1483     m_table->setCurrentItem( item );
1484     m_table->scrollToItem( item );
1485 }
1486 
slotDownClicked()1487 void TableEditForm::slotDownClicked()
1488 {
1489     QList<QTableWidgetItem *> items = m_table->selectedItems();
1490     if ( items.count() != 1 )
1491         return;
1492     QTableWidgetItem *item = items[0];
1493     const int row = item->row();
1494     if ( row < 0 || row >= m_table->rowCount() - 1 )
1495         return;
1496     const int newRow = row + 2;
1497     m_table->insertRow( newRow );
1498     for ( int column = 0; column < m_table->columnCount(); column++ ) {
1499         m_table->setItem( newRow, column, m_table->takeItem( row, column ) );
1500     }
1501     m_table->removeRow( row );
1502 
1503     m_table->setCurrentItem( item );
1504     m_table->scrollToItem( item );
1505 }
1506 
unicodeKeyToSymStr(QChar c)1507 static QString unicodeKeyToSymStr ( QChar c )
1508 {
1509     QString str;
1510 
1511     switch ( c.unicode() ) {
1512     case 0x00A5: str = "yen"; break;
1513     case 0x3002: str = "kana-fullstop"; break;
1514     case 0x300C: str = "kana-opening-bracket"; break;
1515     case 0x300D: str = "kana-closing-bracket"; break;
1516     case 0x3001: str = "kana-comma"; break;
1517     case 0x30FB: str = "kana-conjunctive"; break;
1518     case 0x30F2: str = "kana-WO"; break;
1519     case 0x30A1: str = "kana-a"; break;
1520     case 0x30A3: str = "kana-i"; break;
1521     case 0x30A5: str = "kana-u"; break;
1522     case 0x30A7: str = "kana-e"; break;
1523     case 0x30A9: str = "kana-o"; break;
1524     case 0x30E3: str = "kana-ya"; break;
1525     case 0x30E5: str = "kana-yu"; break;
1526     case 0x30E7: str = "kana-yo"; break;
1527     case 0x30C3: str = "kana-tsu"; break;
1528     case 0x30FC: str = "kana-prolonged-sound"; break;
1529     case 0x30A2: str = "kana-A"; break;
1530     case 0x30A4: str = "kana-I"; break;
1531     case 0x30A6: str = "kana-U"; break;
1532     case 0x30A8: str = "kana-E"; break;
1533     case 0x30AA: str = "kana-O"; break;
1534     case 0x30AB: str = "kana-KA"; break;
1535     case 0x30AD: str = "kana-KI"; break;
1536     case 0x30AF: str = "kana-KU"; break;
1537     case 0x30B1: str = "kana-KE"; break;
1538     case 0x30B3: str = "kana-KO"; break;
1539     case 0x30B5: str = "kana-SA"; break;
1540     case 0x30B7: str = "kana-SHI"; break;
1541     case 0x30B9: str = "kana-SU"; break;
1542     case 0x30BB: str = "kana-SE"; break;
1543     case 0x30BD: str = "kana-SO"; break;
1544     case 0x30BF: str = "kana-TA"; break;
1545     case 0x30C1: str = "kana-CHI"; break;
1546     case 0x30C4: str = "kana-TSU"; break;
1547     case 0x30C6: str = "kana-TE"; break;
1548     case 0x30C8: str = "kana-TO"; break;
1549     case 0x30CA: str = "kana-NA"; break;
1550     case 0x30CB: str = "kana-NI"; break;
1551     case 0x30CC: str = "kana-NU"; break;
1552     case 0x30CD: str = "kana-NE"; break;
1553     case 0x30CE: str = "kana-NO"; break;
1554     case 0x30CF: str = "kana-HA"; break;
1555     case 0x30D2: str = "kana-HI"; break;
1556     case 0x30D5: str = "kana-FU"; break;
1557     case 0x30D8: str = "kana-HE"; break;
1558     case 0x30DB: str = "kana-HO"; break;
1559     case 0x30DE: str = "kana-MA"; break;
1560     case 0x30DF: str = "kana-MI"; break;
1561     case 0x30E0: str = "kana-MU"; break;
1562     case 0x30E1: str = "kana-ME"; break;
1563     case 0x30E2: str = "kana-MO"; break;
1564     case 0x30E4: str = "kana-YA"; break;
1565     case 0x30E6: str = "kana-YU"; break;
1566     case 0x30E8: str = "kana-YO"; break;
1567     case 0x30E9: str = "kana-RA"; break;
1568     case 0x30EA: str = "kana-RI"; break;
1569     case 0x30EB: str = "kana-RU"; break;
1570     case 0x30EC: str = "kana-RE"; break;
1571     case 0x30ED: str = "kana-RO"; break;
1572     case 0x30EF: str = "kana-WA"; break;
1573     case 0x30F3: str = "kana-N"; break;
1574     case 0x309B: str = "kana-voiced-sound"; break;
1575     case 0x309C: str = "kana-semivoiced-sound"; break;
1576     default:
1577         break;
1578     }
1579 
1580     return str;
1581 }
1582