You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kbibtex/src/idsuggestions.cpp

364 lines
14 KiB

/***************************************************************************
* Copyright (C) 2004-2009 by Thomas Fischer *
* fischer@unix-ag.uni-kl.de *
* *
* 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 <tqregexp.h>
#include <tdelocale.h>
#include "encoderlatex.h"
#include "file.h"
#include "settings.h"
#include "entry.h"
#include "idsuggestions.h"
namespace KBibTeX
{
const TQRegExp IdSuggestions::unwantedChars = TQRegExp( "[^-_:/=+a-zA-Z0-9]+" );
IdSuggestions::IdSuggestions()
{
// nothing
}
IdSuggestions::~IdSuggestions()
{
// nothing
}
/**
* Determine list of authors or editors for a given entry
*/
TQStringList IdSuggestions::authorsLastName( BibTeX::Entry *entry )
{
TQStringList result;
/** retrieve field holding authors information for entry */
BibTeX::EntryField *field = entry->getField( BibTeX::EntryField::ftAuthor );
if ( field == NULL )
{
/** no author field available, try editor
patch by Jurgen Spitzmuller <juergen.sp@t-online.de> */
field = entry->getField( BibTeX::EntryField::ftEditor );
if ( field == NULL )
{
return result; /** neither author nor editor available */
}
}
/** fetch container holding list of author names */
BibTeX::PersonContainer *personContainer = field != NULL ? dynamic_cast<BibTeX::PersonContainer*>( field->value()->items.isEmpty() ? NULL : field->value()->items.first() ) : NULL;
if ( personContainer == NULL || personContainer->persons.isEmpty() )
return result; /** container not found or is empty */
/** iterate through container and fetch each author's last name */
for ( TQValueList<BibTeX::Person*>::ConstIterator it = personContainer->persons.begin(); it != personContainer->persons.end(); ++it )
{
result.append( normalizeText(( *it )->lastName() ) );
}
return result;
}
/**
* Normalize a given text by removing spaces or other unwanted characters,
* replace some accented and special characters by plain ASCII transliterations
*/
TQString IdSuggestions::normalizeText( const TQString& text )
{
TQString result = text;
for ( int i = text.length() - 1; i >= 0; --i )
result[i] = TQChar( BibTeX::EncoderLaTeX::unicodeToASCII( result[i].unicode() ) );
return result.replace( unwantedChars, "" );
}
TQString IdSuggestions::resolveConflict( BibTeX::File *file, const TQString &id, BibTeX::Element *element )
{
TQString result = id;
BibTeX::Element *hit = file->containsKey( id ) ;
if ( hit != NULL && hit != element )
{
int i = 0;
do
{
result = TQString( "%1-%2" ).arg( id ).arg( ++i );
hit = file->containsKey( result );
}
while ( hit != NULL && hit != element );
}
return result;
}
/**
* Determine year for a given entry
*/
int IdSuggestions::extractYear( BibTeX::Entry *entry )
{
/** retrieve field holding year information for entry */
BibTeX::EntryField *field = entry->getField( BibTeX::EntryField::ftYear );
if ( field == NULL )
return -1; /** no year field available */
/** fetch value item holding year */
BibTeX::ValueItem *valueItem = field != NULL ? ( field->value()->items.isEmpty() ? NULL : field->value()->items.first() ) : NULL;
if ( valueItem == NULL )
return -1; /** no value item found or is empty */
/** parse value item's text */
bool ok = FALSE;
TQRegExp yearRegExp( "\\b(\\d{2})?\\d{2}\\b" );
yearRegExp.search( valueItem->text() );
int year = TQString( yearRegExp.cap( 0 ) ).toInt( &ok );
if ( !ok ) year = -1;
return year;
}
/**
* Determine title for a given entry
*/
TQString IdSuggestions::extractTitle( BibTeX::Entry *entry )
{
/** retrieve field holding title information for entry */
BibTeX::EntryField *field = entry->getField( BibTeX::EntryField::ftTitle );
if ( field == NULL )
return TQString::null; /** no title field available */
/** *fetch value item holding title */
BibTeX::ValueItem *valueItem = field->value()->items.isEmpty() ? NULL : field->value()->items.first();
if ( valueItem == NULL )
return TQString::null; /** no value item found or is empty */
return valueItem->text();
}
TQStringList IdSuggestions::createSuggestions( BibTeX::File *file, BibTeX::Entry *entry )
{
Settings * settings = Settings::self();
const TQStringList& formatStrList = settings->idSuggestions_formatStrList;
TQStringList result;
TQStringList allKeys = file != NULL ? file->allKeys() : TQStringList();
entry = new BibTeX::Entry( entry );
if ( file != NULL )
file->completeReferencedFields( entry );
for ( TQStringList::ConstIterator it = formatStrList.begin(); it != formatStrList.end(); ++it )
{
TQString id = formatId( entry, *it );
if ( id.isEmpty() || result.contains( id ) )
continue;
if ( !result.contains( id ) )
result.append( id );
}
delete entry;
return result;
}
TQString IdSuggestions::createDefaultSuggestion( BibTeX::File *file, BibTeX::Entry *entry )
{
Settings * settings = Settings::self();
if ( settings->idSuggestions_default < 0 || settings->idSuggestions_default >= ( int )settings->idSuggestions_formatStrList.size() )
return TQString::null;
entry = new BibTeX::Entry( entry );
if ( file != NULL )
file->completeReferencedFields( entry );
TQString result = formatId( entry, settings->idSuggestions_formatStrList[settings->idSuggestions_default] );
delete entry;
return result;
}
TQString IdSuggestions::formatId( BibTeX::Entry *entry, const TQString& formatStr )
{
TQString id;
TQStringList tokenList = TQStringList::split( '|', formatStr );
for ( TQStringList::ConstIterator tit = tokenList.begin(); tit != tokenList.end(); ++tit )
id.append( translateToken( entry, *tit ) );
return id;
}
TQString IdSuggestions::translateToken( BibTeX::Entry *entry, const TQString& token )
{
switch ( token[0] )
{
case 'a': return translateAuthorsToken( entry, token.mid( 1 ), aOnlyFirst );
case 'A': return translateAuthorsToken( entry, token.mid( 1 ), aAll );
case 'z': return translateAuthorsToken( entry, token.mid( 1 ), aNotFirst );
case 'y':
{
int year = extractYear( entry );
if ( year > -1 )
return TQString::number( year % 100 + 100 ).mid( 1 );
else
return TQString::null;
}
case 'Y':
{
int year = extractYear( entry );
if ( year > -1 )
return TQString::number( year % 10000 + 10000 ).mid( 1 );
else
return TQString::null;
}
case 't': return translateTitleToken( entry, token.mid( 1 ), FALSE );
case 'T': return translateTitleToken( entry, token.mid( 1 ), TRUE );
case '"': return token.mid( 1 );
default: return TQString::null;
}
}
TQString IdSuggestions::translateAuthorsToken( BibTeX::Entry *entry, const TQString& token, Authors selectAuthors )
{
struct IdSuggestionTokenInfo ati = evalToken( token );
TQString result;
bool first = true, firstInserted = true;
TQStringList authors = authorsLastName( entry );
for ( TQStringList::ConstIterator it = authors.begin(); it != authors.end(); ++it )
{
TQString author = normalizeText( *it ).left( ati.len );
if ( selectAuthors == aAll || ( selectAuthors == aOnlyFirst && first ) || ( selectAuthors == aNotFirst && !first ) )
{
if ( !firstInserted )
result.append( ati.inBetween );
result.append( author );
firstInserted = false;
}
first = false;
}
if ( ati.toUpper )
result = result.upper();
else if ( ati.toLower )
result = result.lower();
return result;
}
struct IdSuggestionTokenInfo IdSuggestions::evalToken( const TQString& token )
{
unsigned int pos = 0;
struct IdSuggestionTokenInfo result;
result.len = 0x00ffffff;
result.toLower = FALSE;
result.toUpper = FALSE;
result.inBetween = TQString::null;
if ( token.length() > pos )
{
int dv = token[pos].digitValue();
if ( dv > -1 )
{
result.len = dv;
++pos;
}
}
if ( token.length() > pos )
{
result.toLower = token[pos] == 'l';
result.toUpper = token[pos] == 'u';
if ( result.toUpper || result.toLower )
++pos;
}
if ( token.length() > pos + 1 && token[pos] == '"' )
result.inBetween = token.mid( pos + 1 );
return result;
}
TQString IdSuggestions::translateTitleToken( BibTeX::Entry *entry, const TQString& token, bool removeSmallWords )
{
struct IdSuggestionTokenInfo tti = evalToken( token );
Settings * settings = Settings::self();
const TQStringList smallWords = settings->idSuggestions_smallWords;
TQString result;
bool first = TRUE;
TQStringList titleWords = TQStringList::split( TQRegExp( "\\s+" ), extractTitle( entry ) );
for ( TQStringList::ConstIterator it = titleWords.begin(); it != titleWords.end(); ++it )
{
if ( first )
first = FALSE;
else
result.append( tti.inBetween );
TQString lowerText = ( *it ).lower();
if ( !removeSmallWords || !smallWords.contains( lowerText ) )
result.append( normalizeText( *it ).left( tti.len ) );
}
if ( tti.toUpper )
result = result.upper();
else if ( tti.toLower )
result = result.lower();
return result;
}
/** convert a formatting string into a human readable version (even translated) */
TQString IdSuggestions::formatStrToHuman( const TQString& formatStr )
{
bool first = TRUE;
TQString text;
TQStringList elements = TQStringList::split( '|', formatStr );
for ( TQStringList::iterator it = elements.begin();it != elements.end();++it )
{
if ( first ) first = FALSE; else text.append( "\n" );
if (( *it )[0] == 'a' || ( *it )[0] == 'A' || ( *it )[0] == 'z' )
{
struct IdSuggestionTokenInfo info = evalToken(( *it ).mid( 1 ) );
if (( *it )[0] == 'a' ) text.append( i18n( "First author only" ) );
else if (( *it )[0] == 'z' ) text.append( i18n( "All but first author" ) );
else text.append( i18n( "All authors" ) );
int n = info.len;
if ( info.len < 0x00ffffff ) text.append( i18n( ", but only first letter of each last name", ", but only first %n letters of each last name", n ) );
if ( info.toUpper ) text.append( i18n( ", in upper case" ) );
else if ( info.toLower ) text.append( i18n( ", in lower case" ) );
if ( info.inBetween != TQString::null ) text.append( TQString( i18n( ", with '%1' in between" ) ).arg( info.inBetween ) );
}
else if (( *it )[0] == 'y' ) text.append( i18n( "Year (2 digits)" ) );
else if (( *it )[0] == 'Y' ) text.append( i18n( "Year (4 digits)" ) );
else if (( *it )[0] == 't' || ( *it )[0] == 'T' )
{
struct IdSuggestionTokenInfo info = evalToken(( *it ).mid( 1 ) );
text.append( i18n( "Title" ) );
int n = info.len;
if ( info.len < 0x00ffffff ) text.append( i18n( ", but only first letter of each word", ", but only first %n letters of each word", n ) );
if ( info.toUpper ) text.append( i18n( ", in upper case" ) );
else if ( info.toLower ) text.append( i18n( ", in lower case" ) );
if ( info.inBetween != TQString::null ) text.append( TQString( i18n( ", with '%1' in between" ) ).arg( info.inBetween ) );
if (( *it )[0] == 'T' ) text.append( i18n( ", small words removed" ) );
}
else if (( *it )[0] == '"' ) text.append( TQString( i18n( "Text: '%1'" ) ).arg(( *it ).mid( 1 ) ) );
else text.append( "?" );
}
return text;
}
}