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
***************************************************************************/
22
#include <qapplication.h>
23
#include <qstringlist.h>
29
#include <klineedit.h>
33
#include <kmessagebox.h>
34
#include <kio/netaccess.h>
36
#include <entryfield.h>
39
#include "webquerypubmed.h"
43
WebQueryPubMedWidget::WebQueryPubMedWidget( QWidget *parent, const char *name )
44
: WebQueryWidget( parent, name )
48
Settings *settings = Settings::self();
49
QString value = settings->getWebQueryDefault( "PubMed" );
50
value = value == QString::null ? "" : value;
51
lineEditQuery->setText( value );
52
slotTextChanged( value, true );
55
WebQueryPubMed::WebQueryPubMed( QWidget *parent ) : WebQuery( parent )
57
m_widget = new WebQueryPubMedWidget( parent );
60
WebQueryPubMed::~WebQueryPubMed()
65
QString WebQueryPubMed::title()
67
return i18n( "NCBI (PubMed)" );
70
QString WebQueryPubMed::disclaimer()
72
return i18n( "NCBI's Disclaimer and Copyright" );
75
QString WebQueryPubMed::disclaimerURL()
77
return "http://eutils.ncbi.nlm.nih.gov/About/disclaimer.html";
80
WebQueryWidget *WebQueryPubMed::widget()
85
void WebQueryPubMed::query()
88
Settings *settings = Settings::self();
89
settings->setWebQueryDefault( "PubMed", m_widget->lineEditQuery->text() );
92
int numberOfResults = m_widget->spinBoxMaxHits->value();
94
QString searchTerm = m_widget->lineEditQuery->text().stripWhiteSpace().replace( '$', "" );
95
if ( searchTerm.isEmpty() )
97
setEndSearch( WebQuery::statusInvalidQuery );
101
searchTerm = searchTerm.replace( "%", "%25" ).replace( "+", "%2B" ).replace( " ", "%20" ).replace( "#", "%23" ).replace( "&", "%26" ).replace( "?", "%3F" );
102
KURL url = KURL( QString( "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=%2&retmax=%1&tool=KBibTeX&email=kbibtex@unix-ag.uni-kl.de" ).arg( numberOfResults ).arg( searchTerm ) );
104
QString data = downloadHTML( url );
105
if ( data != QString::null && !m_aborted )
108
buffer.open( IO_WriteOnly );
109
QTextStream ts( &buffer );
110
ts.setEncoding( QTextStream::UnicodeUTF8 );
114
buffer.open( IO_ReadOnly );
115
QValueList<int> intList;
116
QXmlInputSource inputSource( &buffer );
117
QXmlSimpleReader reader;
118
WebQueryPubMedStructureParserQuery handler( &intList );
119
reader.setContentHandler( &handler );
120
reader.parse( &inputSource );
124
QValueList<int>::iterator it = intList.begin();
125
if ( it != intList.end() )
127
ids.append( QString::number( *it ) );
129
for ( ; it != intList.end(); ++it )
132
ids.append( QString::number( *it ) );
136
url = KURL( QString( "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&retmode=xml&id=%1&tool=KBibTeX&email=kbibtex@unix-ag.uni-kl.de" ).arg( ids ) );
137
data = downloadHTML( url );
138
if ( data != QString::null && !m_aborted )
140
buffer.open( IO_WriteOnly );
141
QTextStream ts( &buffer );
142
ts.setEncoding( QTextStream::UnicodeUTF8 );
146
buffer.open( IO_ReadOnly );
147
QDomDocument doc( "efetch'ed" );
148
doc.setContent( &buffer );
149
QDomElement docElem = doc.documentElement();
150
WebQueryPubMedResultParser resultParser;
151
connect( &resultParser, SIGNAL( foundEntry( BibTeX::Entry*, bool ) ), this, SIGNAL( foundEntry( BibTeX::Entry*, bool ) ) );
152
resultParser.parse( docElem );
154
setEndSearch( WebQuery::statusSuccess );
156
else if ( !m_aborted )
158
QString message = KIO::NetAccess::lastErrorString();
159
message.prepend( QString( i18n( "Querying database '%1' failed." ) ).arg( title() ) );
160
KMessageBox::error( m_parent, message );
161
setEndSearch( WebQuery::statusError );
164
setEndSearch( WebQuery::statusAborted );
166
else if ( !m_aborted )
168
QString message = KIO::NetAccess::lastErrorString();
169
if ( message.isEmpty() )
170
message.prepend( '\n' );
171
message.prepend( QString( i18n( "Querying database '%1' failed." ) ).arg( title() ) );
172
KMessageBox::error( m_parent, message );
173
setEndSearch( WebQuery::statusError );
176
setEndSearch( WebQuery::statusAborted );
179
WebQueryPubMedStructureParserQuery::WebQueryPubMedStructureParserQuery( QValueList<int> *intList ) : QXmlDefaultHandler(), m_intList( intList )
184
WebQueryPubMedStructureParserQuery::~WebQueryPubMedStructureParserQuery( )
189
bool WebQueryPubMedStructureParserQuery::startElement( const QString & /*namespaceURI*/, const QString & /*localName*/, const QString & /*qName*/, const QXmlAttributes & /*atts*/ )
191
concatString = QString();
195
bool WebQueryPubMedStructureParserQuery::endElement( const QString & /*namespaceURI*/, const QString & /*localName*/, const QString & qName )
200
int id = concatString.toInt( &ok );
201
if ( ok && id > 0 && m_intList != NULL )
202
m_intList->append( id );
208
bool WebQueryPubMedStructureParserQuery::characters( const QString & ch )
210
concatString.append( ch );
214
WebQueryPubMedResultParser::WebQueryPubMedResultParser( ) : QObject()
219
void WebQueryPubMedResultParser::parse( const QDomElement& rootElement )
221
if ( rootElement.tagName() == "PubmedArticleSet" )
222
for ( QDomNode n = rootElement.firstChild(); !n.isNull(); n = n.nextSibling() )
224
QDomElement e = n.toElement();
225
if ( !e.isNull() && e.tagName() == "PubmedArticle" )
227
BibTeX::Entry * entry = new BibTeX::Entry( BibTeX::Entry::etMisc, "PubMed" );
228
parsePubmedArticle( e, entry );
229
emit foundEntry( entry, false );
234
WebQueryPubMedResultParser::~WebQueryPubMedResultParser()
239
void WebQueryPubMedResultParser::parsePubmedArticle( const QDomElement& element, BibTeX::Entry *entry )
241
for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() )
243
QDomElement e = n.toElement();
244
if ( !e.isNull() && e.tagName() == "MedlineCitation" )
245
parseMedlineCitation( e, entry );
249
void WebQueryPubMedResultParser::parseMedlineCitation( const QDomElement& element, BibTeX::Entry *entry )
251
for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() )
253
QDomElement e = n.toElement();
256
if ( e.tagName() == "PMID" )
258
entry->setId( QString( "PubMed_%1" ).arg( e.text() ) );
260
/** add url to pubmed website */
261
BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftURL );
264
field = new BibTeX::EntryField( BibTeX::EntryField::ftURL );
265
entry->addField( field );
267
field->setValue( new BibTeX::Value( QString( "http://www.ncbi.nlm.nih.gov/pubmed/" ).append( e.text() ) ) );
269
else if ( e.tagName() == "Article" )
270
parseArticle( e, entry );
271
else if ( e.tagName() == "MedlineJournalInfo" )
273
for ( QDomNode n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() )
275
QDomElement e2 = n2.toElement();
276
if ( e2.tagName() == "MedlineTA" )
278
BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftJournal );
281
field = new BibTeX::EntryField( BibTeX::EntryField::ftJournal );
282
entry->addField( field );
284
field->setValue( new BibTeX::Value( e2.text() ) );
293
void WebQueryPubMedResultParser::parseArticle( const QDomElement& element, BibTeX::Entry *entry )
295
for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() )
297
QDomElement e = n.toElement();
299
if ( e.tagName() == "Journal" )
301
parseJournal( e, entry );
302
entry->setEntryType( BibTeX::Entry::etArticle );
304
else if ( e.tagName() == "ArticleTitle" )
306
BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftTitle );
309
field = new BibTeX::EntryField( BibTeX::EntryField::ftTitle );
310
entry->addField( field );
312
field->setValue( new BibTeX::Value( e.text() ) );
314
else if ( e.tagName() == "Pagination" )
316
QDomElement medlinePgn = e.firstChild().toElement(); // may fail?
317
if ( !medlinePgn.text().isEmpty() )
319
BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftPages );
322
field = new BibTeX::EntryField( BibTeX::EntryField::ftPages );
323
entry->addField( field );
325
field->setValue( new BibTeX::Value( medlinePgn.text() ) );
328
else if ( e.tagName() == "Abstract" )
330
QDomElement abstractText = e.firstChild().toElement();
331
BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftAbstract );
334
field = new BibTeX::EntryField( BibTeX::EntryField::ftAbstract );
335
entry->addField( field );
337
field->setValue( new BibTeX::Value( abstractText.text() ) );
339
else if ( e.tagName() == "Affiliation" )
341
BibTeX::EntryField * field = entry->getField( "affiliation" );
344
field = new BibTeX::EntryField( "affiliation" );
345
entry->addField( field );
347
field->setValue( new BibTeX::Value( e.text() ) );
349
else if ( e.tagName() == "AuthorList" )
350
parseAuthorList( e, entry );
354
void WebQueryPubMedResultParser::parseJournal( const QDomElement& element, BibTeX::Entry *entry )
356
for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() )
358
QDomElement e = n.toElement();
360
if ( e.tagName() == "ISSN" )
362
BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftISSN );
365
field = new BibTeX::EntryField( BibTeX::EntryField::ftISSN );
366
entry->addField( field );
368
field->setValue( new BibTeX::Value( e.text() ) );
370
else if ( e.tagName() == "JournalIssue" )
371
parseJournalIssue( e, entry );
372
else if ( e.tagName() == "Title" )
374
BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftJournal );
377
field = new BibTeX::EntryField( BibTeX::EntryField::ftJournal );
378
entry->addField( field );
380
field->setValue( new BibTeX::Value( e.text() ) );
385
void WebQueryPubMedResultParser::parseJournalIssue( const QDomElement& element, BibTeX::Entry *entry )
387
for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() )
389
QDomElement e = n.toElement();
391
if ( e.tagName() == "Volume" )
393
BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftVolume );
396
field = new BibTeX::EntryField( BibTeX::EntryField::ftVolume );
397
entry->addField( field );
399
field->setValue( new BibTeX::Value( e.text() ) );
401
else if ( e.tagName() == "Issue" )
403
BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftNumber );
406
field = new BibTeX::EntryField( BibTeX::EntryField::ftNumber );
407
entry->addField( field );
409
field->setValue( new BibTeX::Value( e.text() ) );
411
else if ( e.tagName() == "PubDate" )
412
parsePubDate( e, entry );
416
void WebQueryPubMedResultParser::parsePubDate( const QDomElement& element, BibTeX::Entry *entry )
418
for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() )
420
QDomElement e = n.toElement();
422
if ( e.tagName() == "Year" )
424
BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftYear );
427
field = new BibTeX::EntryField( BibTeX::EntryField::ftYear );
428
entry->addField( field );
430
field->setValue( new BibTeX::Value( e.text() ) );
432
else if ( e.tagName() == "Month" )
434
QString month = e.text().lower();
435
BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftMonth );
438
field = new BibTeX::EntryField( BibTeX::EntryField::ftMonth );
439
entry->addField( field );
441
BibTeX::Value *value = new BibTeX::Value();
442
value->items.append( new BibTeX::MacroKey( month ) );
443
field->setValue( value );
445
else if ( e.tagName() == "MedlineDate" )
447
QStringList frags = QStringList::split( QRegExp( "\\s+" ), e.text() );
448
for ( QStringList::Iterator it = frags.begin(); it != frags.end(); ++it )
451
int num = ( *it ).toInt( &ok );
452
if ( ok && num > 1000 && num < 3000 )
454
BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftYear );
457
field = new BibTeX::EntryField( BibTeX::EntryField::ftYear );
458
entry->addField( field );
460
BibTeX::Value *value = new BibTeX::Value();
461
value->items.append( new BibTeX::MacroKey( QString::number( num ) ) );
462
field->setValue( value );
464
else if ( !ok && ( *it ).length() == 3 )
466
BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftMonth );
469
field = new BibTeX::EntryField( BibTeX::EntryField::ftMonth );
470
entry->addField( field );
472
BibTeX::Value *value = new BibTeX::Value();
473
value->items.append( new BibTeX::MacroKey(( *it ).lower() ) );
474
field->setValue( value );
481
void WebQueryPubMedResultParser::parseAuthorList( const QDomElement& element, BibTeX::Entry *entry )
483
if ( element.attribute( "CompleteYN", "Y" ) == "Y" )
485
QStringList authorList;
486
for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() )
488
QDomElement e = n.toElement();
489
if ( e.tagName() == "Author" && e.attribute( "ValidYN", "Y" ) == "Y" )
491
QString lastName = QString::null, firstName = QString::null;
492
for ( QDomNode n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() )
494
QDomElement e2 = n2.toElement();
495
if ( e2.tagName() == "LastName" )
496
lastName = e2.text();
497
else if ( e2.tagName() == "CollectiveName" )
498
lastName = e2.text();
499
else if ( e2.tagName() == "FirstName" || e2.tagName() == "ForeName" )
500
firstName = e2.text();
502
QString name = lastName;
503
if ( !firstName.isNull() && !firstName.isEmpty() )
505
if ( name.isNull() ) name = "UNSET";
506
name.prepend( "|" ).prepend( firstName );
508
if ( !name.isNull() )
509
authorList.append( name );
513
BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftAuthor );
516
field = new BibTeX::EntryField( BibTeX::EntryField::ftAuthor );
517
entry->addField( field );
519
BibTeX::Value *value = new BibTeX::Value();
520
Settings *settings = Settings::self();
521
BibTeX::PersonContainer *personContainer = new BibTeX::PersonContainer( settings->editing_FirstNameFirst );
522
value->items.append( personContainer );
523
for ( QStringList::Iterator sli = authorList.begin(); sli != authorList.end(); ++sli )
525
QStringList nameParts = QStringList::split( '|', *sli );
526
QString firstName = nameParts.count() > 1 ? nameParts[0] : "";
527
QString lastName = nameParts[nameParts.count() - 1];
528
personContainer->persons.append( new BibTeX::Person( firstName, lastName, settings->editing_FirstNameFirst ) );
530
field->setValue( value );