Logo Search packages:      
Sourcecode: kbibtex version File versions  Download package

documentlistview.cpp

/***************************************************************************
*   Copyright (C) 2004-2006 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 <qevent.h>
#include <qdragobject.h>
#include <qfile.h>
#include <qcursor.h>
#include <qbuffer.h>
#include <qlistview.h>
#include <qclipboard.h>
#include <qheader.h>
#include <qtextstream.h>
#include <qtimer.h>

#include <kapplication.h>
#include <kio/netaccess.h>
#include <ktempfile.h>
#include <klocale.h>
#include <kurl.h>
#include <kdebug.h>
#include <kurldrag.h>
#include <kactionclasses.h>
#include <kaction.h>
#include <kpopupmenu.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <kiconloader.h>

#include <kbibtex_part.h>
#include <documentlistviewitem.h>
#include <file.h>
#include <fileimporterbibtex.h>
#include <fileexporterbibtex.h>
#include <element.h>
#include <entry.h>
#include <macro.h>
#include <comment.h>
#include <entrywidget.h>
#include <commentwidget.h>
#include <macrowidget.h>
#include <settings.h>
#include <encoderlatex.h>

#include "documentlistview.h"

namespace KBibTeX
{
    DocumentListView::DocumentListView( KBibTeX::DocumentWidget *docWidget, bool isReadOnly, QWidget *parent, const char *name )
            : KListView( parent, name ), m_docWidget( docWidget ), m_contextMenu( NULL ), m_headerMenu( NULL ), m_isReadOnly( isReadOnly ), m_newElementCounter( 1 )
    {
        setAllColumnsShowFocus( true );
        setShowSortIndicator( true );
        setSelectionMode( QListView::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( KListView *, QListViewItem *, const QPoint & ) ), this, SLOT( showBibtexListContextMenu( KListView *, QListViewItem *, const QPoint & ) ) );
        connect( this, SIGNAL( doubleClicked( QListViewItem*, const QPoint&, int ) ), this, SLOT( slotDoubleClick( QListViewItem* ) ) );
        connect( this, SIGNAL( dropped( QDropEvent*, QListViewItem* ) ), this, SLOT( slotDropped( QDropEvent*, QListViewItem* ) ) );
    }

    DocumentListView::~DocumentListView()
    {
        // nothing
    }

    void DocumentListView::setFactory( KXMLGUIFactory *factory, KXMLGUIClient *client )
    {
        m_contextMenu = static_cast<KPopupMenu*>( 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()
    {
        QApplication::setOverrideCursor( Qt::waitCursor );
        setUpdatesEnabled( FALSE );

        clear();
        for ( unsigned int i = 0; i < m_bibtexFile->count(); i++ )
        {
            BibTeX::Element *element = m_bibtexFile->at( i );
            QListViewItem *item = new DocumentListViewItem( element, this );
            item->setVisible( m_filter.isEmpty() || element->containsPattern( m_filter, m_filterFieldType ) );
        }
        //     sort();

        setUpdatesEnabled( TRUE );
        triggerUpdate();
        QApplication::restoreOverrideCursor();
        //     triggerUpdate();
    }

    bool DocumentListView::insertItems( BibTeX::File *items, KBibTeX::DocumentListViewItem *after )
    {
        for ( BibTeX::File::ElementList::iterator it = items->begin(); it != items->end(); it++ )
        {
            BibTeX::Element *element = BibTeX::File::cloneElement( *it );

            m_bibtexFile->appendElement( element, after == NULL ? NULL : after->element() );
            after = new DocumentListViewItem( element, this, after );
            after->setUnreadStatus( TRUE );
            m_unreadItems.append( after );
        }

        QTimer::singleShot( 2500, this, SLOT( makeNewItemsUnread() ) );

        return TRUE;
    }

    void DocumentListView::updateVisiblity()
    {
        Settings * settings = Settings::self();

        QListViewItemIterator it( this );
        while ( it.current() )
        {
            DocumentListViewItem * kblvi = dynamic_cast<DocumentListViewItem*>( it.current() );
            BibTeX::Element *element = kblvi->element();
            bool notFiltered = m_filter.isEmpty() || element ->containsPattern( m_filter, m_filterFieldType );

            BibTeX::Macro *macro = dynamic_cast<BibTeX::Macro*>( element );
            if ( macro != NULL )
                kblvi->setVisible( notFiltered && settings->editing_ShowMacros );
            else
            {
                BibTeX::Comment *comment = dynamic_cast<BibTeX::Comment*>( element );
                if ( comment != NULL )
                    kblvi->setVisible( notFiltered && settings->editing_ShowComments );
                else
                    kblvi->setVisible( notFiltered );
            }

            it++;
        }
    }

    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();
        if ( settings->editing_UseSpecialFont )
            setFont( settings->editing_SpecialFont );
        else
            setFont( KGlobalSettings::generalFont() );
        header() ->setFont( KGlobalSettings::generalFont() );

        restoreColumnIndex();
        restoreColumnWidths();
        restoreSortingColumn();
    }

    void DocumentListView::setViewShowColumnsMenu( KActionMenu *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();

            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 );
                QString 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()
    {
        QListViewItemIterator it( this, QListViewItemIterator::Selected );
        QListViewItem *above = it.current() ->itemAbove();
        while ( it.current() )
        {
            DocumentListViewItem * kblvi = dynamic_cast<DocumentListViewItem*>( it.current() );
            m_bibtexFile->deleteElement( kblvi->element() );
            it++;
            takeItem( kblvi );
            delete ( kblvi );
        }

        if ( above )
            ensureItemVisible( above );

        emit modified();
    }

    void DocumentListView::copySelected()
    {
        kapp->clipboard() ->setText( selectedAsString() );
    }

    void DocumentListView::copyRefSelected()
    {
        QString refs;
        QListViewItemIterator it( this, QListViewItemIterator::Selected );
        while ( it.current() )
        {
            DocumentListViewItem * kblvi = dynamic_cast<DocumentListViewItem*>( it.current() );
            BibTeX::Entry *entry = dynamic_cast<BibTeX::Entry*>( kblvi->element() );
            if ( entry != NULL )
            {
                if ( !refs.isEmpty() )
                    refs.append( "," );
                refs.append( entry->id() );
            }
            it++;
        }

        kapp->clipboard() ->setText( QString( "\\cite{%1}" ).arg( refs ) );
    }

    void DocumentListView::cutSelected()
    {
        copySelected();
        deleteSelected();
    }

    bool DocumentListView::paste()
    {
        QListViewItem * lvi = selectedItem();
        if ( lvi == NULL )
            lvi = currentItem();

        DocumentListViewItem * dlvi = NULL;
        if ( lvi != NULL )
            dlvi = dynamic_cast<KBibTeX::DocumentListViewItem *>( lvi );

        BibTeX::FileImporter *importer = NULL;
        if ( BibTeX::FileImporterBibTeX::guessCanDecode( kapp->clipboard() ->text() ) )
            importer = new BibTeX::FileImporterBibTeX();

        if ( ! importer )
        {
            // Decoding the paste text as bibtex failed. Maybe the user wants to paste the text as
            // link address, abstract, etc...
            if ( ! dlvi )
                return FALSE;
            BibTeX::Entry * element = dynamic_cast<BibTeX::Entry*>( dlvi->element() );
            if ( ! element )
                return FALSE;
            KPopupMenu * popup = new KPopupMenu( this, "pastePopup" );
            popup->insertTitle( i18n( "Paste text as..." ) );
            for ( int i = 0; i <= ( int ) BibTeX::EntryField::ftYear; i++ )
            {
                BibTeX::EntryField::FieldType ft;
                ft = ( BibTeX::EntryField::FieldType ) i;
                popup->insertItem( Settings::fieldTypeToI18NString( ft ), i );
            }
            popup->insertSeparator();
            QIconSet cancelPixmap = KGlobal::iconLoader() ->loadIconSet( "cancel", KIcon::Small );
            int cancelId = popup->insertItem( cancelPixmap, i18n( "Cancel" ) );
            int selectedId = popup->exec( QCursor::pos() );
            if ( selectedId == cancelId || selectedId == -1 )
                return FALSE;
            BibTeX::EntryField::FieldType fieldType = ( BibTeX::EntryField::FieldType ) selectedId;
            BibTeX::EntryField * field = element->getField( fieldType );
            if ( ! field )
            {
                field = new BibTeX::EntryField( fieldType );
                element->addField( field );
            }
            else if ( field->value() != NULL )
                delete field->value();

            BibTeX::Value * value = NULL;
            if ( fieldType == BibTeX::EntryField::ftAuthor || fieldType == BibTeX::EntryField::ftEditor )
                value = new BibTeX::ValuePersons();
            else
                value = new BibTeX::Value();
            QString stringValue = kapp->clipboard() ->text();
            // FIXME: I assume that the encoding is correct here; i am not sure if
            // this is ok; maybe I need a construct like in
            // BibTeXFileImporterBibTeX::load() here;
            // maybe Thomas Fischer knows if this needs fixing...
            // TF: I assume that all clipboard content is UTF-8 ...
            stringValue = BibTeX::EncoderLaTeX::currentEncoderLaTeX() ->encode( stringValue );

            value->add( new BibTeX::ValueItem( stringValue, FALSE ) );
            field->setValue( value );
            return TRUE;
        }

        BibTeX::File *clipboardData = importer->load( kapp->clipboard() ->text() );
        delete importer;

        if ( clipboardData != NULL )
            return insertItems( clipboardData, dlvi );
        else
            return FALSE;
    }

    void DocumentListView::slotDoubleClick( QListViewItem *item )
    {
        Settings * settings = Settings::self();
        bool openingDocumentOK = FALSE;

        if ( settings->editing_MainListDoubleClickAction == 1 )
        {
            if ( item == NULL )
                item = selectedItem();
            if ( item == NULL )
                item = currentItem();

            DocumentListViewItem * kblvi = dynamic_cast<DocumentListViewItem*>( item );
            if ( kblvi != NULL )
            {
                BibTeX::Element * element = kblvi->element();
                BibTeX::Entry *entry = dynamic_cast<BibTeX::Entry*>( element );
                if ( entry != NULL )
                {
                    QStringList urls = entry->urls();
                    for ( QStringList::Iterator it = urls.begin(); it != urls.end(); ++it )
                    {
                        KURL url = KURL( *it );
                        if ( url.isValid() && ( !url.isLocalFile() || QFile::exists( url.path() ) ) )
                        {
                            kapp->invokeBrowser( url.prettyURL() );
                            openingDocumentOK = TRUE;
                            break;
                        }
                    }
                }
            }
        }

        if ( !openingDocumentOK )
            editElement( item );
    }


    BibTeX::Element* DocumentListView::editElement( QListViewItem * item )
    {
        QDialog::DialogCode dialogResult = QDialog::Rejected;
        BibTeX::Element* result = NULL;

        if ( item == NULL )
            item = selectedItem();
        if ( item == NULL )
            item = currentItem();

        if ( item != NULL )
        {
            DocumentListViewItem * lvi = dynamic_cast<KBibTeX::DocumentListViewItem*>( item );
            if ( lvi != NULL )
            {
                BibTeX::Entry * entry = dynamic_cast<BibTeX::Entry*>( lvi->element() );
                if ( entry )
                {
                    dialogResult = KBibTeX::EntryWidget::execute( entry, m_bibtexFile, m_isReadOnly );
                    if ( dialogResult == QDialog::Accepted )
                        result = entry;
                }
                else
                {
                    BibTeX::Comment * comment = dynamic_cast<BibTeX::Comment*>( lvi->element() );
                    if ( comment )
                    {
                        dialogResult = KBibTeX::CommentWidget::execute( comment, m_isReadOnly );
                        if ( dialogResult == QDialog::Accepted )
                            result = comment;
                    }
                    else
                    {
                        BibTeX::Macro* macro = dynamic_cast<BibTeX::Macro*>( lvi->element() );
                        if ( macro )
                            dialogResult = KBibTeX::MacroWidget::execute( macro, m_isReadOnly );
                        if ( dialogResult == QDialog::Accepted )
                            result = macro;
                    }
                }

                if ( dialogResult == QDialog::Accepted )
                    lvi->updateItem();
            }
        }

        if ( dialogResult == QDialog::Accepted )
            emit modified();

        return result;
    }

    void DocumentListView::filterText( const QString & text, BibTeX::EntryField::FieldType fieldType )
    {
        m_filter = text;
        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( KListView *, QListViewItem *, const QPoint & p )
    {
        if ( m_contextMenu != NULL )
        {
            emit selectionChanged();
            m_contextMenu->popup( p );
        }
    }

    void DocumentListView::setSortingColumn( int column )
    {
        Settings * settings = Settings::self();
        settings->editing_MainListSortingColumn = column;
        settings->editing_MainListSortingOrder = ( sortOrder() == Qt::Ascending ) ? 1 : -1;
    }

    bool DocumentListView::acceptDrag( QDropEvent * event ) const
    {
        return QTextDrag::canDecode( event ) || QUriDrag::canDecode( event );;
    }

    void DocumentListView::saveColumnIndex( int col )
    {
        Settings * settings = Settings::self();
        QHeader *hdr = header();

        int from = col == -1 ? 0 : col, to = col == -1 ? columns() : ( col + 1 );

        for ( int i = from; i < to; i++ )
        {
            settings->editing_MainListColumnsIndex[ i ] = hdr->mapToIndex( i );
        }
    }

    void DocumentListView::restoreColumnIndex()
    {
        Settings * settings = Settings::self();
        QHeader *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();

        int from = col == -1 ? 0 : col, to = col == -1 ? columns() : ( col + 1 );

        for ( int i = from; i < to; i++ )
        {
            if ( columnWidthMode( i ) == QListView::Manual )
                settings->editing_MainListColumnsWidth[ i ] = columnWidth( i );
            else
                settings->editing_MainListColumnsWidth[ i ] = 0xffff;
        }
    }

    void DocumentListView::restoreColumnWidths()
    {
        Settings * settings = Settings::self();

        for ( int col = 0; col < columns(); col++ )
        {
            int colWidth = settings->editing_MainListColumnsWidth[ col ];
            showColumn( col, colWidth );
        }
    }

    void DocumentListView::restoreSortingColumn()
    {
        Settings * settings = Settings::self();
        setSortColumn( settings->editing_MainListSortingColumn );
        setSortOrder( settings->editing_MainListSortingOrder > 0 ? Qt::Ascending : Qt::Descending );
    }

    void DocumentListView::makeNewItemsUnread()
    {
        for ( QValueList<DocumentListViewItem*>::ConstIterator it = m_unreadItems.begin() ; it != m_unreadItems.end(); ++it )
        {
            ( *it ) ->setUnreadStatus( FALSE );
            ( *it ) ->repaint();
        }

        m_unreadItems.clear();
    }

    void DocumentListView::slotDropped( QDropEvent * event, QListViewItem * item )
    {
        QString text;
        QStrList urlList;

        if ( QUriDrag::decode( event, urlList ) )
        {
            QString url = urlList.at ( 0 );
            QString tmpFile;
            if ( ! KIO::NetAccess::download( url, tmpFile, 0 ) )
            {
                KMessageBox::error( this, KIO::NetAccess::lastErrorString() );
                return ;
            }
            QFile f( tmpFile );
            if ( ! f.open( IO_ReadOnly ) )
            {
                KMessageBox::error( this, f.errorString() );
                KIO::NetAccess::removeTempFile( tmpFile );
                return ;
            }
            QByteArray ba = f.readAll();
            text = QString( ba );
            f.close();
            KIO::NetAccess::removeTempFile( tmpFile );

        }
        else if ( ! QTextDrag::decode( event, text ) )
            return ;

        event->accept( TRUE );
        DocumentListViewItem * dlvi = dynamic_cast<KBibTeX::DocumentListViewItem *>( item );
        BibTeX::FileImporter *importer = NULL;
        if ( BibTeX::FileImporterBibTeX::guessCanDecode( text ) )
            importer = new BibTeX::FileImporterBibTeX();
        //        else if (BibTeX::FileImporterExternal::guessCanDecode( text ))
        //            importer = new BibTeX::FileImporterExternal();
        else
            return ;

        BibTeX::File *droppedData = importer->load( text );
        delete importer;
        if ( droppedData != NULL )
            insertItems( droppedData, dlvi );
    }

    // void DocumentListView::contentsDragEnterEvent( QDragEnterEvent * event )
    // {
    //     KListView::contentsDragEnterEvent( event );
    //     qDebug( "contentsDragEnterEvent" );
    //     event->accept( FALSE );
    // }

    // void DocumentListView::contentsDropEvent( QDropEvent * event )
    // {
    //     KListView::contentsDropEvent( event );
    //     //     dropEvent( event );
    //     qDebug( "ContentsDropEvent" );
    //     event->accept( FALSE );
    // }

    // void DocumentListView::startDrag()
    // {
    //     QDragObject * d = new QTextDrag( selectedAsString(), this );
    //     d->dragCopy();
    //     // do NOT delete d.
    // }

    QString DocumentListView::selectedAsString()
    {
        QBuffer buffer;
        buffer.open( IO_WriteOnly );
        BibTeX::FileExporterBibTeX * exporter = new BibTeX::FileExporterBibTeX();
        exporter->setEncoding( BibTeX::File::encLaTeX );
        QListViewItemIterator it( this, QListViewItemIterator::Selected );
        while ( it.current() )
        {
            DocumentListViewItem * kblvi = dynamic_cast<DocumentListViewItem*>( it.current() );
            exporter->save( &buffer, kblvi->element() );
            it++;
        }
        delete exporter;
        buffer.close();

        buffer.open( IO_ReadOnly );
        QTextStream in( &buffer );
        in.setEncoding( QTextStream::UnicodeUTF8 );
        QString result = in.read();
        buffer.close();

        return result;
    }

    bool DocumentListView::eventFilter( QObject * watched, QEvent * e )
    {
        if ( watched == header() )
        {
            switch ( e->type() )
            {
            case QEvent::MouseButtonPress:
                {
                    if ( static_cast<QMouseEvent *>( e ) ->button() == RightButton && m_headerMenu != NULL )
                        m_headerMenu->popup( QCursor::pos() );

                    break;
                }

            default: break;
            }
        }

        return KListView::eventFilter( watched, e );
    }

    void DocumentListView::keyPressEvent ( QKeyEvent *e )
    {
        if ( e->key() == QKeyEvent::Key_Enter || e->key() == QKeyEvent::Key_Return )
        {
            slotDoubleClick();
        }
        else
            KListView::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 ? QListView::Manual : QListView::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 );
            QString label = Settings::fieldTypeToI18NString( fieldType );
            addColumn( label );
        }
    }
}

#include "documentlistview.moc"

Generated by  Doxygen 1.6.0   Back to index