/*************************************************************************** * 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #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 #include "documentlistview.h" namespace KBibTeX { DocumentListView::DocumentListView( KBibTeX::DocumentWidget *docWidget, bool isReadOnly, TQWidget *parent, const char *name ) : TDEListView( parent, name ), m_docWidget( docWidget ), m_bibtexFile( NULL ), m_contextMenu( NULL ), m_headerMenu( NULL ), m_isReadOnly( isReadOnly ), m_newElementCounter( 1 ) { setAllColumnsShowFocus( true ); setShowSortIndicator( true ); setSelectionMode( TQListView::Extended ); header() ->setClickEnabled( TRUE ); header() ->setMovingEnabled( TRUE ); buildColumns(); setDragEnabled( true ); // setDragAutoScroll( true ); setAcceptDrops( TRUE ); setDropVisualizer( TRUE ); connect( header(), SIGNAL( clicked( int ) ), this, SLOT( setSortingColumn( int ) ) ); connect( this, SIGNAL( contextMenu( TDEListView *, TQListViewItem *, const TQPoint & ) ), this, SLOT( showBibtexListContextMenu( TDEListView *, TQListViewItem *, const TQPoint & ) ) ); connect( this, SIGNAL( doubleClicked( TQListViewItem*, const TQPoint&, int ) ), this, SLOT( slotDoubleClick( TQListViewItem* ) ) ); connect( this, SIGNAL( dropped( TQDropEvent*, TQListViewItem* ) ), this, SLOT( slotDropped( TQDropEvent*, TQListViewItem* ) ) ); } DocumentListView::~DocumentListView() { // nothing } void DocumentListView::setFactory( KXMLGUIFactory *factory, KXMLGUIClient *client ) { m_contextMenu = static_cast( factory -> container( "popup_bibtexlist", client ) ); } bool DocumentListView::setBibTeXFile( BibTeX::File *bibtexFile ) { m_bibtexFile = bibtexFile; setItems(); return TRUE; } BibTeX::File* DocumentListView::getBibTeXFile( ) { return m_bibtexFile; } void DocumentListView::setItems() { TQApplication::setOverrideCursor( TQt::waitCursor ); KProgressDialog *prgDlg = new KProgressDialog( this, "prgDlg", i18n( "List View" ), i18n( "Updating main view ..." ), TRUE ); prgDlg->show(); KProgress *progress = prgDlg->progressBar(); progress->setTotalSteps( m_bibtexFile->count() ); bool update = viewport()->isUpdatesEnabled(); viewport()->setUpdatesEnabled( FALSE ); int sortCol = sortColumn(); setSortColumn( -1 ); clear(); for ( unsigned int i = 0; i < m_bibtexFile->count(); i++ ) { BibTeX::Element *element = m_bibtexFile->at( i ); new DocumentListViewItem( m_bibtexFile, element, this ); progress->setProgress( i ); if ( i % 43 == 23 ) kapp->processEvents(); } viewport()->setUpdatesEnabled( update ); setSortColumn( sortCol ); triggerUpdate(); delete prgDlg; updateVisiblity(); TQApplication::restoreOverrideCursor(); } void DocumentListView::insertItems( BibTeX::File *items, KBibTeX::DocumentListViewItem *after ) { for ( BibTeX::File::ElementList::iterator it = items->begin(); it != items->end(); it++ ) after = insertItem( *it, after ); } KBibTeX::DocumentListViewItem * DocumentListView::insertItem( BibTeX::Element *item, KBibTeX::DocumentListViewItem *after ) { if ( m_bibtexFile == NULL ) m_bibtexFile = new BibTeX::File(); BibTeX::Element *element = NULL; BibTeX::Entry *entry = dynamic_cast( item ); if ( entry != NULL ) { BibTeX::Entry *newEntry = new BibTeX::Entry( entry ); if ( m_bibtexFile->containsKey( newEntry->id() ) ) { int counter = 0; TQString newId = TQString( newEntry->id() ).append( '_' ).append( TQString::number( ++counter ) ); while ( m_bibtexFile->containsKey( newId ) ) newId = TQString( newEntry->id() ).append( '_' ).append( TQString::number( ++counter ) ); newEntry->setId( newId ); } element = newEntry; } else element = item->clone(); m_bibtexFile->appendElement( element, after == NULL ? NULL : after->element() ); after = new DocumentListViewItem( m_bibtexFile, element, this, after ); after->setUnreadStatus( TRUE ); updateVisiblity( after ); m_unreadItems.append( after ); emit modified(); TQTimer::singleShot( 3500, this, SLOT( makeNewItemsUnread() ) ); return after; } void DocumentListView::insertItem( BibTeX::Element *item ) { insertItem( item, NULL ); } void DocumentListView::updateVisiblity() { TQListViewItemIterator it( this ); while ( it.current() ) { DocumentListViewItem * kblvi = dynamic_cast( it.current() ); updateVisiblity( kblvi ); it++; } } void DocumentListView::updateVisiblity( KBibTeX::DocumentListViewItem *item ) { Settings * settings = Settings::self( m_bibtexFile ); BibTeX::Element *element = item->element(); bool notFiltered = m_filter.isEmpty() || element ->containsPattern( m_filter, m_filterFieldType, m_filterType ); BibTeX::Macro *macro = dynamic_cast( element ); if ( macro != NULL ) item->setVisible( notFiltered && settings->editing_ShowMacros ); else { BibTeX::Comment *comment = dynamic_cast( element ); if ( comment != NULL ) item->setVisible( notFiltered && settings->editing_ShowComments ); else item->setVisible( notFiltered ); } } void DocumentListView::deferredInitialization() { connect( header(), SIGNAL( sizeChange( int, int, int ) ), this, SLOT( saveColumnWidths() ) ); connect( header(), SIGNAL( indexChange( int, int, int ) ), this, SLOT( saveColumnIndex() ) ); } void DocumentListView::restoreState() { Settings * settings = Settings::self( m_bibtexFile ); if ( settings->editing_UseSpecialFont ) setFont( settings->editing_SpecialFont ); else setFont( TDEGlobalSettings::generalFont() ); header() ->setFont( TDEGlobalSettings::generalFont() ); restoreColumnIndex(); restoreColumnWidths(); restoreSortingColumn(); } void DocumentListView::setViewShowColumnsMenu( TDEActionMenu *actionMenu ) { if ( m_headerMenu == NULL ) { m_headerMenu = actionMenu->popupMenu(); m_headerMenu->insertTitle( i18n( "Show Columns" ) ); m_headerMenu->setCheckable( TRUE ); connect( m_headerMenu, SIGNAL( activated( int ) ), this, SLOT( activateShowColumnMenu( int ) ) ); Settings * settings = Settings::self( m_bibtexFile ); int item = m_headerMenu->insertItem( i18n( "Element Type" ), 0 ); m_headerMenu->setItemChecked( item, settings->editing_MainListColumnsWidth[ 0 ] > 0 ); m_headerMenu->insertSeparator(); for ( int i = 0; i <= ( int ) BibTeX::EntryField::ftYear - ( int ) BibTeX::EntryField::ftAbstract; i++ ) { BibTeX::EntryField::FieldType fieldType = ( BibTeX::EntryField::FieldType )( i + ( int ) BibTeX::EntryField::ftAbstract ); TQString label = Settings::fieldTypeToI18NString( fieldType ); item = m_headerMenu->insertItem( label, ( int ) fieldType + 2 ); m_headerMenu->setItemChecked( item, settings->editing_MainListColumnsWidth[ i + 2 ] > 0 ); } } } void DocumentListView::deleteSelected() { TQListViewItemIterator it( this, TQListViewItemIterator::Selected | TQListViewItemIterator::Visible ); if ( it.current() == NULL ) return; TQListViewItem *above = it.current() ->itemAbove(); TQValueList toBeDeleted; while ( it.current() ) { DocumentListViewItem * kblvi = dynamic_cast( it.current() ); toBeDeleted.append( kblvi ); it++; } for ( TQValueList::Iterator it = toBeDeleted.begin(); it != toBeDeleted.end(); ++it ) { m_bibtexFile->deleteElement(( *it )->element() ); takeItem( *it ); delete( *it ); } if ( above ) ensureItemVisible( above ); emit modified(); } const TQValueList DocumentListView::selectedItems() { TQValueList result; TQListViewItemIterator it( this, TQListViewItemIterator::Selected ); while ( it.current() ) { DocumentListViewItem * kblvi = dynamic_cast( it.current() ); if ( kblvi->isVisible() ) result.append( kblvi->element() ); it++; } return result; } TQString DocumentListView::selectedToBibTeXText() { BibTeX::FileExporterBibTeX *exporter = new BibTeX::FileExporterBibTeX(); exporter->setEncoding( "latex" ); TQBuffer buffer; buffer.open( IO_WriteOnly ); TQValueList selectedElements = selectedItems(); for ( TQValueList::iterator it = selectedElements.begin(); it != selectedElements.end(); ++it ) exporter->save( &buffer, *it ); buffer.close(); delete exporter; buffer.open( IO_ReadOnly ); TQTextStream in( &buffer ); in.setEncoding( TQTextStream::UnicodeUTF8 ); TQString result = in.read(); buffer.close(); return result; } TQString DocumentListView::selectedToBibTeXRefs() { TQString refs; TQValueList selectedElements = selectedItems(); for ( TQValueList::iterator it = selectedElements.begin(); it != selectedElements.end(); ++it ) { BibTeX::Entry *entry = dynamic_cast( *it ); if ( entry == NULL ) continue; if ( !refs.isEmpty() ) refs.append( "," ); refs.append( entry->id() ); } return TQString( "\\cite{%1}" ).arg( refs ); } void DocumentListView::copy() { kapp->clipboard() ->setText( selectedToBibTeXText() ); } void DocumentListView::copyReferences() { kapp->clipboard() ->setText( selectedToBibTeXRefs() ); } void DocumentListView::cut() { copy(); deleteSelected(); } bool DocumentListView::paste() { DocumentListViewItem * dlvi = dynamic_cast( selectedItem() ); if ( dlvi == NULL ) dlvi = dynamic_cast( currentItem() ); TQString clipboardText = kapp->clipboard() ->text(); return paste( clipboardText, dlvi ); } bool DocumentListView::paste( const TQString& text, DocumentListViewItem *at ) { Settings * settings = Settings::self( m_bibtexFile ); /** check if clipboard contains BibTeX content */ if ( BibTeX::FileImporterBibTeX::guessCanDecode( text ) ) { BibTeX::FileImporter *importer = new BibTeX::FileImporterBibTeX( settings->editing_FirstNameFirst ); BibTeX::File *clipboardData = importer->load( text ); delete importer; if ( clipboardData != NULL ) { insertItems( clipboardData, at ); delete clipboardData; return TRUE; } else return FALSE; } else if ( settings->external_xml2bibAvailable && settings->external_end2xmlAvailable && BibTeX::FileImporterBibUtils::guessCanDecode( text ) ) { Settings * settings = Settings::self( m_bibtexFile ); BibTeX::File::FileFormat inputFormat = BibTeX::FileImporterBibUtils::guessInputFormat( text ); BibTeX::FileImporter *importer = NULL; if ( inputFormat == BibTeX::File::formatRIS && !settings->fileIO_useBibUtils ) importer = new BibTeX::FileImporterRIS(); else importer = new BibTeX::FileImporterBibUtils( inputFormat ); BibTeX::File *clipboardData = importer->load( text ); delete importer; if ( clipboardData != NULL ) { insertItems( clipboardData, at ); delete clipboardData; return TRUE; } else return FALSE; } else if ( BibTeX::FileImporterRIS::guessCanDecode( text ) ) { BibTeX::FileImporter *importer = new BibTeX::FileImporterRIS( ); BibTeX::File *clipboardData = importer->load( text ); delete importer; if ( clipboardData != NULL ) { insertItems( clipboardData, at ); delete clipboardData; return TRUE; } else return FALSE; } else { /** Decoding the paste text as bibtex failed. Maybe the user wants to paste the text as link address, abstract, etc... */ if ( !at ) // no list view item selected to add data to return FALSE; // fetch BibTeX element from current list view item BibTeX::Entry * element = dynamic_cast( at->element() ); if ( ! element ) return FALSE; // build popup menu TDEPopupMenu * popup = new TDEPopupMenu( this, "pastePopup" ); popup->insertTitle( i18n( "Paste text as..." ) ); for ( int i = ( int ) BibTeX::EntryField::ftAuthor; i <= ( int ) BibTeX::EntryField::ftYear; i++ ) { BibTeX::EntryField::FieldType ft = ( BibTeX::EntryField::FieldType ) i; popup->insertItem( Settings::fieldTypeToI18NString( ft ), i ); } popup->insertSeparator(); TQIconSet cancelPixmap = TDEGlobal::iconLoader() ->loadIconSet( "cancel", TDEIcon::Small ); int cancelId = popup->insertItem( cancelPixmap, i18n( "Cancel" ) ); // show popup menu int selectedId = popup->exec( TQCursor::pos() ); if ( selectedId == cancelId || selectedId == -1 ) return FALSE; // cancel menu // determine field to add clipboard value to BibTeX::EntryField::FieldType fieldType = ( BibTeX::EntryField::FieldType ) selectedId; BibTeX::EntryField * field = element->getField( fieldType ); if ( field == NULL ) { field = new BibTeX::EntryField( fieldType ); element->addField( field ); } else if ( field->value() != NULL ) delete field->value(); TQString encodedText = BibTeX::EncoderLaTeX::currentEncoderLaTeX() ->encode( text ); // create new value from clipboard's content BibTeX::Value * value = new BibTeX::Value(); if ( fieldType == BibTeX::EntryField::ftAuthor || fieldType == BibTeX::EntryField::ftEditor ) { Settings * settings = Settings::self( m_bibtexFile ); value->items.append( new BibTeX::PersonContainer( encodedText, settings->editing_FirstNameFirst ) ); } else if ( fieldType == BibTeX::EntryField::ftKeywords ) value->items.append( new BibTeX::KeywordContainer( encodedText ) ); else value->items.append( new BibTeX::PlainText( encodedText ) ); field->setValue( value ); return TRUE; } } void DocumentListView::selectAll() { TQListView::selectAll( true ); } /* void DocumentListView::sendSelectedToLyx() { TQStringList refsToSend; TQListViewItemIterator it( this, TQListViewItemIterator::Selected ); while ( it.current() ) { DocumentListViewItem * kblvi = dynamic_cast( it.current() ); BibTeX::Entry *entry = dynamic_cast( kblvi->element() ); if ( entry != NULL && kblvi->isVisible() ) refsToSend.append( entry->id() ); it++; } Settings * settings = Settings::self( m_bibtexFile ); TQString lyxPipeFilename = settings->detectLyXInPipe(); kdDebug() << "sendSelectedToLyx: lyxPipeFilename= " << lyxPipeFilename << endl; TQFile pipe( lyxPipeFilename ); if ( pipe.exists() && pipe.open( IO_WriteOnly ) ) { TQTextStream * writer = new TQTextStream( &pipe ); TQString msg = "LYXCMD:kbibtex:citation-insert:" + refsToSend.join( "," ); *writer << msg << endl; delete writer; pipe.close(); } else KMessageBox::error( this, ( lyxPipeFilename.isEmpty() ? i18n( "Cannot establish a link to LyX" ) : TQString( i18n( "Cannot establish a link to LyX using the pipe \"%1\"" ) ).arg( lyxPipeFilename ) ) + i18n( "\nMaybe LyX is not running?" ), i18n( "Error communicating with LyX" ) ); }*/ void DocumentListView::slotDoubleClick( TQListViewItem *item ) { DocumentListViewItem *dlvi = dynamic_cast( item ); if ( dlvi != NULL ) emit executed( dlvi ); } void DocumentListView::filter( const TQString & text, BibTeX::Element::FilterType filterType, BibTeX::EntryField::FieldType fieldType ) { m_filter = text; m_filterType = filterType; m_filterFieldType = fieldType; updateVisiblity(); } void DocumentListView::setReadOnly( bool isReadOnly ) { m_isReadOnly = isReadOnly; } void DocumentListView::activateShowColumnMenu( int id ) { if ( id >= 0 ) { if ( columnWidth( id ) > 0 ) { hideColumn( id ); m_headerMenu->setItemChecked( id, FALSE ); } else { showColumn( id ); m_headerMenu->setItemChecked( id, TRUE ); } } } void DocumentListView::showBibtexListContextMenu( TDEListView *, TQListViewItem *, const TQPoint & p ) { if ( m_contextMenu != NULL ) { emit selectionChanged(); m_contextMenu->popup( p ); } } void DocumentListView::setSortingColumn( int column ) { Settings * settings = Settings::self( m_bibtexFile ); settings->editing_MainListSortingColumn = column; settings->editing_MainListSortingOrder = ( sortOrder() == TQt::Ascending ) ? 1 : -1; } bool DocumentListView::acceptDrag( TQDropEvent * event ) const { if ( event->source() == this ) return false; return TQTextDrag::canDecode( event ) || TQUriDrag::canDecode( event ); } void DocumentListView::startDrag() { Settings * settings = Settings::self( m_bibtexFile ); TQDragObject *d = new TQTextDrag( settings->editing_DragAction == Settings::COPYREFERENCE ? selectedToBibTeXRefs() : selectedToBibTeXText(), this ); d->dragCopy(); } void DocumentListView::saveColumnIndex() { Settings * settings = Settings::self( m_bibtexFile ); TQHeader *hdr = header(); for ( int i = 0; i < columns(); i++ ) settings->editing_MainListColumnsIndex[ i ] = hdr->mapToIndex( i ); } void DocumentListView::restoreColumnIndex() { Settings * settings = Settings::self( m_bibtexFile ); TQHeader *hdr = header(); for ( int i = 0; i < columns(); i++ ) hdr->moveSection( i, settings->editing_MainListColumnsIndex[ i ] ); } void DocumentListView::saveColumnWidths( int col ) { Settings * settings = Settings::self( m_bibtexFile ); int from = col == -1 ? 0 : col, to = col == -1 ? columns() : ( col + 1 ); for ( int i = from; i < to; i++ ) { if ( columnWidthMode( i ) == TQListView::Manual ) settings->editing_MainListColumnsWidth[ i ] = columnWidth( i ); else settings->editing_MainListColumnsWidth[ i ] = 0xffff; } } void DocumentListView::restoreColumnWidths() { Settings * settings = Settings::self( m_bibtexFile ); for ( int col = 0; col < columns(); col++ ) { int colWidth = settings->editing_MainListColumnsWidth[ col ]; showColumn( col, colWidth ); } } void DocumentListView::restoreSortingColumn() { Settings * settings = Settings::self( m_bibtexFile ); setSortColumn( settings->editing_MainListSortingColumn ); setSortOrder( settings->editing_MainListSortingOrder > 0 ? TQt::Ascending : TQt::Descending ); } void DocumentListView::makeNewItemsUnread() { for ( TQValueList::ConstIterator it = m_unreadItems.begin() ; it != m_unreadItems.end(); ++it ) { ( *it ) ->setUnreadStatus( FALSE ); ( *it ) ->repaint(); } m_unreadItems.clear(); } void DocumentListView::slotDropped( TQDropEvent * event, TQListViewItem * item ) { TQString text; TQStrList urlList; if ( TQTextDrag::decode( event, text ) && KURL( text ).isValid() ) urlList.append( text ); if ( !urlList.isEmpty() || TQUriDrag::decode( event, urlList ) ) { TQString url = urlList.at( 0 ); TQString tmpFile; if ( ! TDEIO::NetAccess::download( url, tmpFile, 0 ) ) { KMessageBox::error( this, TDEIO::NetAccess::lastErrorString() ); return ; } TQFile f( tmpFile ); if ( ! f.open( IO_ReadOnly ) ) { KMessageBox::error( this, f.errorString() ); TDEIO::NetAccess::removeTempFile( tmpFile ); return ; } TQByteArray ba = f.readAll(); text = TQString( ba ); f.close(); TDEIO::NetAccess::removeTempFile( tmpFile ); } else if ( !TQTextDrag::decode( event, text ) ) return; event->accept( TRUE ); DocumentListViewItem * dlvi = dynamic_cast( item ); paste( text, dlvi ); } bool DocumentListView::eventFilter( TQObject * watched, TQEvent * e ) { if ( watched == header() ) { switch ( e->type() ) { case TQEvent::MouseButtonPress: { if ( static_cast( e ) ->button() == RightButton && m_headerMenu != NULL ) m_headerMenu->popup( TQCursor::pos() ); break; } default: break; } } return TDEListView::eventFilter( watched, e ); } void DocumentListView::keyPressEvent( TQKeyEvent *e ) { if ( e->key() == TQKeyEvent::Key_Enter || e->key() == TQKeyEvent::Key_Return ) { DocumentListViewItem *item = dynamic_cast( selectedItem() ); if ( item == NULL ) item = dynamic_cast( currentItem() ); if ( item != NULL ) emit executed( item ); } else TDEListView::keyPressEvent( e ); } void DocumentListView::showColumn( int col, int colWidth ) { if ( colWidth == 0xffff ) { adjustColumn( col ); if ( columnWidth( col ) > width() / 3 ) colWidth = width() / 4; if ( columnWidth( col ) < width() / 12 ) colWidth = width() / 8; } if ( colWidth < 0xffff ) setColumnWidth( col, colWidth ); header() ->setResizeEnabled( colWidth > 0, col ); setColumnWidthMode( col, colWidth < 0xffff ? TQListView::Manual : TQListView::Maximum ); saveColumnWidths( col ); } void DocumentListView::hideColumn( int col ) { showColumn( col, 0 ); } void DocumentListView::buildColumns() { addColumn( i18n( "Element Type" ) ); addColumn( i18n( "Entry Id" ) ); for ( int i = 0; i <= ( int ) BibTeX::EntryField::ftYear - ( int ) BibTeX::EntryField::ftAbstract; i++ ) { BibTeX::EntryField::FieldType fieldType = ( BibTeX::EntryField::FieldType )( i + ( int ) BibTeX::EntryField::ftAbstract ); TQString label = Settings::fieldTypeToI18NString( fieldType ); addColumn( label ); } } } #include "documentlistview.moc"