~ubuntu-branches/ubuntu/quantal/kiten/quantal-proposed

« back to all changes in this revision

Viewing changes to lib/dictquery.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Harald Sitter
  • Date: 2011-07-10 11:23:47 UTC
  • Revision ID: james.westby@ubuntu.com-20110710112347-ykfhtvam3kgssspo
Tags: upstream-4.6.90+repack
ImportĀ upstreamĀ versionĀ 4.6.90+repack

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 * This file is part of Kiten, a KDE Japanese Reference Tool                 *
 
3
 * Copyright (C) 2006 Joseph Kerian <jkerian@gmail.com>                      *
 
4
 *                                                                           *
 
5
 * This library is free software; you can redistribute it and/or             *
 
6
 * modify it under the terms of the GNU Library General Public               *
 
7
 * License as published by the Free Software Foundation; either              *
 
8
 * version 2 of the License, or (at your option) any later version.          *
 
9
 *                                                                           *
 
10
 * This library is distributed in the hope that it will be useful,           *
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
 
13
 * Library General Public License for more details.                          *
 
14
 *                                                                           *
 
15
 * You should have received a copy of the GNU Library General Public License *
 
16
 * along with this library; see the file COPYING.LIB.  If not, write to      *
 
17
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,      *
 
18
 * Boston, MA 02110-1301, USA.                                               *
 
19
 *****************************************************************************/
 
20
 
 
21
/*
 
22
TODO: Add features to limit the number of hits on a per-search basis.
 
23
 
 
24
        Add a mechanism (either through subclassing, or directly) for use
 
25
                for marking "requested" fields for the dcop system.
 
26
*/
 
27
 
 
28
#include "dictquery.h"
 
29
 
 
30
#include <KDebug>
 
31
 
 
32
#include <QString>
 
33
#include <QStringList>
 
34
 
 
35
class DictQuery::Private
 
36
{
 
37
  public:
 
38
    Private() : matchType( DictQuery::matchExact ) {}
 
39
 
 
40
    /** Stores the (english or otherwise non-japanese) meaning */
 
41
    QString meaning;
 
42
    /** Stores the pronunciation in kana */
 
43
    QString pronunciation;
 
44
    /** The main word, this usually contains kanji */
 
45
    QString word;
 
46
    /** Any amount of extended attributes, grade leve, heisig/henshall/etc index numbers, whatever you want */
 
47
    QHash<QString,QString> extendedAttributes;
 
48
    /** The order that various attributes, meanings, and pronunciations were entered, so we can
 
49
      * regenerate the list for the user if they need them again */
 
50
    QStringList entryOrder;
 
51
    /** A list of dictionaries to limit the search to, and empty list implies "all loaded dictionaries" */
 
52
    QStringList targetDictionaries;
 
53
    /** What MatchType is this set to */
 
54
    MatchType matchType;
 
55
 
 
56
    /** Marker in the m_entryOrder for the location of the pronunciation element */
 
57
    static const QString pronunciationMarker;
 
58
    /** Marker in the m_entryOrder for the location of the translated meaning element */
 
59
    static const QString meaningMarker;
 
60
    /** Marker in the m_entryOrder for the location of the word (kanji) element */
 
61
    static const QString wordMarker;
 
62
};
 
63
 
 
64
const QString DictQuery::Private::pronunciationMarker( "__@\\p" );
 
65
const QString DictQuery::Private::meaningMarker( "__@\\m" );
 
66
const QString DictQuery::Private::wordMarker( "_@\\w" );
 
67
 
 
68
/*****************************************************************************
 
69
*       Constructors, Destructors, Initilizers, and
 
70
*       Global Status Indicators.
 
71
*****************************************************************************/
 
72
DictQuery::DictQuery()
 
73
: d( new Private )
 
74
{ }
 
75
 
 
76
DictQuery::DictQuery( const QString& str )
 
77
: d( new Private )
 
78
{
 
79
  this->operator=( (QString)str );
 
80
}
 
81
 
 
82
DictQuery::DictQuery( const DictQuery& orig )
 
83
: d( new Private )
 
84
{
 
85
  this->operator=( (DictQuery&)orig );
 
86
}
 
87
 
 
88
DictQuery *DictQuery::clone() const
 
89
{
 
90
  return new DictQuery( *this );
 
91
}
 
92
 
 
93
DictQuery::operator QString() const
 
94
{
 
95
  //kDebug() << "DictQuery toString operator called!";
 
96
  return toString();
 
97
}
 
98
 
 
99
DictQuery::~DictQuery()
 
100
{
 
101
  delete d;
 
102
}
 
103
 
 
104
bool DictQuery::isEmpty() const
 
105
{
 
106
  // We're only empty if the two strings are empty too
 
107
  return d->extendedAttributes.isEmpty() && d->meaning.isEmpty()
 
108
           && d->pronunciation.isEmpty() && d->word.isEmpty();
 
109
}
 
110
 
 
111
void DictQuery::clear()
 
112
{
 
113
  d->extendedAttributes.clear();
 
114
  d->meaning = "";
 
115
  d->pronunciation = "";
 
116
  d->word = "";
 
117
  d->entryOrder.clear();
 
118
}
 
119
 
 
120
/*****************************************************************************
 
121
*       Methods that involve multiple instances of the class
 
122
*       (comparison, copy etc)
 
123
*****************************************************************************/
 
124
DictQuery &DictQuery::operator=( const DictQuery &old )
 
125
{
 
126
  if ( &old == this )
 
127
  {
 
128
    return *this;
 
129
  }
 
130
 
 
131
  clear();
 
132
  d->matchType          = old.d->matchType;
 
133
  d->extendedAttributes = old.d->extendedAttributes;
 
134
  d->meaning            = old.d->meaning;
 
135
  d->pronunciation      = old.d->pronunciation;
 
136
  d->word               = old.d->word;
 
137
  d->entryOrder         = old.d->entryOrder;
 
138
  return *this;
 
139
}
 
140
 
 
141
DictQuery &DictQuery::operator+=( const DictQuery &old )
 
142
{
 
143
  foreach( const QString &item, old.d->entryOrder )
 
144
  {
 
145
    if( item == d->meaningMarker )
 
146
    {
 
147
      if( d->entryOrder.removeAll( d->meaningMarker ) > 0 )
 
148
      {
 
149
        setMeaning( getMeaning() + mainDelimiter + old.getMeaning() );
 
150
      }
 
151
      else
 
152
      {
 
153
        setMeaning( old.getMeaning() );
 
154
      }
 
155
    }
 
156
    else if( item == d->pronunciationMarker )
 
157
    {
 
158
      if( d->entryOrder.removeAll( d->pronunciationMarker ) > 0 )
 
159
      {
 
160
        setPronunciation(getPronunciation() + mainDelimiter + old.getPronunciation() );
 
161
      }
 
162
      else
 
163
      {
 
164
        setPronunciation(old.getPronunciation());
 
165
      }
 
166
    }
 
167
    else if( item == d->wordMarker )
 
168
    {
 
169
      d->entryOrder.removeAll( d->wordMarker );
 
170
      setWord( old.getWord() ); //Only one of these allowed
 
171
    }
 
172
    else
 
173
    {
 
174
      setProperty( item, old.getProperty( item ) );
 
175
    }
 
176
  }
 
177
 
 
178
  return *this;
 
179
}
 
180
 
 
181
DictQuery operator+( const DictQuery &a, const DictQuery &b )
 
182
{
 
183
  DictQuery val( a );
 
184
  val += b;
 
185
  return val;
 
186
}
 
187
 
 
188
bool operator==( const DictQuery &a, const DictQuery &b )
 
189
{
 
190
  if(   ( a.d->pronunciation      != b.d->pronunciation )
 
191
     || ( a.d->meaning            != b.d->meaning )
 
192
     || ( a.d->word               != b.d->word )
 
193
     || ( a.d->entryOrder         != b.d->entryOrder )
 
194
     || ( a.d->extendedAttributes != b.d->extendedAttributes )
 
195
     || ( a.d->matchType          != b.d->matchType ) )
 
196
  {
 
197
    return false;
 
198
  }
 
199
 
 
200
  return true;
 
201
}
 
202
 
 
203
bool operator!=( const DictQuery &a, const DictQuery &b )
 
204
{
 
205
  return ! ( a == b );
 
206
}
 
207
 
 
208
bool operator<( const DictQuery &a, const DictQuery &b )
 
209
{
 
210
  QHash<QString,QString>::const_iterator it     = a.d->extendedAttributes.constBegin();
 
211
  QHash<QString,QString>::const_iterator it_end = a.d->extendedAttributes.constEnd();
 
212
  for( ; it != it_end; ++it )
 
213
  {
 
214
    QString B_version = b.d->extendedAttributes.value( it.key() );
 
215
    if( a.d->extendedAttributes[ it.key() ] != B_version )
 
216
    {
 
217
      if( ! B_version.contains( "," ) && ! B_version.contains( "-" ) )
 
218
      {
 
219
        return false;
 
220
      }
 
221
      //TODO: check for multi-values or ranges in DictQuery operator<
 
222
    }
 
223
  }
 
224
 
 
225
  if( ! a.d->pronunciation.isEmpty() )
 
226
  {
 
227
    QStringList aList = a.d->pronunciation.split( DictQuery::mainDelimiter );
 
228
    QStringList bList = b.d->pronunciation.split( DictQuery::mainDelimiter );
 
229
    foreach( const QString &str, aList )
 
230
    {
 
231
      if( bList.contains( str ) == 0 )
 
232
      {
 
233
        return false;
 
234
      }
 
235
    }
 
236
  }
 
237
 
 
238
  if( ! a.d->meaning.isEmpty() )
 
239
  {
 
240
    QStringList aList = a.d->meaning.split( DictQuery::mainDelimiter );
 
241
    QStringList bList = b.d->meaning.split( DictQuery::mainDelimiter );
 
242
    foreach( const QString &str, aList )
 
243
    {
 
244
      if( bList.contains( str ) == 0 )
 
245
      {
 
246
        return false;
 
247
      }
 
248
    }
 
249
  }
 
250
 
 
251
  //Assume only one entry for word
 
252
  if( ! a.d->word.isEmpty() )
 
253
  {
 
254
    if( a.d->word != b.d->word )
 
255
    {
 
256
      return false;
 
257
    }
 
258
  }
 
259
 
 
260
  return true;
 
261
}
 
262
 
 
263
/*****************************************************************************
 
264
*       Methods to extract from QStrings and recreate QStrings
 
265
*
 
266
*****************************************************************************/
 
267
const QString DictQuery::toString() const
 
268
{
 
269
  if( isEmpty() )
 
270
  {
 
271
    return QString();
 
272
  }
 
273
 
 
274
  QString reply;
 
275
  foreach( const QString &it, d->entryOrder )
 
276
  {
 
277
    if( it == d->pronunciationMarker )
 
278
    {
 
279
      reply += d->pronunciation+mainDelimiter;
 
280
    }
 
281
    else if( it == d->meaningMarker )
 
282
    {
 
283
      reply += d->meaning+mainDelimiter;
 
284
    }
 
285
    else if( it == d->wordMarker )
 
286
    {
 
287
      reply += d->word+mainDelimiter;
 
288
    }
 
289
    else
 
290
    {
 
291
      reply += it + propertySeperator + d->extendedAttributes.value( it )
 
292
                  + mainDelimiter;
 
293
    }
 
294
  }
 
295
  reply.truncate( reply.length() - mainDelimiter.length() );
 
296
 
 
297
  return reply;
 
298
}
 
299
 
 
300
DictQuery &DictQuery::operator=( const QString &str )
 
301
{
 
302
  QStringList parts = str.split( mainDelimiter );
 
303
  DictQuery result;
 
304
  if( str.length() > 0 )
 
305
  {
 
306
    foreach( const QString &it, parts)
 
307
    {
 
308
      if( it.contains( propertySeperator ) )
 
309
      {
 
310
        QStringList prop = it.split( propertySeperator );
 
311
        if( prop.count() != 2 )
 
312
        {
 
313
          break;
 
314
        }
 
315
        result.setProperty( prop[ 0 ], prop[ 1 ] );
 
316
        //replace or throw an error with duplicates?
 
317
      }
 
318
      else
 
319
      {
 
320
        switch( stringTypeCheck( it ) )
 
321
        {
 
322
          case DictQuery::strTypeLatin :
 
323
            if( result.d->entryOrder.removeAll( d->meaningMarker ) > 0 )
 
324
            {
 
325
              result.setMeaning( result.getMeaning() + mainDelimiter + it );
 
326
            }
 
327
            else
 
328
            {
 
329
              result.setMeaning( it );
 
330
            }
 
331
            break;
 
332
 
 
333
          case DictQuery::strTypeKana :
 
334
            if( result.d->entryOrder.removeAll( d->pronunciationMarker ) > 0 )
 
335
            {
 
336
              result.setPronunciation( result.getPronunciation() + mainDelimiter + it );
 
337
            }
 
338
            else
 
339
            {
 
340
              result.setPronunciation( it );
 
341
            }
 
342
            break;
 
343
 
 
344
          case DictQuery::strTypeKanji :
 
345
            result.d->entryOrder.removeAll( d->wordMarker );
 
346
            result.setWord( it ); //Only one of these allowed
 
347
            break;
 
348
 
 
349
          case DictQuery::mixed :
 
350
            kWarning() <<"DictQuery: String parsing error - mixed type";
 
351
            break;
 
352
 
 
353
          case DictQuery::stringParseError :
 
354
            kWarning() << "DictQuery: String parsing error";
 
355
        }
 
356
      }
 
357
    }
 
358
  }
 
359
  //kDebug() << "Query: ("<<result.getWord() << ") ["<<result.getPronunciation()<<"] :"<<
 
360
  //    result.getMeaning()<<endl;
 
361
  this->operator=( result );
 
362
  return *this;
 
363
}
 
364
 
 
365
/**
 
366
 * Private utility method for the above... confirms that an entire string
 
367
 * is either completely japanese or completely english
 
368
 */
 
369
DictQuery::stringTypeEnum DictQuery::stringTypeCheck( const QString &in )
 
370
{
 
371
  stringTypeEnum firstType;
 
372
  //Split into individual characters
 
373
  if( in.size() <= 0 )
 
374
  {
 
375
    return DictQuery::stringParseError;
 
376
  }
 
377
 
 
378
  firstType = charTypeCheck( in.at( 0 ) );
 
379
  for( int i = 1; i < in.size(); i++ )
 
380
  {
 
381
    stringTypeEnum newType = charTypeCheck( in.at( i ) );
 
382
    if( newType != firstType )
 
383
    {
 
384
      if( firstType == strTypeKana && newType == strTypeKanji )
 
385
      {
 
386
        firstType = strTypeKanji;
 
387
      }
 
388
      else if( firstType == strTypeKanji && newType == strTypeKana )
 
389
        ; //That's okay
 
390
      else
 
391
      {
 
392
        return DictQuery::mixed;
 
393
      }
 
394
    }
 
395
  }
 
396
 
 
397
  return firstType;
 
398
}
 
399
 
 
400
/**
 
401
 * Private utility method for the stringTypeCheck
 
402
 * Just checks and returns the type of the first character in the string
 
403
 * that is passed to it.
 
404
 */
 
405
DictQuery::stringTypeEnum DictQuery::charTypeCheck( const QChar &ch )
 
406
{
 
407
  if( ch.toLatin1() )
 
408
  {
 
409
    return strTypeLatin;
 
410
  }
 
411
  //The unicode character boundaries are:
 
412
  // 3040 - 309F Hiragana
 
413
  // 30A0 - 30FF Katakana
 
414
  // 31F0 - 31FF Katakana phonetic expressions (wtf?)
 
415
  if( 0x3040 <= ch.unicode() && ch.unicode() <= 0x30FF /*|| ch.unicode() & 0x31F0*/ )
 
416
  {
 
417
    return strTypeKana;
 
418
  }
 
419
 
 
420
  return strTypeKanji;
 
421
}
 
422
 
 
423
/*****************************************************************************
 
424
*       An array of Property List accessors and mutators
 
425
*
 
426
*****************************************************************************/
 
427
QString DictQuery::getProperty( const QString &key ) const
 
428
{
 
429
  return ( *this )[ key ];
 
430
}
 
431
 
 
432
const QList<QString> DictQuery::listPropertyKeys() const
 
433
{
 
434
  return d->extendedAttributes.keys();
 
435
}
 
436
 
 
437
const QString DictQuery::operator[] ( const QString &key ) const
 
438
{
 
439
  return d->extendedAttributes.value( key );
 
440
}
 
441
 
 
442
QString DictQuery::operator[] ( const QString &key )
 
443
{
 
444
  return d->extendedAttributes[ key ];
 
445
}
 
446
 
 
447
bool DictQuery::hasProperty( const QString &key ) const
 
448
{
 
449
  return d->entryOrder.contains( key ) > 0;
 
450
}
 
451
 
 
452
//TODO: Add i18n handling and alternate versions of property names
 
453
//TODO: further break down the barrier between different types
 
454
bool DictQuery::setProperty( const QString& key, const QString& value )
 
455
{
 
456
  if( key == d->pronunciationMarker || key == d->meaningMarker
 
457
      || key.isEmpty() || value.isEmpty() )
 
458
  {
 
459
    return false;
 
460
  }
 
461
 
 
462
  if ( ! d->extendedAttributes.contains( key ) )
 
463
  {
 
464
    d->entryOrder.append( key );
 
465
  }
 
466
 
 
467
  d->extendedAttributes.insert(key,value);
 
468
  return true;
 
469
}
 
470
 
 
471
bool DictQuery::removeProperty( const QString &key )
 
472
{
 
473
  if( d->extendedAttributes.contains( key ) )
 
474
  {
 
475
    return d->entryOrder.removeAll( key );
 
476
  }
 
477
  return false;
 
478
}
 
479
 
 
480
QString DictQuery::takeProperty ( const QString & key )
 
481
{
 
482
  d->entryOrder.removeAll( key );
 
483
  return d->extendedAttributes.take( key );
 
484
}
 
485
 
 
486
/*****************************************************************************
 
487
*       Meaning and Pronunciation Accessors and Mutators
 
488
****************************************************************************/
 
489
QString DictQuery::getMeaning() const
 
490
{
 
491
  return d->meaning;
 
492
}
 
493
 
 
494
bool DictQuery::setMeaning( const QString &newMeaning )
 
495
{
 
496
  if ( newMeaning.isEmpty() )
 
497
  {
 
498
#ifdef USING_QUERY_EXCEPTIONS
 
499
    throw InvalidQueryException( newMeaning );
 
500
#else
 
501
    return false;
 
502
#endif
 
503
  }
 
504
 
 
505
  d->meaning = newMeaning;
 
506
 
 
507
  if( ! d->entryOrder.contains( d->meaningMarker ) )
 
508
  {
 
509
    d->entryOrder.append( d->meaningMarker );
 
510
  }
 
511
 
 
512
  return true;
 
513
}
 
514
 
 
515
QString DictQuery::getPronunciation() const
 
516
{
 
517
  return d->pronunciation;
 
518
}
 
519
 
 
520
bool DictQuery::setPronunciation( const QString &newPronunciation )
 
521
{
 
522
  if( newPronunciation.isEmpty() )
 
523
  {
 
524
#ifdef USING_QUERY_EXCEPTIONS
 
525
    throw InvalidQueryException( newPro );
 
526
#else
 
527
    return false;
 
528
#endif
 
529
  }
 
530
 
 
531
  d->pronunciation = newPronunciation;
 
532
 
 
533
  if( ! d->entryOrder.contains( d->pronunciationMarker ) )
 
534
  {
 
535
    d->entryOrder.append( d->pronunciationMarker );
 
536
  }
 
537
 
 
538
  return true;
 
539
}
 
540
 
 
541
QString DictQuery::getWord() const
 
542
{
 
543
  return d->word;
 
544
}
 
545
 
 
546
bool DictQuery::setWord( const QString &newWord )
 
547
{
 
548
  if( newWord.isEmpty() )
 
549
  {
 
550
#ifdef USING_QUERY_EXCEPTIONS
 
551
    throw InvalidQueryException( newWord );
 
552
#else
 
553
    return false;
 
554
#endif
 
555
  }
 
556
 
 
557
  d->word = newWord;
 
558
 
 
559
  if( ! d->entryOrder.contains( d->wordMarker ) )
 
560
  {
 
561
    d->entryOrder.append( d->wordMarker );
 
562
  }
 
563
 
 
564
  return true;
 
565
}
 
566
 
 
567
/*************************************************************
 
568
  Handlers for getting and setting dictionary types
 
569
  *************************************************************/
 
570
QStringList DictQuery::getDictionaries() const
 
571
{
 
572
  return d->targetDictionaries;
 
573
}
 
574
 
 
575
void DictQuery::setDictionaries( const QStringList &newDictionaries )
 
576
{
 
577
  d->targetDictionaries = newDictionaries;
 
578
}
 
579
 
 
580
/**************************************************************
 
581
  Match Type Accessors and Mutators
 
582
  ************************************************************/
 
583
DictQuery::MatchType DictQuery::getMatchType() const
 
584
{
 
585
  return d->matchType;
 
586
}
 
587
 
 
588
void DictQuery::setMatchType( MatchType newType )
 
589
{
 
590
  d->matchType = newType;
 
591
}
 
592
 
 
593
/**************************************************************
 
594
*       Aliases to handle different forms of operator arguments
 
595
*       Disabled at the moment
 
596
*************************************************************
 
597
bool operator==( const QString &other, const DictQuery &query ) {
 
598
        DictQuery x(other); return x == query;
 
599
}
 
600
bool operator==( const DictQuery &query, const QString &other ) {
 
601
        return other==query;
 
602
}
 
603
bool operator!=( const DictQuery &q1, const DictQuery &q2 ) {
 
604
        return !(q1==q2);
 
605
}
 
606
bool operator!=( const QString &other, const DictQuery &query ) {
 
607
        return !(other==query);
 
608
}
 
609
bool operator!=( const DictQuery &query, const QString &other ) {
 
610
        return !(query==other);
 
611
}
 
612
inline bool operator<=( const DictQuery &a, const DictQuery &b) {
 
613
        return (a<b || a==b);
 
614
}
 
615
bool operator>=( const DictQuery &a, const DictQuery &b) {
 
616
        return (b>a || a==b);
 
617
}
 
618
bool operator>( const DictQuery &a, const DictQuery &b) {
 
619
        return b < a;
 
620
}
 
621
DictQuery &operator+( const DictQuery &a, const QString &b) {
 
622
        return (*(new DictQuery(a))) += b;
 
623
}
 
624
DictQuery &operator+( const QString &a,   const DictQuery &b)  {
 
625
        return (*(new DictQuery(a))) += b;
 
626
}
 
627
DictQuery    &DictQuery::operator+=(const QString &str) {
 
628
        DictQuery x(str);
 
629
        return operator+=(x);
 
630
}
 
631
#ifndef QT_NO_CAST_ASCII
 
632
DictQuery    &DictQuery::operator=(const char *str) {
 
633
        QString x(str);
 
634
        return operator=(x);
 
635
}
 
636
DictQuery    &DictQuery::operator+=(const char *str) {
 
637
        DictQuery x(str);
 
638
        return operator+=(x);
 
639
}
 
640
#endif
 
641
*/
 
642
/**************************************************************
 
643
*       Set our constants declared in the class
 
644
**************************************************************/
 
645
const QString DictQuery::mainDelimiter( " " );
 
646
const QString DictQuery::propertySeperator( ":" );