/*************************************************************************** * Copyright (C) 2005 by Enrico Ros * * * * 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. * ***************************************************************************/ // qt/kde includes #include #include #include #include #include #include #include #include #include #include #include // local includes #include "core/annotations.h" #include "core/document.h" #include "core/page.h" #include "settings.h" #include "side_reviews.h" Reviews::Reviews( QWidget * parent, KPDFDocument * document ) : QWidget( parent ), m_document( document ), m_delayTimer( 0 ), m_currentPage( -1 ) { // create widgets and layout them vertically QVBoxLayout * vLayout = new QVBoxLayout( this ); vLayout->setMargin( 0 ); vLayout->setSpacing( 4 ); m_toolBar1 = new QToolBar( this ); m_toolBar1->setObjectName( "reviewSearchBar" ); vLayout->addWidget( m_toolBar1 ); m_listView = new K3ListView( this ); vLayout->addWidget( m_listView ); m_toolBar2 = new QToolBar( this ); m_toolBar2->setObjectName( "reviewOptsBar" ); vLayout->addWidget( m_toolBar2 ); // setup 1-UPPER toolbar and searchLine m_searchLine = new K3ListViewSearchLine( m_toolBar1, m_listView ); m_toolBar1->setIconSize( QSize( 16, 16 ) ); m_toolBar1->setMovable( false ); // - add Clear button QString clearIconName = QApplication::layoutDirection() == Qt::RightToLeft ? "clear_left" : "locationbar_erase"; QAction * clearAction = m_toolBar1->addAction( KIcon( clearIconName ), i18n( "Clear Filter" ), m_searchLine, SLOT( clear() ) ); // - add Search line m_toolBar1->addWidget(m_searchLine); // setup 2-LOWER toolbar m_toolBar2->setIconSize( QSize( 16, 16 ) ); m_toolBar2->setMovable( false ); // - add Page button QAction * groupByPageAction = m_toolBar2->addAction( KIcon( "txt" ), i18n( "Group by Page" ) ); groupByPageAction->setCheckable( true ); connect( groupByPageAction, SIGNAL( toggled( bool ) ), this, SLOT( slotPageEnabled( bool ) ) ); groupByPageAction->setChecked( KpdfSettings::groupByPage() ); // - add Author button QAction * groupByAuthorAction = m_toolBar2->addAction( KIcon( "personal" ), i18n( "Group by Author" ) ); groupByAuthorAction->setCheckable( true ); connect( groupByAuthorAction, SIGNAL( toggled( bool ) ), this, SLOT( slotAuthorEnabled( bool ) ) ); groupByAuthorAction->setChecked( KpdfSettings::groupByAuthor() ); // - add separator m_toolBar2->addSeparator(); // - add Current Page Only button QAction * curPageOnlyAction = m_toolBar2->addAction( KIcon( "1downarrow" ), i18n( "Show reviews for current page only" ) ); curPageOnlyAction->setCheckable( true ); connect( curPageOnlyAction, SIGNAL( toggled( bool ) ), this, SLOT( slotCurrentPageOnly( bool ) ) ); curPageOnlyAction->setChecked( KpdfSettings::currentPageOnly() ); // customize listview appearance m_listView->addColumn( i18n("Annotation") ); m_listView->header()->hide(); m_listView->setTreeStepSize( 16 ); m_listView->setResizeMode( K3ListView::AllColumns ); } //BEGIN DocumentObserver Notifies -> requestListViewUpdate void Reviews::notifySetup( const QVector< KPDFPage * > & pages, bool documentChanged ) { // grab the page array when document changes if ( documentChanged ) { m_currentPage = -1; m_pages = pages; // request an update to the listview m_listView->clear(); requestListViewUpdate( 1000 ); } } void Reviews::notifyViewportChanged( bool /*smoothMove*/ ) { // sync current page and update listview on change if filtering-on-page int page = m_document->currentPage(); if ( page != m_currentPage ) { m_currentPage = page; if ( KpdfSettings::currentPageOnly() ) requestListViewUpdate(); } } void Reviews::notifyPageChanged( int pageNumber, int changedFlags ) { // only check if there are changes to annotations if ( changedFlags & DocumentObserver::Annotations ) { // if filtering-on-page and the page is not the active one, return if ( KpdfSettings::currentPageOnly() && pageNumber != m_currentPage ) return; // request an update to the listview // TODO selective update on modified page only // nice trick: listview is cleared but screen not updated. zero flicker. m_listView->setUpdatesEnabled( false ); m_listView->clear(); m_listView->setUpdatesEnabled( true ); requestListViewUpdate(); } } //END DocumentObserver Notifies //BEGIN GUI Slots -> requestListViewUpdate void Reviews::slotPageEnabled( bool on ) { // store toggle state in Settings and update the listview KpdfSettings::setGroupByPage( on ); requestListViewUpdate(); } void Reviews::slotAuthorEnabled( bool on ) { // store toggle state in Settings and update the listview KpdfSettings::setGroupByAuthor( on ); requestListViewUpdate(); } void Reviews::slotCurrentPageOnly( bool on ) { // store toggle state in Settings and update the listview KpdfSettings::setCurrentPageOnly( on ); requestListViewUpdate(); } //END GUI Slots class ReviewItem : public Q3ListViewItem { public: ReviewItem( Q3ListView * parent, const QString & text ) : Q3ListViewItem( parent, text ) {} void paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int align ) { QColorGroup myCg = cg; myCg.setColor( QColorGroup::Text, Qt::red ); Q3ListViewItem::paintCell( p, myCg, column, width, align ); } void paintFocus( QPainter *, const QColorGroup &, const QRect & ) { } }; void Reviews::slotUpdateListView() { // reset listview to default m_listView->clear(); m_listView->setRootIsDecorated( true ); m_listView->setSelectionMode( Q3ListView::Single ); if ( KpdfSettings::currentPageOnly() ) { // handle the 'filter on current page' if ( m_currentPage >= 0 && m_currentPage < (int)m_pages.count() ) { const KPDFPage * page = m_pages[ m_currentPage ]; if ( page->hasAnnotations() ) addContents( page ); } } else { // grab all annotations from pages QVector< KPDFPage * >::iterator it = m_pages.begin(), end = m_pages.end(); for ( ; it != end; ++it ) { const KPDFPage * page = *it; if ( page->hasAnnotations() ) addContents( page ); } } // display an info message if no annotations present if ( !m_listView->firstChild() ) { m_listView->setRootIsDecorated( false ); m_listView->setSelectionMode( Q3ListView::NoSelection ); new ReviewItem( m_listView, i18n("") ); } } void Reviews::addContents( const KPDFPage * page ) { // if page-grouping -> create Page subnode Q3ListViewItem * pageItem = 0; if ( KpdfSettings::groupByPage() ) { QString pageText = i18n( "page %1" ).arg( page->number() + 1 ); pageItem = new Q3ListViewItem( m_listView, pageText ); pageItem->setPixmap( 0, SmallIcon( "txt" ) ); pageItem->setOpen( KpdfSettings::groupByAuthor() ); } // iterate over all annotations in this page const QLinkedList< Annotation * > & annots = page->getAnnotations(); QLinkedList< Annotation * >::const_iterator aIt = annots.begin(), aEnd = annots.end(); for ( ; aIt != aEnd; ++aIt ) { // get annotation Annotation * annotation = *aIt; // if page-grouping -> create Author subnode Q3ListViewItem * authorItem = pageItem; if ( KpdfSettings::groupByAuthor() ) { // get author's name QString author = annotation->author; if ( author.isEmpty() ) author = i18n( "Unknown" ); // find out a previous entry by author authorItem = pageItem ? pageItem->firstChild() : m_listView->firstChild(); while ( authorItem && authorItem->text(0) != author ) authorItem = authorItem->nextSibling(); // if item not found, create one if ( !authorItem ) { if ( pageItem ) authorItem = new Q3ListViewItem( pageItem, author ); else authorItem = new Q3ListViewItem( m_listView, author ); QString icon = author != i18n( "Unknown" ) ? "personal" : "presence_away"; authorItem->setPixmap( 0, SmallIcon( icon ) ); } } // create Annotation subnode Q3ListViewItem * singleItem = authorItem ? new Q3ListViewItem( authorItem, annotation->contents ) : new Q3ListViewItem( m_listView, annotation->contents ); singleItem->setPixmap( 0, SmallIcon( "kpdf" ) ); } } void Reviews::requestListViewUpdate( int delayms ) { // only schedule an update if have any pages if ( m_pages.isEmpty() ) return; // create timer if not present if ( !m_delayTimer ) { m_delayTimer = new QTimer( this ); connect( m_delayTimer, SIGNAL( timeout() ), this, SLOT( slotUpdateListView() ) ); } // start timer if not already running if ( !m_delayTimer->isActive() ) m_delayTimer->start( delayms, true ); } #include "side_reviews.moc"