/*************************************************************************** * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_YAZ #include #endif // HAVE_YAZ #include #include "webquery.h" #define min(a,b) ((a)>(b)?(b):(a)) namespace KBibTeX { WebQueryWidget::WebQueryWidget( TQWidget *parent, const char *name ) : TQWidget( parent, name ), lineEditQuery( NULL ), spinBoxMaxHits( NULL ) { // nothing } bool WebQueryWidget::searchPossible() { return lineEditQuery != NULL && !lineEditQuery->text().stripWhiteSpace().replace( '$', "" ).isEmpty(); } void WebQueryWidget::init() { TQVBoxLayout *vLayout = new TQVBoxLayout( this, 0, KDialog::spacingHint() ); TQHBoxLayout *hLayout = new TQHBoxLayout( ); vLayout->addLayout( hLayout ); KPushButton *clearSearchText = new KPushButton( this ); clearSearchText->setIconSet( TQIconSet( SmallIcon( "locationbar_erase" ) ) ); hLayout->addWidget( clearSearchText ); TQLabel *label = new TQLabel( i18n( "Search &term:" ), this ); hLayout->addWidget( label ); lineEditQuery = new KLineEdit( this ); hLayout->addWidget( lineEditQuery ); label->setBuddy( lineEditQuery ); hLayout->addSpacing( KDialog::spacingHint() * 2 ); connect( clearSearchText, SIGNAL( clicked() ), lineEditQuery, SLOT( clear() ) ); connect( lineEditQuery, SIGNAL( textChanged( const TQString& ) ), this, SLOT( slotTextChanged( const TQString& ) ) ); hLayout->setStretchFactor( lineEditQuery, 4 ); TDECompletion *completionQuery = lineEditQuery->completionObject(); label = new TQLabel( i18n( "&Number of results:" ), this ); hLayout->addWidget( label ); spinBoxMaxHits = new TQSpinBox( 1, 250, 1, this ); spinBoxMaxHits->setValue( 10 ); hLayout->addWidget( spinBoxMaxHits ); label->setBuddy( spinBoxMaxHits ); vLayout->addStretch( 0 ); connect( lineEditQuery, SIGNAL( returnPressed() ), this, SIGNAL( startSearch() ) ); connect( lineEditQuery, SIGNAL( returnPressed( const TQString& ) ), completionQuery, SLOT( addItem( const TQString& ) ) ); } void WebQueryWidget::slotTextChanged( const TQString& text ) { slotTextChanged( text, false ); } void WebQueryWidget::slotTextChanged( const TQString& text, bool delayed ) { bool doEnable = !text.stripWhiteSpace().replace( '$', "" ).isEmpty(); if ( delayed && doEnable ) TQTimer::singleShot( 100, this, SLOT( slotEnableSearchTrue() ) ); else if ( !delayed ) emit enableSearch( doEnable ); } void WebQueryWidget::slotEnableSearchTrue() { emit enableSearch( true ); } WebQuery::WebQuery( TQWidget *parent ): TQObject(), m_parent( parent ), m_progressDialog( NULL ), m_currentJob( NULL ) { // nothing } WebQuery::~WebQuery() { if ( m_progressDialog != NULL ) delete m_progressDialog; } void WebQuery::query() { if ( m_progressDialog != NULL ) delete m_progressDialog; m_aborted = false; m_progressDialog = new KProgressDialog( m_parent, "WebQuery_progressDialog", i18n( "Searching" ), TQString( i18n( "Searching %1" ) ).arg( title() ) ); m_progressDialog->progressBar()->setMinimumWidth( 256 ); m_progressDialog->setAutoClose( true ); m_progressDialog->setMinimumDuration( 10 ); m_progressDialog->setEnabled( true ); connect( m_progressDialog, SIGNAL( cancelClicked() ), this, SLOT( slotCancelQuery() ) ); } void WebQuery::cancelQuery() { // nothing } void WebQuery::slotCancelQuery() { m_aborted = true; cancelQuery(); } void WebQuery::setEndSearch( WebQuery::Status status ) { if ( m_progressDialog != NULL ) m_progressDialog->hide(); emit endSearch( status ); } void WebQuery::setNumStages( int numStages ) { m_currentStage = 0; m_numStages = numStages; m_progressDialog->progressBar()->setTotalSteps( m_numStages * 100 ); } void WebQuery::enterNextStage() { ++m_currentStage; if ( m_progressDialog != NULL ) m_progressDialog->progressBar()->setProgress( m_currentStage * 100 ); } TQString WebQuery::download( const KURL& url ) { TQString data = downloadHTML( url ); if ( data == TQString::null ) return TQString::null; /** post-processing */ if ( data != TQString::null ) { data.replace( TQRegExp( "]*>" ), "\n" ); data.replace( TQRegExp( "]*>" ), "" ); data.replace( "@import", "" );/// JavaScript import? } return data; } TQString WebQuery::downloadHTML( const KURL& url ) { if ( m_currentJob != NULL ) return TQString::null; tqDebug( "WebQuery::download( %s )", url.prettyURL().latin1() ); m_incomingData = ""; m_currentJobTotalSize = -1; m_currentJob = TDEIO::get( url, false, false ); connect( m_currentJob, SIGNAL( totalSize( TDEIO::Job*, TDEIO::filesize_t ) ), this, SLOT( slotSetJobTotalSize( TDEIO::Job*, TDEIO::filesize_t ) ) ); connect( m_currentJob, SIGNAL( processedSize( TDEIO::Job*, TDEIO::filesize_t ) ), this, SLOT( slotSetJobProcessedSize( TDEIO::Job*, TDEIO::filesize_t ) ) ); connect( m_currentJob, SIGNAL( data( TDEIO::Job*, const TQByteArray & ) ), this, SLOT( slotJobData( TDEIO::Job*, const TQByteArray & ) ) ); connect( m_currentJob, SIGNAL( result( TDEIO::Job* ) ), this, SLOT( slotJobFinished( TDEIO::Job* ) ) ); tqApp->eventLoop()->enterLoop(); return m_incomingData; } BibTeX::File *WebQuery::downloadBibTeXFile( const KURL& url, TQTextStream::Encoding encoding ) { TQString data = download( url ); if ( data == TQString::null ) return NULL; BibTeX::FileImporterBibTeX importer( FALSE ); importer.setIgnoreComments( TRUE ); TQBuffer buffer; buffer.open( IO_WriteOnly ); TQTextStream ts( &buffer ); ts.setEncoding( encoding ); ts << data << endl; buffer.close(); buffer.open( IO_ReadOnly ); BibTeX::File *result = importer.load( &buffer ); buffer.close(); return result; } void WebQuery::slotSetJobTotalSize( TDEIO::Job *job, TDEIO::filesize_t size ) { if ( job != m_currentJob ) return; m_currentJobTotalSize = size; } void WebQuery::slotSetJobProcessedSize( TDEIO::Job *job, TDEIO::filesize_t size ) { if ( job != m_currentJob ) return; if ( m_currentJobTotalSize <= 0 ) m_currentJobTotalSize = size; m_progressDialog->progressBar()->setProgress( m_currentStage * 100 + min( 100, size * 100 / m_currentJobTotalSize ) ); } void WebQuery::slotJobData( TDEIO::Job *job, const TQByteArray &data ) { if ( job != m_currentJob ) return; TQCString dataStr = TQCString( data, data.size() + 1 ); if ( data.size() > 0 ) m_incomingData.append( dataStr ); } void WebQuery::slotJobFinished( TDEIO::Job *job ) { if ( job != m_currentJob ) return; m_currentJob = NULL; if ( job->error() ) { job->showErrorDialog(); m_incomingData = TQString::null; } enterNextStage(); tqApp->eventLoop()->exitLoop(); } WebQueryWizard::WebQueryWizard( KDialogBase *dlg, const char* name ) : TQWidget( dlg, name ), m_dlg( dlg ), m_pushButtonSearch( NULL ) { setupGUI( ); Settings *settings = Settings::self( NULL ); m_comboBoxEngines->setCurrentItem( settings->webQuery_LastEngine ); otherEngineSelected( settings->webQuery_LastEngine ); m_checkBoxImportAll->setChecked( settings->webQuery_ImportAll ); m_pushButtonSearch->setEnabled( false ); } WebQueryWizard::~WebQueryWizard() { TDEConfig * config = kapp->config(); config->setGroup( "WebQueryWizard" ); saveWindowSize( config ); } void WebQueryWizard::showEvent( TQShowEvent * ) { TDEConfig * config = kapp->config(); config->setGroup( "WebQueryWizard" ); restoreWindowSize( config ); } int WebQueryWizard::execute( TQWidget *parent, TQValueList &results ) { KDialogBase *dlg = new KDialogBase( parent, "WebQueryWizard", true, i18n( "Import" ), KDialogBase::Ok | KDialogBase::Cancel, ( KDialogBase::ButtonCode )0, true ); WebQueryWizard *wiz = new WebQueryWizard( dlg, "WebQueryWizard" ); dlg->setButtonOK( KGuiItem( i18n( "&Import" ), "import", i18n( "Import selected items" ) ) ); dlg->setMainWidget( wiz ); connect( wiz, SIGNAL( changeButtonOK( bool ) ), dlg, SLOT( enableButtonOK( bool ) ) ); dlg->enableButtonOK( false ); results.clear(); int result = dlg->exec(); if ( result == TQDialog::Accepted ) { TQListViewItemIterator it = wiz->m_checkBoxImportAll->isChecked() ? TQListViewItemIterator( wiz->m_listViewResults ) : TQListViewItemIterator( wiz->m_listViewResults, TQListViewItemIterator::Selected ); while ( it.current() ) { ResultsListViewItem *item = dynamic_cast( it.current() ); results.append( new BibTeX::Entry( item->entry() ) ); ++it; } } Settings *settings = Settings::self( NULL ); settings->webQuery_LastEngine = wiz->m_comboBoxEngines->currentItem(); settings->webQuery_ImportAll = wiz->m_checkBoxImportAll->isChecked(); delete dlg; return result; } void WebQueryWizard::previewEntry( TQListViewItem *item ) { ResultsListViewItem *rlvi = dynamic_cast( item ); if ( rlvi != NULL ) { BibTeX::Entry *entry = rlvi->entry(); KBibTeX::EntryWidget::execute( entry, NULL, TRUE, FALSE ); } } void WebQueryWizard::importEnableChanging( ) { TQListViewItemIterator it( m_listViewResults, TQListViewItemIterator::Selected ); emit changeButtonOK(( m_checkBoxImportAll->isChecked() && m_listViewResults->childCount() > 0 ) || it.current() != NULL ); } void WebQueryWizard::otherEngineSelected( int index ) { if ( index < 0 || index >= ( int )m_webQueries.size() ) return; m_pushButtonSearch->setCaption( TQString( i18n( "Search %1" ) ).arg( m_webQueries[index]->title() ) ); m_disclaimerLabel->setText( m_webQueries[index]->disclaimer() ); m_disclaimerLabel->setURL( m_webQueries[index]->disclaimerURL() ); TQToolTip::remove( m_disclaimerLabel ); TQToolTip::add( m_disclaimerLabel, m_webQueries[index]->disclaimerURL() ); m_widgetStackQueries->raiseWidget( m_webQueries[index]->widget() ); m_pushButtonSearch->setEnabled( m_webQueries[index]->widget()->searchPossible() ); } void WebQueryWizard::startSearch() { if ( !m_pushButtonSearch->isEnabled() ) { kdDebug() << "WebQueryWizard::startSearch not enabled" << endl; return; } int index = m_comboBoxEngines->currentItem(); setEnabled( FALSE ); m_dlg->enableButtonCancel( FALSE ); TQApplication::setOverrideCursor( TQt::waitCursor ); m_listViewResults->clear(); connect( m_webQueries[index], SIGNAL( foundEntry( BibTeX::Entry*, bool ) ), this, SLOT( addHit( BibTeX::Entry*, bool ) ) ); connect( m_webQueries[index], SIGNAL( endSearch( WebQuery::Status ) ), this, SLOT( endSearch( WebQuery::Status ) ) ); m_webQueries[index]->query(); } void WebQueryWizard::endSearch( WebQuery::Status status ) { int index = m_comboBoxEngines->currentItem(); disconnect( m_webQueries[index], SIGNAL( foundEntry( BibTeX::Entry*, bool ) ), this, SLOT( addHit( BibTeX::Entry*, bool ) ) ); disconnect( m_webQueries[index], SIGNAL( endSearch( WebQuery::Status ) ), this, SLOT( endSearch( WebQuery::Status ) ) ); setEnabled( TRUE ); m_dlg->enableButtonCancel( TRUE ); importEnableChanging(); TQApplication::restoreOverrideCursor(); if ( status == WebQuery::statusInsufficientPermissions ) KMessageBox::sorry( this, i18n( "You do not have the necessary permissions to query data from this service." ) ); } void WebQueryWizard::addHit( BibTeX::Entry *entry, bool keepId ) { Settings * settings = Settings::self(); if ( !keepId && settings->idSuggestions_default >= 0 ) entry->setId( IdSuggestions::createDefaultSuggestion( NULL, entry ) ); new ResultsListViewItem( m_listViewResults, new BibTeX::Entry( entry ) ); } void WebQueryWizard::enableSearch( bool enabled ) { m_pushButtonSearch->setEnabled( enabled ); } void WebQueryWizard::openURL( const TQString& url ) { Settings::openUrl( KURL( url ), this ); } void WebQueryWizard::setupGUI() { Settings * settings = Settings::self(); setMinimumSize( 640, 384 ); TQGridLayout *layout = new TQGridLayout( this, 5, 4, 0, KDialog::spacingHint() ); layout->setColStretch( 2, 1 ); layout->setRowStretch( 3, 1 ); TQLabel *label = new TQLabel( i18n( "&Engine:" ), this ); layout->addWidget( label, 0, 0 ); m_comboBoxEngines = new KComboBox( FALSE, this ); label->setBuddy( m_comboBoxEngines ); layout->addWidget( m_comboBoxEngines, 0, 1 ); connect( m_comboBoxEngines, SIGNAL( activated( int ) ), this, SLOT( otherEngineSelected( int ) ) ); m_widgetStackQueries = new TQWidgetStack( this ); layout->addMultiCellWidget( m_widgetStackQueries, 1, 2, 0, 2 ); setupQueries(); m_pushButtonSearch = new KPushButton( i18n( "&Search" ), this ); layout->addWidget( m_pushButtonSearch, 0, 3 ); m_pushButtonSearch->setIconSet( TQIconSet( SmallIcon( "edit-find" ) ) ); m_pushButtonSearch->setEnabled( FALSE ); m_listViewResults = new TDEListView( this ); m_listViewResults->addColumn( i18n( "Year" ), 64 ); m_listViewResults->addColumn( i18n( "Author" ), 128 ); m_listViewResults->addColumn( i18n( "Title" ), 512 ); if ( settings->editing_UseSpecialFont ) m_listViewResults->setFont( settings->editing_SpecialFont ); else m_listViewResults->setFont( TDEGlobalSettings::generalFont() ); m_listViewResults->header() ->setFont( TDEGlobalSettings::generalFont() ); m_listViewResults->setAllColumnsShowFocus( TRUE ); m_listViewResults->setFullWidth( true ); m_listViewResults->setSelectionMode( TQListView::Extended ); layout->addMultiCellWidget( m_listViewResults, 3, 3, 0, 3 ); connect( m_listViewResults, SIGNAL( executed( TQListViewItem* ) ), this, SLOT( previewEntry( TQListViewItem* ) ) ); connect( m_listViewResults, SIGNAL( returnPressed( TQListViewItem* ) ), this, SLOT( previewEntry( TQListViewItem* ) ) ); TQHBoxLayout *horizontalLayout = new TQHBoxLayout(); layout->addMultiCellLayout( horizontalLayout, 4, 4, 0, 3 ); m_disclaimerLabel = new KURLLabel( this ); horizontalLayout->addWidget( m_disclaimerLabel ); horizontalLayout->setStretchFactor( m_disclaimerLabel, 4 ); m_checkBoxImportAll = new TQCheckBox( i18n( "Import all hits" ), this ); m_checkBoxImportAll->setSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Minimum ); horizontalLayout->addWidget( m_checkBoxImportAll ); connect( m_disclaimerLabel, SIGNAL( leftClickedURL( const TQString& ) ), this, SLOT( openURL( const TQString& ) ) ); connect( m_listViewResults, SIGNAL( selectionChanged( ) ), this, SLOT( importEnableChanging( ) ) ); connect( m_listViewResults, SIGNAL( clicked( TQListViewItem* ) ), this, SLOT( importEnableChanging( ) ) ); connect( m_checkBoxImportAll, SIGNAL( toggled( bool ) ), this, SLOT( importEnableChanging( ) ) ); connect( m_pushButtonSearch, SIGNAL( clicked() ), this, SLOT( startSearch() ) ); } void WebQueryWizard::setupQueries() { WebQuery *query = new WebQueryArXiv( this ); m_webQueries.append( query ); // query = new WebQueryAmatex( this ); // m_webQueries.append( query ); query = new WebQueryBibSonomy( this ); m_webQueries.append( query ); query = new WebQueryCitebase( this ); m_webQueries.append( query ); query = new WebQueryCiteSeerX( this ); m_webQueries.append( query ); query = new WebQueryCSB( this ); m_webQueries.append( query ); query = new WebQueryDBLP( this ); m_webQueries.append( query ); query = new WebQueryGoogleScholar( this ); m_webQueries.append( query ); query = new WebQueryIEEExplore( this ); m_webQueries.append( query ); query = new WebQueryMathSciNet( this ); m_webQueries.append( query ); query = new WebQueryPubMed( this ); m_webQueries.append( query ); query = new WebQueryScienceDirect( this ); m_webQueries.append( query ); query = new WebQuerySpiresHep( this ); m_webQueries.append( query ); #ifdef HAVE_YAZ query = new WebQueryZ3950( this ); m_webQueries.append( query ); #endif // HAVE_YAZ query = new WebQueryZMATH( this ); m_webQueries.append( query ); for ( TQValueList::Iterator it = m_webQueries.begin(); it != m_webQueries.end(); ++it ) { m_comboBoxEngines->insertItem(( *it )->title() ); m_widgetStackQueries->addWidget(( *it )->widget() ); connect(( *it )->widget(), SIGNAL( enableSearch( bool ) ), this, SLOT( enableSearch( bool ) ) ); connect(( *it )->widget(), SIGNAL( startSearch() ), this, SLOT( startSearch() ) ); } } /* This function was taken form TDEMainWindow of KDE 3.5 and modified to fit KBibTeX */ void WebQueryWizard::saveWindowSize( TDEConfig *config ) const { int scnum = TQApplication::desktop()->screenNumber( parentWidget() ); TQRect desk = TQApplication::desktop()->screenGeometry( scnum ); int w, h; #if defined Q_WS_X11 // save maximalization as desktop size + 1 in that direction KWin::WindowInfo info = KWin::windowInfo( m_dlg->winId(), NET::WMState ); w = info.state() & NET::MaxHoriz ? desk.width() + 1 : m_dlg->width(); h = info.state() & NET::MaxVert ? desk.height() + 1 : m_dlg->height(); #else if ( isMaximized() ) { w = desk.width() + 1; h = desk.height() + 1; } //TODO: add "Maximized" property instead "+1" hack #endif TQRect size( desk.width(), w, desk.height(), h ); bool defaultSize = false;//( size == d->defaultWindowSize ); TQString widthString = TQString::fromLatin1( "Width %1" ).arg( desk.width() ); TQString heightString = TQString::fromLatin1( "Height %1" ).arg( desk.height() ); if ( !config->hasDefault( widthString ) && defaultSize ) config->revertToDefault( widthString ); else config->writeEntry( widthString, w ); if ( !config->hasDefault( heightString ) && defaultSize ) config->revertToDefault( heightString ); else config->writeEntry( heightString, h ); } /* This function was taken form TDEMainWindow of KDE 3.5 and modified to fit KBibTeX */ void WebQueryWizard::restoreWindowSize( TDEConfig *config ) { // restore the size int scnum = TQApplication::desktop()->screenNumber( parentWidget() ); TQRect desk = TQApplication::desktop()->screenGeometry( scnum ); TQSize size( config->readNumEntry( TQString::fromLatin1( "Width %1" ).arg( desk.width() ), 0 ), config->readNumEntry( TQString::fromLatin1( "Height %1" ).arg( desk.height() ), 0 ) ); if ( size.isEmpty() ) { // try the KDE 2.0 way size = TQSize( config->readNumEntry( TQString::fromLatin1( "Width" ), 0 ), config->readNumEntry( TQString::fromLatin1( "Height" ), 0 ) ); if ( !size.isEmpty() ) { // make sure the other resolutions don't get old settings config->writeEntry( TQString::fromLatin1( "Width" ), 0 ); config->writeEntry( TQString::fromLatin1( "Height" ), 0 ); } } if ( !size.isEmpty() ) { #ifdef Q_WS_X11 int state = ( size.width() > desk.width() ? NET::MaxHoriz : 0 ) | ( size.height() > desk.height() ? NET::MaxVert : 0 ); if (( state & NET::Max ) == NET::Max ) ; // no resize else if (( state & NET::MaxHoriz ) == NET::MaxHoriz ) m_dlg->resize( width(), size.height() ); else if (( state & NET::MaxVert ) == NET::MaxVert ) m_dlg->resize( size.width(), height() ); else m_dlg->resize( size ); // TQWidget::showMaximized() is both insufficient and broken KWin::setState( m_dlg->winId(), state ); #else if ( size.width() > desk.width() || size.height() > desk.height() ) m_dlg->setWindowState( WindowMaximized ); else m_dlg->resize( size ); #endif } } ResultsListViewItem::ResultsListViewItem( TQListView * parent, BibTeX::Entry * entry ) : TQListViewItem( parent ), m_entry( entry ) { BibTeX::EntryField * field = entry->getField( BibTeX::EntryField::ftTitle ); if ( field != NULL && field->value() != NULL ) setText( 2, field ->value() ->text().replace( '{', "" ).replace( '}', "" ).replace( '~', ' ' ) ); field = entry->getField( BibTeX::EntryField::ftAuthor ); if ( field != NULL && field->value() != NULL ) { BibTeX::PersonContainer* personContainer = dynamic_cast( field->value()->items.first() ); if ( personContainer != NULL ) { TQStringList authors; TQValueList list = personContainer->persons; for ( TQValueList::ConstIterator it = list.begin(); it != list.end(); ++it ) authors.append(( *it ) ->text() ); setText( 1, authors.join( " and " ).replace( '{', "" ).replace( '}', "" ).replace( '~', ' ' ) ); } else setText( 1, field ->value() ->text().replace( '{', "" ).replace( '}', "" ).replace( '~', ' ' ) ); } field = entry->getField( BibTeX::EntryField::ftYear ); if ( field != NULL && field->value() != NULL ) setText( 0, field ->value() ->text().replace( '{', "" ).replace( '}', "" ).replace( '~', ' ' ) ); } ResultsListViewItem::~ResultsListViewItem() { if ( m_entry != NULL ) delete m_entry; } BibTeX::Entry* ResultsListViewItem::entry() { return m_entry; } } #include "webquery.moc"