|
|
|
/***************************************************************************
|
|
|
|
* 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 <ntqregexp.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;
|
|
|
|
}
|
|
|
|
}
|