1
/*****************************************************************************
2
* This file is part of Kiten, a KDE Japanese Reference Tool *
3
* Copyright (C) 2006 Joseph Kerian <jkerian@gmail.com> *
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. *
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. *
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
*****************************************************************************/
22
TODO: Add features to limit the number of hits on a per-search basis.
24
Add a mechanism (either through subclassing, or directly) for use
25
for marking "requested" fields for the dcop system.
28
#include "dictquery.h"
33
#include <QStringList>
35
class DictQuery::Private
38
Private() : matchType( DictQuery::matchExact ) {}
40
/** Stores the (english or otherwise non-japanese) meaning */
42
/** Stores the pronunciation in kana */
43
QString pronunciation;
44
/** The main word, this usually contains kanji */
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 */
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;
64
const QString DictQuery::Private::pronunciationMarker( "__@\\p" );
65
const QString DictQuery::Private::meaningMarker( "__@\\m" );
66
const QString DictQuery::Private::wordMarker( "_@\\w" );
68
/*****************************************************************************
69
* Constructors, Destructors, Initilizers, and
70
* Global Status Indicators.
71
*****************************************************************************/
72
DictQuery::DictQuery()
76
DictQuery::DictQuery( const QString& str )
79
this->operator=( (QString)str );
82
DictQuery::DictQuery( const DictQuery& orig )
85
this->operator=( (DictQuery&)orig );
88
DictQuery *DictQuery::clone() const
90
return new DictQuery( *this );
93
DictQuery::operator QString() const
95
//kDebug() << "DictQuery toString operator called!";
99
DictQuery::~DictQuery()
104
bool DictQuery::isEmpty() const
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();
111
void DictQuery::clear()
113
d->extendedAttributes.clear();
115
d->pronunciation = "";
117
d->entryOrder.clear();
120
/*****************************************************************************
121
* Methods that involve multiple instances of the class
122
* (comparison, copy etc)
123
*****************************************************************************/
124
DictQuery &DictQuery::operator=( const DictQuery &old )
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;
141
DictQuery &DictQuery::operator+=( const DictQuery &old )
143
foreach( const QString &item, old.d->entryOrder )
145
if( item == d->meaningMarker )
147
if( d->entryOrder.removeAll( d->meaningMarker ) > 0 )
149
setMeaning( getMeaning() + mainDelimiter + old.getMeaning() );
153
setMeaning( old.getMeaning() );
156
else if( item == d->pronunciationMarker )
158
if( d->entryOrder.removeAll( d->pronunciationMarker ) > 0 )
160
setPronunciation(getPronunciation() + mainDelimiter + old.getPronunciation() );
164
setPronunciation(old.getPronunciation());
167
else if( item == d->wordMarker )
169
d->entryOrder.removeAll( d->wordMarker );
170
setWord( old.getWord() ); //Only one of these allowed
174
setProperty( item, old.getProperty( item ) );
181
DictQuery operator+( const DictQuery &a, const DictQuery &b )
188
bool operator==( const DictQuery &a, const DictQuery &b )
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 ) )
203
bool operator!=( const DictQuery &a, const DictQuery &b )
208
bool operator<( const DictQuery &a, const DictQuery &b )
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 )
214
QString B_version = b.d->extendedAttributes.value( it.key() );
215
if( a.d->extendedAttributes[ it.key() ] != B_version )
217
if( ! B_version.contains( "," ) && ! B_version.contains( "-" ) )
221
//TODO: check for multi-values or ranges in DictQuery operator<
225
if( ! a.d->pronunciation.isEmpty() )
227
QStringList aList = a.d->pronunciation.split( DictQuery::mainDelimiter );
228
QStringList bList = b.d->pronunciation.split( DictQuery::mainDelimiter );
229
foreach( const QString &str, aList )
231
if( bList.contains( str ) == 0 )
238
if( ! a.d->meaning.isEmpty() )
240
QStringList aList = a.d->meaning.split( DictQuery::mainDelimiter );
241
QStringList bList = b.d->meaning.split( DictQuery::mainDelimiter );
242
foreach( const QString &str, aList )
244
if( bList.contains( str ) == 0 )
251
//Assume only one entry for word
252
if( ! a.d->word.isEmpty() )
254
if( a.d->word != b.d->word )
263
/*****************************************************************************
264
* Methods to extract from QStrings and recreate QStrings
266
*****************************************************************************/
267
const QString DictQuery::toString() const
275
foreach( const QString &it, d->entryOrder )
277
if( it == d->pronunciationMarker )
279
reply += d->pronunciation+mainDelimiter;
281
else if( it == d->meaningMarker )
283
reply += d->meaning+mainDelimiter;
285
else if( it == d->wordMarker )
287
reply += d->word+mainDelimiter;
291
reply += it + propertySeperator + d->extendedAttributes.value( it )
295
reply.truncate( reply.length() - mainDelimiter.length() );
300
DictQuery &DictQuery::operator=( const QString &str )
302
QStringList parts = str.split( mainDelimiter );
304
if( str.length() > 0 )
306
foreach( const QString &it, parts)
308
if( it.contains( propertySeperator ) )
310
QStringList prop = it.split( propertySeperator );
311
if( prop.count() != 2 )
315
result.setProperty( prop[ 0 ], prop[ 1 ] );
316
//replace or throw an error with duplicates?
320
switch( stringTypeCheck( it ) )
322
case DictQuery::strTypeLatin :
323
if( result.d->entryOrder.removeAll( d->meaningMarker ) > 0 )
325
result.setMeaning( result.getMeaning() + mainDelimiter + it );
329
result.setMeaning( it );
333
case DictQuery::strTypeKana :
334
if( result.d->entryOrder.removeAll( d->pronunciationMarker ) > 0 )
336
result.setPronunciation( result.getPronunciation() + mainDelimiter + it );
340
result.setPronunciation( it );
344
case DictQuery::strTypeKanji :
345
result.d->entryOrder.removeAll( d->wordMarker );
346
result.setWord( it ); //Only one of these allowed
349
case DictQuery::mixed :
350
kWarning() <<"DictQuery: String parsing error - mixed type";
353
case DictQuery::stringParseError :
354
kWarning() << "DictQuery: String parsing error";
359
//kDebug() << "Query: ("<<result.getWord() << ") ["<<result.getPronunciation()<<"] :"<<
360
// result.getMeaning()<<endl;
361
this->operator=( result );
366
* Private utility method for the above... confirms that an entire string
367
* is either completely japanese or completely english
369
DictQuery::stringTypeEnum DictQuery::stringTypeCheck( const QString &in )
371
stringTypeEnum firstType;
372
//Split into individual characters
375
return DictQuery::stringParseError;
378
firstType = charTypeCheck( in.at( 0 ) );
379
for( int i = 1; i < in.size(); i++ )
381
stringTypeEnum newType = charTypeCheck( in.at( i ) );
382
if( newType != firstType )
384
if( firstType == strTypeKana && newType == strTypeKanji )
386
firstType = strTypeKanji;
388
else if( firstType == strTypeKanji && newType == strTypeKana )
392
return DictQuery::mixed;
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.
405
DictQuery::stringTypeEnum DictQuery::charTypeCheck( const QChar &ch )
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*/ )
423
/*****************************************************************************
424
* An array of Property List accessors and mutators
426
*****************************************************************************/
427
QString DictQuery::getProperty( const QString &key ) const
429
return ( *this )[ key ];
432
const QList<QString> DictQuery::listPropertyKeys() const
434
return d->extendedAttributes.keys();
437
const QString DictQuery::operator[] ( const QString &key ) const
439
return d->extendedAttributes.value( key );
442
QString DictQuery::operator[] ( const QString &key )
444
return d->extendedAttributes[ key ];
447
bool DictQuery::hasProperty( const QString &key ) const
449
return d->entryOrder.contains( key ) > 0;
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 )
456
if( key == d->pronunciationMarker || key == d->meaningMarker
457
|| key.isEmpty() || value.isEmpty() )
462
if ( ! d->extendedAttributes.contains( key ) )
464
d->entryOrder.append( key );
467
d->extendedAttributes.insert(key,value);
471
bool DictQuery::removeProperty( const QString &key )
473
if( d->extendedAttributes.contains( key ) )
475
return d->entryOrder.removeAll( key );
480
QString DictQuery::takeProperty ( const QString & key )
482
d->entryOrder.removeAll( key );
483
return d->extendedAttributes.take( key );
486
/*****************************************************************************
487
* Meaning and Pronunciation Accessors and Mutators
488
****************************************************************************/
489
QString DictQuery::getMeaning() const
494
bool DictQuery::setMeaning( const QString &newMeaning )
496
if ( newMeaning.isEmpty() )
498
#ifdef USING_QUERY_EXCEPTIONS
499
throw InvalidQueryException( newMeaning );
505
d->meaning = newMeaning;
507
if( ! d->entryOrder.contains( d->meaningMarker ) )
509
d->entryOrder.append( d->meaningMarker );
515
QString DictQuery::getPronunciation() const
517
return d->pronunciation;
520
bool DictQuery::setPronunciation( const QString &newPronunciation )
522
if( newPronunciation.isEmpty() )
524
#ifdef USING_QUERY_EXCEPTIONS
525
throw InvalidQueryException( newPro );
531
d->pronunciation = newPronunciation;
533
if( ! d->entryOrder.contains( d->pronunciationMarker ) )
535
d->entryOrder.append( d->pronunciationMarker );
541
QString DictQuery::getWord() const
546
bool DictQuery::setWord( const QString &newWord )
548
if( newWord.isEmpty() )
550
#ifdef USING_QUERY_EXCEPTIONS
551
throw InvalidQueryException( newWord );
559
if( ! d->entryOrder.contains( d->wordMarker ) )
561
d->entryOrder.append( d->wordMarker );
567
/*************************************************************
568
Handlers for getting and setting dictionary types
569
*************************************************************/
570
QStringList DictQuery::getDictionaries() const
572
return d->targetDictionaries;
575
void DictQuery::setDictionaries( const QStringList &newDictionaries )
577
d->targetDictionaries = newDictionaries;
580
/**************************************************************
581
Match Type Accessors and Mutators
582
************************************************************/
583
DictQuery::MatchType DictQuery::getMatchType() const
588
void DictQuery::setMatchType( MatchType newType )
590
d->matchType = newType;
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;
600
bool operator==( const DictQuery &query, const QString &other ) {
603
bool operator!=( const DictQuery &q1, const DictQuery &q2 ) {
606
bool operator!=( const QString &other, const DictQuery &query ) {
607
return !(other==query);
609
bool operator!=( const DictQuery &query, const QString &other ) {
610
return !(query==other);
612
inline bool operator<=( const DictQuery &a, const DictQuery &b) {
613
return (a<b || a==b);
615
bool operator>=( const DictQuery &a, const DictQuery &b) {
616
return (b>a || a==b);
618
bool operator>( const DictQuery &a, const DictQuery &b) {
621
DictQuery &operator+( const DictQuery &a, const QString &b) {
622
return (*(new DictQuery(a))) += b;
624
DictQuery &operator+( const QString &a, const DictQuery &b) {
625
return (*(new DictQuery(a))) += b;
627
DictQuery &DictQuery::operator+=(const QString &str) {
629
return operator+=(x);
631
#ifndef QT_NO_CAST_ASCII
632
DictQuery &DictQuery::operator=(const char *str) {
636
DictQuery &DictQuery::operator+=(const char *str) {
638
return operator+=(x);
642
/**************************************************************
643
* Set our constants declared in the class
644
**************************************************************/
645
const QString DictQuery::mainDelimiter( " " );
646
const QString DictQuery::propertySeperator( ":" );