diff options
Diffstat (limited to 'src/entry.cpp')
-rw-r--r-- | src/entry.cpp | 714 |
1 files changed, 714 insertions, 0 deletions
diff --git a/src/entry.cpp b/src/entry.cpp new file mode 100644 index 0000000..fcd81fd --- /dev/null +++ b/src/entry.cpp @@ -0,0 +1,714 @@ +/*************************************************************************** +* Copyright (C) 2004-2009 by Thomas Fischer * +* [email protected] * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * +***************************************************************************/ +#include <qstring.h> +#include <qstringlist.h> +#include <qregexp.h> + +#include <entry.h> +#include <file.h> +#include <xsltransform.h> +#include <entryfield.h> + +#define max(a,b) ((a)>(b)?(a):(b)) + +namespace BibTeX +{ + + Entry::Entry( ) + : Element(), m_entryType( etUnknown ), m_entryTypeString( QString::null ), m_id( QString::null ) + { + // nothing + } + + Entry::Entry( const EntryType entryType, const QString &id ) + : Element( ), m_entryType( entryType ), m_id( id ) + { + m_entryTypeString = entryTypeToString( entryType ); + } + + Entry::Entry( const QString& entryTypeString, const QString& id ) : Element( ), m_entryTypeString( entryTypeString ), m_id( id ) + { + m_entryType = entryTypeFromString( entryTypeString ); + if ( m_entryType != etUnknown ) + m_entryTypeString = entryTypeToString( m_entryType ); + } + + Entry::Entry( const Entry *other ) + { + copyFrom( other ); + } + + Entry::~Entry() + { + for ( EntryFields::iterator it = m_fields.begin(); it != m_fields.end(); it++ ) + { + delete( *it ); + } + } + + Element* Entry::clone() + { + return new Entry( this ); + } + + bool Entry::equals( const Entry &other ) + { + if ( other.id().compare( id() ) != 0 ) + return false; + + for ( EntryFields::iterator it = m_fields.begin(); it != m_fields.end(); it++ ) + { + EntryField *field1 = *it; + EntryField *field2 = other.getField( field1->fieldTypeName() ); + + if ( field2 == NULL || field1->value() == NULL || field2->value() == NULL || field1->value()->text().compare( field2->value()->text() ) != 0 ) + return false; + } + + return true; + } + + QString Entry::text() const + { + QString result = "Id: "; + result.append( m_id ).append( " (" ).append( entryTypeString() ).append( ")\n" ); + + for ( EntryFields::ConstIterator it = m_fields.begin(); it != m_fields.end(); it++ ) + { + result.append(( *it )->fieldTypeName() ).append( ": " ); + result.append(( *it )->value()->text() ).append( "\n" ); + } + + return result; + } + + void Entry::setEntryType( const EntryType entryType ) + { + m_entryType = entryType; + m_entryTypeString = entryTypeToString( entryType ); + } + + void Entry::setEntryTypeString( const QString& entryTypeString ) + { + m_entryTypeString = entryTypeString; + m_entryType = entryTypeFromString( entryTypeString ); + } + + Entry::EntryType Entry::entryType() const + { + return m_entryType; + } + + QString Entry::entryTypeString() const + { + return m_entryTypeString; + } + + void Entry::setId( const QString& id ) + { + m_id = id; + } + + QString Entry::id() const + { + return m_id; + } + + bool Entry::containsPattern( const QString & pattern, EntryField::FieldType fieldType, BibTeX::Element::FilterType filterType, bool caseSensitive ) const + { + if ( filterType == ftExact ) + { + /** check for exact match */ + bool result = fieldType == EntryField::ftUnknown && m_id.contains( pattern, caseSensitive ); + + for ( EntryFields::ConstIterator it = m_fields.begin(); !result && it != m_fields.end(); it++ ) + if ( fieldType == EntryField::ftUnknown || ( *it ) ->fieldType() == fieldType ) + result |= ( *it ) ->value() ->containsPattern( pattern, caseSensitive ); + + return result; + } + else + { + /** for each word in the search pattern ... */ + QStringList words = QStringList::split( QRegExp( "\\s+" ), pattern ); + bool *hits = new bool[words.count()]; + int i = 0; + for ( QStringList::Iterator wit = words.begin(); wit != words.end(); ++wit, ++i ) + { + hits[i] = fieldType == EntryField::ftUnknown && m_id.contains( *wit, caseSensitive ); + + /** check if word is contained in any field */ + for ( EntryFields::ConstIterator fit = m_fields.begin(); fit != m_fields.end(); ++fit ) + if ( fieldType == EntryField::ftUnknown || ( *fit ) ->fieldType() == fieldType ) + hits[i] |= ( *fit ) ->value() ->containsPattern( *wit, caseSensitive ); + } + + unsigned int hitCount = 0; + for ( i = words.count() - 1; i >= 0; --i ) + if ( hits[i] ) ++hitCount; + delete[] hits; + + /** return success depending on filter type and number of hits */ + return (( filterType == ftAnyWord && hitCount > 0 ) || ( filterType == ftEveryWord && hitCount == words.count() ) ); + } + } + + QStringList Entry::urls() const + { + QStringList result; + const QString fieldNames[] = {"localfile", "pdf", "ps", "postscript", "doi", "url", "howpublished", "ee", "biburl", "note"}; + const int fieldNamesCount = sizeof( fieldNames ) / sizeof( fieldNames[0] ); + + for ( int j = 1; j < 5 ; ++j ) /** there may be variants such as url3 or doi2 */ + for ( int i = 0; i < fieldNamesCount; i++ ) + { + QString fieldName = fieldNames[i]; + /** field names should be like url, url2, url3, ... */ + if ( j > 1 ) fieldName.append( QString::number( j ) ); + + EntryField * field = getField( fieldName ); + if (( field && !field->value()->items.isEmpty() ) ) + { + PlainText *plainText = dynamic_cast<PlainText*>( field->value()->items.first() ); + if ( plainText != NULL ) + { + QString plain = plainText->text(); + int urlPos = plain.find( "\\url{", 0, FALSE ); + if ( urlPos > -1 ) + { + plain = plain.mid( urlPos + 5 ); + urlPos = plain.find( "}", 0, FALSE ); + if ( urlPos > 0 ) + plain = plain.left( urlPos - 1 ); + } + + if ( fieldNames[ i ] == "doi" && !plain.startsWith( "http", FALSE ) ) + plain.prepend( "http://dx.doi.org/" ); + + result.append( plain ); + } + } + } + + return result; + } + + bool Entry::addField( EntryField * field ) + { + m_fields.append( field ); + return TRUE; + } + + EntryField* Entry::getField( const EntryField::FieldType fieldType ) const + { + EntryField * result = NULL; + + for ( EntryFields::ConstIterator it = m_fields.begin(); ( it != m_fields.end() ) && ( result == NULL ); it++ ) + if (( *it ) ->fieldType() == fieldType ) result = *it; + + return result; + } + + EntryField* Entry::getField( const QString & fieldName ) const + { + EntryField * result = NULL; + + for ( EntryFields::ConstIterator it = m_fields.begin(); ( it != m_fields.end() ) && ( result == NULL ); it++ ) + if (( *it ) ->fieldTypeName().lower() == fieldName.lower() ) + result = *it; + + return result; + } + + bool Entry::deleteField( const QString & fieldName ) + { + for ( EntryFields::ConstIterator it = m_fields.begin(); it != m_fields.end(); it++ ) + if (( *it ) ->fieldTypeName().lower() == fieldName.lower() ) + { + delete( *it ); + m_fields.remove( *it ); + return TRUE; + } + + return FALSE; + } + + bool Entry::deleteField( const EntryField::FieldType fieldType ) + { + for ( EntryFields::iterator it = m_fields.begin(); it != m_fields.end(); it++ ) + if (( *it ) ->fieldType() == fieldType ) + { + delete( *it ); + m_fields.remove( it ); + return TRUE; + } + + return FALSE; + } + + Entry::EntryFields::ConstIterator Entry::begin() const + { + return m_fields.constBegin(); + } + + Entry::EntryFields::ConstIterator Entry::end() const + { + return m_fields.constEnd(); + } + + int Entry::getFieldCount() const + { + return m_fields.count(); + } + + void Entry::clearFields() + { + for ( EntryFields::iterator it = m_fields.begin(); it != m_fields.end(); it++ ) + delete( *it ); + m_fields.clear(); + } + + void Entry::copyFrom( const Entry *other ) + { + if ( other == NULL ) return; + + m_entryType = other->m_entryType; + m_entryTypeString = other->m_entryTypeString; + m_id = other->m_id; + clearFields(); + for ( EntryFields::ConstIterator it = other->m_fields.begin(); it != other->m_fields.end(); it++ ) + m_fields.append( new EntryField( *it ) ); + } + + void Entry::merge( BibTeX::Entry *other, MergeSemantics mergeSemantics ) + { + for ( EntryFields::iterator it = other->m_fields.begin(); it != other->m_fields.end(); it++ ) + { + EntryField *otherField = new EntryField( *it ); + EntryField::FieldType otherFieldType = otherField->fieldType(); + QString otherFieldTypeName = otherField->fieldTypeName(); + EntryField *thisField = otherFieldType != EntryField::ftUnknown ? getField( otherFieldType ) : getField( otherFieldTypeName ); + + if ( thisField == NULL ) + { + m_fields.append( otherField ); + } + else if ( otherField->value()->text() == thisField->value()->text() && mergeSemantics == msForceAdding ) + { + otherFieldTypeName.prepend( "OPT" ); + otherField->setFieldType( EntryField::ftUnknown, otherFieldTypeName ); + m_fields.append( otherField ); + } + } + } + + QString Entry::entryTypeToString( const EntryType entryType ) + { + switch ( entryType ) + { + case etArticle: + return QString( "Article" ); + case etBook: + return QString( "Book" ); + case etBooklet: + return QString( "Booklet" ); + case etCollection: + return QString( "Collection" ); + case etElectronic: + return QString( "Electronic" ); + case etInBook: + return QString( "InBook" ); + case etInCollection: + return QString( "InCollection" ); + case etInProceedings: + return QString( "InProceedings" ); + case etManual: + return QString( "Manual" ); + case etMastersThesis: + return QString( "MastersThesis" ); + case etMisc: + return QString( "Misc" ); + case etPhDThesis: + return QString( "PhDThesis" ); + case etProceedings: + return QString( "Proceedings" ); + case etTechReport: + return QString( "TechReport" ); + case etUnpublished: + return QString( "Unpublished" ); + default: + return QString( "Unknown" ); + } + } + + Entry::EntryType Entry::entryTypeFromString( const QString & entryTypeString ) + { + QString entryTypeStringLower = entryTypeString.lower(); + if ( entryTypeStringLower == "article" ) + return etArticle; + else if ( entryTypeStringLower == "book" ) + return etBook; + else if ( entryTypeStringLower == "booklet" ) + return etBooklet; + else if ( entryTypeStringLower == "collection" ) + return etCollection; + else if (( entryTypeStringLower == "electronic" ) || ( entryTypeStringLower == "online" ) || ( entryTypeStringLower == "internet" ) || ( entryTypeStringLower == "webpage" ) ) + return etElectronic; + else if ( entryTypeStringLower == "inbook" ) + return etInBook; + else if ( entryTypeStringLower == "incollection" ) + return etInCollection; + else if (( entryTypeStringLower == "inproceedings" ) || ( entryTypeStringLower == "conference" ) ) + return etInProceedings; + else if ( entryTypeStringLower == "manual" ) + return etManual; + else if ( entryTypeStringLower == "mastersthesis" ) + return etMastersThesis; + else if ( entryTypeStringLower == "misc" ) + return etMisc; + else if ( entryTypeStringLower == "phdthesis" ) + return etPhDThesis; + else if ( entryTypeStringLower == "proceedings" ) + return etProceedings; + else if ( entryTypeStringLower == "techreport" ) + return etTechReport; + else if ( entryTypeStringLower == "unpublished" ) + return etUnpublished; + else + return etUnknown; + } + + Entry::FieldRequireStatus Entry::getRequireStatus( Entry::EntryType entryType, EntryField::FieldType fieldType ) + { + switch ( entryType ) + { + case etArticle: + switch ( fieldType ) + { + case EntryField::ftAuthor: + case EntryField::ftTitle: + case EntryField::ftJournal: + case EntryField::ftYear: + return Entry::frsRequired; + case EntryField::ftVolume: + case EntryField::ftMonth: + case EntryField::ftDoi: + case EntryField::ftNumber: + case EntryField::ftPages: + case EntryField::ftNote: + case EntryField::ftKey: + case EntryField::ftISSN: + case EntryField::ftURL: + case EntryField::ftLocalFile: + return Entry::frsOptional; + default: + return Entry::frsIgnored; + } + case etBook: + switch ( fieldType ) + { + case EntryField::ftAuthor: + case EntryField::ftEditor: + case EntryField::ftTitle: + case EntryField::ftPublisher: + case EntryField::ftYear: + return Entry::frsRequired; + case EntryField::ftVolume: + case EntryField::ftNumber: + case EntryField::ftSeries: + case EntryField::ftAddress: + case EntryField::ftDoi: + case EntryField::ftEdition: + case EntryField::ftMonth: + case EntryField::ftNote: + case EntryField::ftKey: + case EntryField::ftISBN: + case EntryField::ftURL: + case EntryField::ftLocalFile: + return Entry::frsOptional; + default: + return Entry::frsIgnored; + } + case etBooklet: + switch ( fieldType ) + { + case EntryField::ftTitle: + return Entry::frsRequired; + case EntryField::ftAuthor: + case EntryField::ftHowPublished: + case EntryField::ftAddress: + case EntryField::ftDoi: + case EntryField::ftMonth: + case EntryField::ftYear: + case EntryField::ftNote: + case EntryField::ftKey: + case EntryField::ftISBN: + case EntryField::ftURL: + case EntryField::ftLocalFile: + return Entry::frsOptional; + default: + return Entry::frsIgnored; + } + case etElectronic: + switch ( fieldType ) + { + case EntryField::ftTitle: + case EntryField::ftURL: + return Entry::frsRequired; + case EntryField::ftAuthor: + case EntryField::ftHowPublished: + case EntryField::ftDoi: + case EntryField::ftMonth: + case EntryField::ftYear: + case EntryField::ftKey: + case EntryField::ftLocalFile: + return Entry::frsOptional; + default: + return Entry::frsIgnored; + } + case etInBook: + switch ( fieldType ) + { + case EntryField::ftAuthor: + case EntryField::ftEditor: + case EntryField::ftTitle: + case EntryField::ftPages: + case EntryField::ftChapter: + case EntryField::ftPublisher: + case EntryField::ftYear: + return Entry::frsRequired; + case EntryField::ftVolume: + case EntryField::ftSeries: + case EntryField::ftAddress: + case EntryField::ftDoi: + case EntryField::ftEdition: + case EntryField::ftMonth: + case EntryField::ftNote: + case EntryField::ftCrossRef: + case EntryField::ftKey: + case EntryField::ftISBN: + case EntryField::ftURL: + case EntryField::ftLocalFile: + return Entry::frsOptional; + default: + return Entry::frsIgnored; + } + case etInCollection: + switch ( fieldType ) + { + case EntryField::ftAuthor: + case EntryField::ftTitle: + case EntryField::ftBookTitle: + case EntryField::ftPublisher: + case EntryField::ftYear: + return Entry::frsRequired; + case EntryField::ftEditor: + case EntryField::ftPages: + case EntryField::ftOrganization: + case EntryField::ftAddress: + case EntryField::ftMonth: + case EntryField::ftLocation: + case EntryField::ftNote: + case EntryField::ftCrossRef: + case EntryField::ftDoi: + case EntryField::ftKey: + case EntryField::ftType: + case EntryField::ftISBN: + case EntryField::ftURL: + case EntryField::ftLocalFile: + return Entry::frsOptional; + default: + return Entry::frsIgnored; + } + case etInProceedings: + switch ( fieldType ) + { + case EntryField::ftAuthor: + case EntryField::ftTitle: + case EntryField::ftYear: + case EntryField::ftBookTitle: + return Entry::frsRequired; + case EntryField::ftPages: + case EntryField::ftEditor: + case EntryField::ftVolume: + case EntryField::ftNumber: + case EntryField::ftSeries: + case EntryField::ftType: + case EntryField::ftChapter: + case EntryField::ftAddress: + case EntryField::ftDoi: + case EntryField::ftEdition: + case EntryField::ftLocation: + case EntryField::ftMonth: + case EntryField::ftNote: + case EntryField::ftCrossRef: + case EntryField::ftPublisher: + case EntryField::ftISBN: + case EntryField::ftURL: + case EntryField::ftLocalFile: + return Entry::frsOptional; + default: + return Entry::frsIgnored; + } + case etManual: + switch ( fieldType ) + { + case EntryField::ftTitle: + return Entry::frsRequired; + case EntryField::ftAuthor: + case EntryField::ftOrganization: + case EntryField::ftAddress: + case EntryField::ftDoi: + case EntryField::ftEdition: + case EntryField::ftMonth: + case EntryField::ftYear: + case EntryField::ftNote: + case EntryField::ftISBN: + case EntryField::ftURL: + case EntryField::ftLocalFile: + return Entry::frsOptional; + default: + return Entry::frsIgnored; + } + case etMastersThesis: + switch ( fieldType ) + { + case EntryField::ftAuthor: + case EntryField::ftTitle: + case EntryField::ftSchool: + case EntryField::ftYear: + return Entry::frsRequired; + case EntryField::ftAddress: + case EntryField::ftMonth: + case EntryField::ftDoi: + case EntryField::ftNote: + case EntryField::ftKey: + case EntryField::ftURL: + case EntryField::ftLocalFile: + return Entry::frsOptional; + default: + return Entry::frsIgnored; + } + case etMisc: + switch ( fieldType ) + { + case EntryField::ftAuthor: + case EntryField::ftTitle: + case EntryField::ftHowPublished: + case EntryField::ftMonth: + case EntryField::ftYear: + case EntryField::ftDoi: + case EntryField::ftNote: + case EntryField::ftKey: + case EntryField::ftURL: + case EntryField::ftLocalFile: + return Entry::frsOptional; + default: + return Entry::frsIgnored; + } + case etPhDThesis: + switch ( fieldType ) + { + case EntryField::ftAuthor: + case EntryField::ftTitle: + case EntryField::ftSchool: + case EntryField::ftYear: + return Entry::frsRequired; + case EntryField::ftAddress: + case EntryField::ftMonth: + case EntryField::ftNote: + case EntryField::ftDoi: + case EntryField::ftKey: + case EntryField::ftISBN: + case EntryField::ftURL: + case EntryField::ftLocalFile: + return Entry::frsOptional; + default: + return Entry::frsIgnored; + } + case etCollection: + case etProceedings: + switch ( fieldType ) + { + case EntryField::ftTitle: + case EntryField::ftYear: + return Entry::frsRequired; + case EntryField::ftEditor: + case EntryField::ftPublisher: + case EntryField::ftOrganization: + case EntryField::ftAddress: + case EntryField::ftMonth: + case EntryField::ftLocation: + case EntryField::ftNote: + case EntryField::ftDoi: + case EntryField::ftKey: + case EntryField::ftSeries: + case EntryField::ftBookTitle: + case EntryField::ftISBN: + case EntryField::ftURL: + case EntryField::ftLocalFile: + return Entry::frsOptional; + default: + return Entry::frsIgnored; + } + case etTechReport: + switch ( fieldType ) + { + case EntryField::ftAuthor: + case EntryField::ftTitle: + case EntryField::ftInstitution: + case EntryField::ftYear: + return Entry::frsRequired; + case EntryField::ftType: + case EntryField::ftDoi: + case EntryField::ftNumber: + case EntryField::ftAddress: + case EntryField::ftMonth: + case EntryField::ftNote: + case EntryField::ftKey: + case EntryField::ftURL: + case EntryField::ftLocalFile: + case EntryField::ftISSN: + return Entry::frsOptional; + default: + return Entry::frsIgnored; + } + case etUnpublished: + switch ( fieldType ) + { + case EntryField::ftAuthor: + case EntryField::ftTitle: + case EntryField::ftNote: + return Entry::frsRequired; + case EntryField::ftMonth: + case EntryField::ftYear: + case EntryField::ftDoi: + case EntryField::ftKey: + case EntryField::ftURL: + case EntryField::ftLocalFile: + return Entry::frsOptional; + default: + return Entry::frsIgnored; + } + default: + return Entry::frsOptional; + } + } +} |