1
/***************************************************************************
2
* Copyright (C) 2004-2009 by Thomas Fischer *
3
* fischer@unix-ag.uni-kl.de *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License as published by *
7
* the Free Software Foundation; either version 2 of the License, or *
8
* (at your option) any later version. *
10
* This program 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 *
13
* GNU General Public License for more details. *
15
* You should have received a copy of the GNU General Public License *
16
* along with this program; if not, write to the *
17
* Free Software Foundation, Inc., *
18
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19
***************************************************************************/
21
#include <qstringlist.h>
26
#include <xsltransform.h>
27
#include <entryfield.h>
29
#define max(a,b) ((a)>(b)?(a):(b))
35
: Element(), m_entryType( etUnknown ), m_entryTypeString( QString::null ), m_id( QString::null )
40
Entry::Entry( const EntryType entryType, const QString &id )
41
: Element( ), m_entryType( entryType ), m_id( id )
43
m_entryTypeString = entryTypeToString( entryType );
46
Entry::Entry( const QString& entryTypeString, const QString& id ) : Element( ), m_entryTypeString( entryTypeString ), m_id( id )
48
m_entryType = entryTypeFromString( entryTypeString );
49
if ( m_entryType != etUnknown )
50
m_entryTypeString = entryTypeToString( m_entryType );
53
Entry::Entry( const Entry *other )
60
for ( EntryFields::iterator it = m_fields.begin(); it != m_fields.end(); it++ )
66
Element* Entry::clone()
68
return new Entry( this );
71
bool Entry::equals( const Entry &other )
73
if ( other.id().compare( id() ) != 0 )
76
for ( EntryFields::iterator it = m_fields.begin(); it != m_fields.end(); it++ )
78
EntryField *field1 = *it;
79
EntryField *field2 = other.getField( field1->fieldTypeName() );
81
if ( field2 == NULL || field1->value() == NULL || field2->value() == NULL || field1->value()->text().compare( field2->value()->text() ) != 0 )
88
QString Entry::text() const
90
QString result = "Id: ";
91
result.append( m_id ).append( " (" ).append( entryTypeString() ).append( ")\n" );
93
for ( EntryFields::ConstIterator it = m_fields.begin(); it != m_fields.end(); it++ )
95
result.append(( *it )->fieldTypeName() ).append( ": " );
96
result.append(( *it )->value()->text() ).append( "\n" );
102
void Entry::setEntryType( const EntryType entryType )
104
m_entryType = entryType;
105
m_entryTypeString = entryTypeToString( entryType );
108
void Entry::setEntryTypeString( const QString& entryTypeString )
110
m_entryTypeString = entryTypeString;
111
m_entryType = entryTypeFromString( entryTypeString );
114
Entry::EntryType Entry::entryType() const
119
QString Entry::entryTypeString() const
121
return m_entryTypeString;
124
void Entry::setId( const QString& id )
129
QString Entry::id() const
134
bool Entry::containsPattern( const QString & pattern, EntryField::FieldType fieldType, BibTeX::Element::FilterType filterType, bool caseSensitive ) const
136
if ( filterType == ftExact )
138
/** check for exact match */
139
bool result = fieldType == EntryField::ftUnknown && m_id.contains( pattern, caseSensitive );
141
for ( EntryFields::ConstIterator it = m_fields.begin(); !result && it != m_fields.end(); it++ )
142
if ( fieldType == EntryField::ftUnknown || ( *it ) ->fieldType() == fieldType )
143
result |= ( *it ) ->value() ->containsPattern( pattern, caseSensitive );
149
/** for each word in the search pattern ... */
150
QStringList words = QStringList::split( QRegExp( "\\s+" ), pattern );
151
bool *hits = new bool[words.count()];
153
for ( QStringList::Iterator wit = words.begin(); wit != words.end(); ++wit, ++i )
155
hits[i] = fieldType == EntryField::ftUnknown && m_id.contains( *wit, caseSensitive );
157
/** check if word is contained in any field */
158
for ( EntryFields::ConstIterator fit = m_fields.begin(); fit != m_fields.end(); ++fit )
159
if ( fieldType == EntryField::ftUnknown || ( *fit ) ->fieldType() == fieldType )
160
hits[i] |= ( *fit ) ->value() ->containsPattern( *wit, caseSensitive );
163
unsigned int hitCount = 0;
164
for ( i = words.count() - 1; i >= 0; --i )
165
if ( hits[i] ) ++hitCount;
168
/** return success depending on filter type and number of hits */
169
return (( filterType == ftAnyWord && hitCount > 0 ) || ( filterType == ftEveryWord && hitCount == words.count() ) );
173
QStringList Entry::urls() const
176
const QString fieldNames[] = {"localfile", "pdf", "ps", "postscript", "doi", "url", "howpublished", "ee", "biburl", "note"};
177
const int fieldNamesCount = sizeof( fieldNames ) / sizeof( fieldNames[0] );
179
for ( int j = 1; j < 5 ; ++j ) /** there may be variants such as url3 or doi2 */
180
for ( int i = 0; i < fieldNamesCount; i++ )
182
QString fieldName = fieldNames[i];
183
/** field names should be like url, url2, url3, ... */
184
if ( j > 1 ) fieldName.append( QString::number( j ) );
186
EntryField * field = getField( fieldName );
187
if (( field && !field->value()->items.isEmpty() ) )
189
PlainText *plainText = dynamic_cast<PlainText*>( field->value()->items.first() );
190
if ( plainText != NULL )
192
QString plain = plainText->text();
193
int urlPos = plain.find( "\\url{", 0, FALSE );
196
plain = plain.mid( urlPos + 5 );
197
urlPos = plain.find( "}", 0, FALSE );
199
plain = plain.left( urlPos - 1 );
202
if ( fieldNames[ i ] == "doi" && !plain.startsWith( "http", FALSE ) )
203
plain.prepend( "http://dx.doi.org/" );
205
result.append( plain );
213
bool Entry::addField( EntryField * field )
215
m_fields.append( field );
219
EntryField* Entry::getField( const EntryField::FieldType fieldType ) const
221
EntryField * result = NULL;
223
for ( EntryFields::ConstIterator it = m_fields.begin(); ( it != m_fields.end() ) && ( result == NULL ); it++ )
224
if (( *it ) ->fieldType() == fieldType ) result = *it;
229
EntryField* Entry::getField( const QString & fieldName ) const
231
EntryField * result = NULL;
233
for ( EntryFields::ConstIterator it = m_fields.begin(); ( it != m_fields.end() ) && ( result == NULL ); it++ )
234
if (( *it ) ->fieldTypeName().lower() == fieldName.lower() )
240
bool Entry::deleteField( const QString & fieldName )
242
for ( EntryFields::ConstIterator it = m_fields.begin(); it != m_fields.end(); it++ )
243
if (( *it ) ->fieldTypeName().lower() == fieldName.lower() )
246
m_fields.remove( *it );
253
bool Entry::deleteField( const EntryField::FieldType fieldType )
255
for ( EntryFields::iterator it = m_fields.begin(); it != m_fields.end(); it++ )
256
if (( *it ) ->fieldType() == fieldType )
259
m_fields.remove( it );
266
Entry::EntryFields::ConstIterator Entry::begin() const
268
return m_fields.constBegin();
271
Entry::EntryFields::ConstIterator Entry::end() const
273
return m_fields.constEnd();
276
int Entry::getFieldCount() const
278
return m_fields.count();
281
void Entry::clearFields()
283
for ( EntryFields::iterator it = m_fields.begin(); it != m_fields.end(); it++ )
288
void Entry::copyFrom( const Entry *other )
290
if ( other == NULL ) return;
292
m_entryType = other->m_entryType;
293
m_entryTypeString = other->m_entryTypeString;
296
for ( EntryFields::ConstIterator it = other->m_fields.begin(); it != other->m_fields.end(); it++ )
297
m_fields.append( new EntryField( *it ) );
300
void Entry::merge( BibTeX::Entry *other, MergeSemantics mergeSemantics )
302
for ( EntryFields::iterator it = other->m_fields.begin(); it != other->m_fields.end(); it++ )
304
EntryField *otherField = new EntryField( *it );
305
EntryField::FieldType otherFieldType = otherField->fieldType();
306
QString otherFieldTypeName = otherField->fieldTypeName();
307
EntryField *thisField = otherFieldType != EntryField::ftUnknown ? getField( otherFieldType ) : getField( otherFieldTypeName );
309
if ( thisField == NULL )
311
m_fields.append( otherField );
313
else if ( otherField->value()->text() == thisField->value()->text() && mergeSemantics == msForceAdding )
315
otherFieldTypeName.prepend( "OPT" );
316
otherField->setFieldType( EntryField::ftUnknown, otherFieldTypeName );
317
m_fields.append( otherField );
322
QString Entry::entryTypeToString( const EntryType entryType )
327
return QString( "Article" );
329
return QString( "Book" );
331
return QString( "Booklet" );
333
return QString( "Collection" );
335
return QString( "Electronic" );
337
return QString( "InBook" );
339
return QString( "InCollection" );
340
case etInProceedings:
341
return QString( "InProceedings" );
343
return QString( "Manual" );
344
case etMastersThesis:
345
return QString( "MastersThesis" );
347
return QString( "Misc" );
349
return QString( "PhDThesis" );
351
return QString( "Proceedings" );
353
return QString( "TechReport" );
355
return QString( "Unpublished" );
357
return QString( "Unknown" );
361
Entry::EntryType Entry::entryTypeFromString( const QString & entryTypeString )
363
QString entryTypeStringLower = entryTypeString.lower();
364
if ( entryTypeStringLower == "article" )
366
else if ( entryTypeStringLower == "book" )
368
else if ( entryTypeStringLower == "booklet" )
370
else if ( entryTypeStringLower == "collection" )
372
else if (( entryTypeStringLower == "electronic" ) || ( entryTypeStringLower == "online" ) || ( entryTypeStringLower == "internet" ) || ( entryTypeStringLower == "webpage" ) )
374
else if ( entryTypeStringLower == "inbook" )
376
else if ( entryTypeStringLower == "incollection" )
377
return etInCollection;
378
else if (( entryTypeStringLower == "inproceedings" ) || ( entryTypeStringLower == "conference" ) )
379
return etInProceedings;
380
else if ( entryTypeStringLower == "manual" )
382
else if ( entryTypeStringLower == "mastersthesis" )
383
return etMastersThesis;
384
else if ( entryTypeStringLower == "misc" )
386
else if ( entryTypeStringLower == "phdthesis" )
388
else if ( entryTypeStringLower == "proceedings" )
389
return etProceedings;
390
else if ( entryTypeStringLower == "techreport" )
392
else if ( entryTypeStringLower == "unpublished" )
393
return etUnpublished;
398
Entry::FieldRequireStatus Entry::getRequireStatus( Entry::EntryType entryType, EntryField::FieldType fieldType )
405
case EntryField::ftAuthor:
406
case EntryField::ftTitle:
407
case EntryField::ftJournal:
408
case EntryField::ftYear:
409
return Entry::frsRequired;
410
case EntryField::ftVolume:
411
case EntryField::ftMonth:
412
case EntryField::ftDoi:
413
case EntryField::ftNumber:
414
case EntryField::ftPages:
415
case EntryField::ftNote:
416
case EntryField::ftKey:
417
case EntryField::ftISSN:
418
case EntryField::ftURL:
419
case EntryField::ftLocalFile:
420
return Entry::frsOptional;
422
return Entry::frsIgnored;
427
case EntryField::ftAuthor:
428
case EntryField::ftEditor:
429
case EntryField::ftTitle:
430
case EntryField::ftPublisher:
431
case EntryField::ftYear:
432
return Entry::frsRequired;
433
case EntryField::ftVolume:
434
case EntryField::ftNumber:
435
case EntryField::ftSeries:
436
case EntryField::ftAddress:
437
case EntryField::ftDoi:
438
case EntryField::ftEdition:
439
case EntryField::ftMonth:
440
case EntryField::ftNote:
441
case EntryField::ftKey:
442
case EntryField::ftISBN:
443
case EntryField::ftURL:
444
case EntryField::ftLocalFile:
445
return Entry::frsOptional;
447
return Entry::frsIgnored;
452
case EntryField::ftTitle:
453
return Entry::frsRequired;
454
case EntryField::ftAuthor:
455
case EntryField::ftHowPublished:
456
case EntryField::ftAddress:
457
case EntryField::ftDoi:
458
case EntryField::ftMonth:
459
case EntryField::ftYear:
460
case EntryField::ftNote:
461
case EntryField::ftKey:
462
case EntryField::ftISBN:
463
case EntryField::ftURL:
464
case EntryField::ftLocalFile:
465
return Entry::frsOptional;
467
return Entry::frsIgnored;
472
case EntryField::ftTitle:
473
case EntryField::ftURL:
474
return Entry::frsRequired;
475
case EntryField::ftAuthor:
476
case EntryField::ftHowPublished:
477
case EntryField::ftDoi:
478
case EntryField::ftMonth:
479
case EntryField::ftYear:
480
case EntryField::ftKey:
481
case EntryField::ftLocalFile:
482
return Entry::frsOptional;
484
return Entry::frsIgnored;
489
case EntryField::ftAuthor:
490
case EntryField::ftEditor:
491
case EntryField::ftTitle:
492
case EntryField::ftPages:
493
case EntryField::ftChapter:
494
case EntryField::ftPublisher:
495
case EntryField::ftYear:
496
return Entry::frsRequired;
497
case EntryField::ftVolume:
498
case EntryField::ftSeries:
499
case EntryField::ftAddress:
500
case EntryField::ftDoi:
501
case EntryField::ftEdition:
502
case EntryField::ftMonth:
503
case EntryField::ftNote:
504
case EntryField::ftCrossRef:
505
case EntryField::ftKey:
506
case EntryField::ftISBN:
507
case EntryField::ftURL:
508
case EntryField::ftLocalFile:
509
return Entry::frsOptional;
511
return Entry::frsIgnored;
516
case EntryField::ftAuthor:
517
case EntryField::ftTitle:
518
case EntryField::ftBookTitle:
519
case EntryField::ftPublisher:
520
case EntryField::ftYear:
521
return Entry::frsRequired;
522
case EntryField::ftEditor:
523
case EntryField::ftPages:
524
case EntryField::ftOrganization:
525
case EntryField::ftAddress:
526
case EntryField::ftMonth:
527
case EntryField::ftLocation:
528
case EntryField::ftNote:
529
case EntryField::ftCrossRef:
530
case EntryField::ftDoi:
531
case EntryField::ftKey:
532
case EntryField::ftType:
533
case EntryField::ftISBN:
534
case EntryField::ftURL:
535
case EntryField::ftLocalFile:
536
return Entry::frsOptional;
538
return Entry::frsIgnored;
540
case etInProceedings:
543
case EntryField::ftAuthor:
544
case EntryField::ftTitle:
545
case EntryField::ftYear:
546
case EntryField::ftBookTitle:
547
return Entry::frsRequired;
548
case EntryField::ftPages:
549
case EntryField::ftEditor:
550
case EntryField::ftVolume:
551
case EntryField::ftNumber:
552
case EntryField::ftSeries:
553
case EntryField::ftType:
554
case EntryField::ftChapter:
555
case EntryField::ftAddress:
556
case EntryField::ftDoi:
557
case EntryField::ftEdition:
558
case EntryField::ftLocation:
559
case EntryField::ftMonth:
560
case EntryField::ftNote:
561
case EntryField::ftCrossRef:
562
case EntryField::ftPublisher:
563
case EntryField::ftISBN:
564
case EntryField::ftURL:
565
case EntryField::ftLocalFile:
566
return Entry::frsOptional;
568
return Entry::frsIgnored;
573
case EntryField::ftTitle:
574
return Entry::frsRequired;
575
case EntryField::ftAuthor:
576
case EntryField::ftOrganization:
577
case EntryField::ftAddress:
578
case EntryField::ftDoi:
579
case EntryField::ftEdition:
580
case EntryField::ftMonth:
581
case EntryField::ftYear:
582
case EntryField::ftNote:
583
case EntryField::ftISBN:
584
case EntryField::ftURL:
585
case EntryField::ftLocalFile:
586
return Entry::frsOptional;
588
return Entry::frsIgnored;
590
case etMastersThesis:
593
case EntryField::ftAuthor:
594
case EntryField::ftTitle:
595
case EntryField::ftSchool:
596
case EntryField::ftYear:
597
return Entry::frsRequired;
598
case EntryField::ftAddress:
599
case EntryField::ftMonth:
600
case EntryField::ftDoi:
601
case EntryField::ftNote:
602
case EntryField::ftKey:
603
case EntryField::ftURL:
604
case EntryField::ftLocalFile:
605
return Entry::frsOptional;
607
return Entry::frsIgnored;
612
case EntryField::ftAuthor:
613
case EntryField::ftTitle:
614
case EntryField::ftHowPublished:
615
case EntryField::ftMonth:
616
case EntryField::ftYear:
617
case EntryField::ftDoi:
618
case EntryField::ftNote:
619
case EntryField::ftKey:
620
case EntryField::ftURL:
621
case EntryField::ftLocalFile:
622
return Entry::frsOptional;
624
return Entry::frsIgnored;
629
case EntryField::ftAuthor:
630
case EntryField::ftTitle:
631
case EntryField::ftSchool:
632
case EntryField::ftYear:
633
return Entry::frsRequired;
634
case EntryField::ftAddress:
635
case EntryField::ftMonth:
636
case EntryField::ftNote:
637
case EntryField::ftDoi:
638
case EntryField::ftKey:
639
case EntryField::ftISBN:
640
case EntryField::ftURL:
641
case EntryField::ftLocalFile:
642
return Entry::frsOptional;
644
return Entry::frsIgnored;
650
case EntryField::ftTitle:
651
case EntryField::ftYear:
652
return Entry::frsRequired;
653
case EntryField::ftEditor:
654
case EntryField::ftPublisher:
655
case EntryField::ftOrganization:
656
case EntryField::ftAddress:
657
case EntryField::ftMonth:
658
case EntryField::ftLocation:
659
case EntryField::ftNote:
660
case EntryField::ftDoi:
661
case EntryField::ftKey:
662
case EntryField::ftSeries:
663
case EntryField::ftBookTitle:
664
case EntryField::ftISBN:
665
case EntryField::ftURL:
666
case EntryField::ftLocalFile:
667
return Entry::frsOptional;
669
return Entry::frsIgnored;
674
case EntryField::ftAuthor:
675
case EntryField::ftTitle:
676
case EntryField::ftInstitution:
677
case EntryField::ftYear:
678
return Entry::frsRequired;
679
case EntryField::ftType:
680
case EntryField::ftDoi:
681
case EntryField::ftNumber:
682
case EntryField::ftAddress:
683
case EntryField::ftMonth:
684
case EntryField::ftNote:
685
case EntryField::ftKey:
686
case EntryField::ftURL:
687
case EntryField::ftLocalFile:
688
case EntryField::ftISSN:
689
return Entry::frsOptional;
691
return Entry::frsIgnored;
696
case EntryField::ftAuthor:
697
case EntryField::ftTitle:
698
case EntryField::ftNote:
699
return Entry::frsRequired;
700
case EntryField::ftMonth:
701
case EntryField::ftYear:
702
case EntryField::ftDoi:
703
case EntryField::ftKey:
704
case EntryField::ftURL:
705
case EntryField::ftLocalFile:
706
return Entry::frsOptional;
708
return Entry::frsIgnored;
711
return Entry::frsOptional;