side_reviews.cpp 9.68 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/***************************************************************************
 *   Copyright (C) 2005 by Enrico Ros <eros.kde@email.it>                  *
 *                                                                         *
 *   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
11
#include <q3header.h>
12 13 14
#include <qlayout.h>
#include <qtimer.h>
#include <ktoolbar.h>
Pino Toscano's avatar
porting  
Pino Toscano committed
15 16
#include <k3listview.h>
#include <k3listviewsearchline.h>
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
#include <kaction.h>
#include <kactionclasses.h>
#include <klocale.h>
#include <kapplication.h>
#include <kiconloader.h>

// local includes
#include "core/annotations.h"
#include "core/document.h"
#include "core/page.h"
#include "conf/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, 0, 4 );
    m_toolBar1 = new KToolBar( this, "reviewSearchBar" );
    vLayout->addWidget( m_toolBar1 );
Pino Toscano's avatar
porting  
Pino Toscano committed
38
    m_listView = new K3ListView( this );
39 40 41 42 43
    vLayout->addWidget( m_listView );
    m_toolBar2 = new KToolBar( this, "reviewOptsBar" );
    vLayout->addWidget( m_toolBar2 );

    // setup 1-UPPER toolbar and searchLine
Pino Toscano's avatar
porting  
Pino Toscano committed
44
    m_searchLine = new K3ListViewSearchLine( m_toolBar1, m_listView );
45 46
    m_toolBar1->setIconDimensions( 16 );
    m_toolBar1->setMovable( false );
47 48
    // - add Clear button
    QString clearIconName = KApplication::reverseLayout() ? "clear_left" : "locationbar_erase";
49 50
#warning lots of KToolBar code to port
/*    m_toolBar1->insertButton( clearIconName, 1, SIGNAL( clicked() ),
51 52 53 54 55 56 57
        m_searchLine, SLOT( clear() ), true, i18n( "Clear Filter" ) );
    // - add Search line
    m_toolBar1->insertWidget( 2, 0, m_searchLine );
    m_toolBar1->setItemAutoSized( 2 );
    m_toolBar1->getWidget( 2 )->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored );

    // setup 2-LOWER toolbar
58 59
    m_toolBar2->setIconDimensions( 16 );
    m_toolBar2->setMovable( false );
60 61 62 63
    // - add Page button
    m_toolBar2->insertButton( "txt", 1, SIGNAL( toggled( bool ) ),
        this, SLOT( slotPageEnabled( bool ) ), true, i18n( "Group by Page" ) );
    m_toolBar2->setToggle( 1 );
Piotr Szymanski's avatar
Piotr Szymanski committed
64
    m_toolBar2->setButton( 1, KpdfSettings::groupByPage() );
65 66 67 68
    // - add Author button
    m_toolBar2->insertButton( "personal", 2, SIGNAL( toggled( bool ) ),
        this, SLOT( slotAuthorEnabled( bool ) ), true, i18n( "Group by Author" ) );
    m_toolBar2->setToggle( 2 );
Piotr Szymanski's avatar
Piotr Szymanski committed
69
    m_toolBar2->setButton( 2, KpdfSettings::groupByAuthor() );
70 71 72 73 74 75
    // - add separator
    m_toolBar2->insertLineSeparator();
    // - add Current Page Only button
    m_toolBar2->insertButton( "1downarrow", 3, SIGNAL( toggled( bool ) ),
        this, SLOT( slotCurrentPageOnly( bool ) ), true, i18n( "Show reviews for current page only" ) );
    m_toolBar2->setToggle( 3 );
76
    m_toolBar2->setButton( 3, KpdfSettings::currentPageOnly() );*/
77 78 79 80 81

    // customize listview appearance
    m_listView->addColumn( i18n("Annotation") );
    m_listView->header()->hide();
    m_listView->setTreeStepSize( 16 );
Pino Toscano's avatar
porting  
Pino Toscano committed
82
    m_listView->setResizeMode( K3ListView::AllColumns );
83 84 85
}

//BEGIN DocumentObserver Notifies -> requestListViewUpdate
86
void Reviews::notifySetup( const QVector< KPDFPage * > & pages, bool documentChanged )
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
{
    // 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;
Piotr Szymanski's avatar
Piotr Szymanski committed
107
        if ( KpdfSettings::currentPageOnly() )
108 109 110 111 112 113 114 115 116 117
            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
Piotr Szymanski's avatar
Piotr Szymanski committed
118
        if ( KpdfSettings::currentPageOnly() && pageNumber != m_currentPage )
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
            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
Piotr Szymanski's avatar
Piotr Szymanski committed
135
    KpdfSettings::setGroupByPage( on );
136 137 138 139 140 141
    requestListViewUpdate();
}

void Reviews::slotAuthorEnabled( bool on )
{
    // store toggle state in Settings and update the listview
Piotr Szymanski's avatar
Piotr Szymanski committed
142
    KpdfSettings::setGroupByAuthor( on );
143 144 145 146 147 148
    requestListViewUpdate();
}

void Reviews::slotCurrentPageOnly( bool on )
{
    // store toggle state in Settings and update the listview
Piotr Szymanski's avatar
Piotr Szymanski committed
149
    KpdfSettings::setCurrentPageOnly( on );
150 151 152 153 154
    requestListViewUpdate();
}
//END GUI Slots


155
class ReviewItem : public Q3ListViewItem
156 157
{
    public:
158 159
        ReviewItem( Q3ListView * parent, const QString & text )
            : Q3ListViewItem( parent, text ) {}
160 161 162 163 164

        void paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int align )
        {
            QColorGroup myCg = cg;
            myCg.setColor( QColorGroup::Text, Qt::red );
165
            Q3ListViewItem::paintCell( p, myCg, column, width, align );
166 167 168 169 170 171 172 173 174 175 176
        }
        void paintFocus( QPainter *, const QColorGroup &, const QRect & )
        {
        }
};

void Reviews::slotUpdateListView()
{
    // reset listview to default
    m_listView->clear();
    m_listView->setRootIsDecorated( true );
177
    m_listView->setSelectionMode( Q3ListView::Single );
178

Piotr Szymanski's avatar
Piotr Szymanski committed
179
    if ( KpdfSettings::currentPageOnly() )
180 181 182 183 184 185 186 187 188 189 190 191
    {
        // 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
192
        QVector< KPDFPage * >::iterator it = m_pages.begin(), end = m_pages.end();
193 194 195 196 197 198 199 200 201 202 203 204
        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 );
205
        m_listView->setSelectionMode( Q3ListView::NoSelection );
206 207 208 209 210 211 212
        new ReviewItem( m_listView, i18n("<No Items>") );
    }
}

void Reviews::addContents( const KPDFPage * page )
{
    // if page-grouping -> create Page subnode
213
    Q3ListViewItem * pageItem = 0;
Piotr Szymanski's avatar
Piotr Szymanski committed
214
    if ( KpdfSettings::groupByPage() )
215 216
    {
        QString pageText = i18n( "page %1" ).arg( page->number() + 1 );
217
        pageItem = new Q3ListViewItem( m_listView, pageText );
218
        pageItem->setPixmap( 0, SmallIcon( "txt" ) );
Piotr Szymanski's avatar
Piotr Szymanski committed
219
        pageItem->setOpen( KpdfSettings::groupByAuthor() );
220 221 222
    }

    // iterate over all annotations in this page
223 224
    const QLinkedList< Annotation * > & annots = page->getAnnotations();
    QLinkedList< Annotation * >::const_iterator aIt = annots.begin(), aEnd = annots.end();
225 226 227 228 229 230
    for ( ; aIt != aEnd; ++aIt )
    {
        // get annotation
        Annotation * annotation = *aIt;

        // if page-grouping -> create Author subnode
231
        Q3ListViewItem * authorItem = pageItem;
Piotr Szymanski's avatar
Piotr Szymanski committed
232
        if ( KpdfSettings::groupByAuthor() )
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
        {
            // 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 )
248
                    authorItem = new Q3ListViewItem( pageItem, author );
249
                else
250
                    authorItem = new Q3ListViewItem( m_listView, author );
251 252 253 254 255 256
                QString icon = author != i18n( "Unknown" ) ? "personal" : "presence_away";
                authorItem->setPixmap( 0, SmallIcon( icon ) );
            }
        }

        // create Annotation subnode
257 258 259
        Q3ListViewItem * singleItem = authorItem ?
            new Q3ListViewItem( authorItem, annotation->contents ) :
            new Q3ListViewItem( m_listView, annotation->contents );
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
        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"