compile
[kdegraphics.git] / okular / ui / tocmodel.cpp
blobf6eb429d8665d9523780d4a37071da9217d2a57c
1 /***************************************************************************
2 * Copyright (C) 2007 by Pino Toscano <pino@kde.org> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 ***************************************************************************/
10 #include "tocmodel.h"
12 #include <qapplication.h>
13 #include <qdom.h>
14 #include <qlist.h>
16 #include <kicon.h>
18 #include "pageitemdelegate.h"
19 #include "core/document.h"
20 #include "core/page.h"
22 Q_DECLARE_METATYPE( QModelIndex )
24 struct TOCItem
26 TOCItem();
27 TOCItem( TOCItem *parent, const QDomElement &e );
28 ~TOCItem();
30 QString text;
31 Okular::DocumentViewport viewport;
32 QString extFileName;
33 bool highlight : 1;
34 TOCItem *parent;
35 QList< TOCItem* > children;
36 TOCModelPrivate *model;
40 class TOCModelPrivate
42 public:
43 TOCModelPrivate( TOCModel *qq );
44 ~TOCModelPrivate();
46 void addChildren( const QDomNode &parentNode, TOCItem * parentItem );
47 QModelIndex indexForItem( TOCItem *item ) const;
48 void findViewport( const Okular::DocumentViewport &viewport, TOCItem *item, QList< TOCItem* > &list ) const;
50 TOCModel *q;
51 TOCItem *root;
52 bool dirty : 1;
53 Okular::Document *document;
54 QList< TOCItem* > itemsToOpen;
55 QList< TOCItem* > currentPage;
59 TOCItem::TOCItem()
60 : highlight( false ), parent( 0 ), model( 0 )
64 TOCItem::TOCItem( TOCItem *_parent, const QDomElement &e )
65 : highlight( false ), parent( _parent )
67 parent->children.append( this );
68 model = parent->model;
69 text = e.tagName();
71 // viewport loading
72 if ( e.hasAttribute( "Viewport" ) )
74 // if the node has a viewport, set it
75 viewport = Okular::DocumentViewport( e.attribute( "Viewport" ) );
77 else if ( e.hasAttribute( "ViewportName" ) )
79 // if the node references a viewport, get the reference and set it
80 const QString & page = e.attribute( "ViewportName" );
81 QString viewport_string = model->document->metaData( "NamedViewport", page ).toString();
82 if ( !viewport_string.isEmpty() )
83 viewport = Okular::DocumentViewport( viewport_string );
86 extFileName = e.attribute( "ExternalFileName" );
89 TOCItem::~TOCItem()
91 qDeleteAll( children );
95 TOCModelPrivate::TOCModelPrivate( TOCModel *qq )
96 : q( qq ), root( new TOCItem ), dirty( false )
98 root->model = this;
101 TOCModelPrivate::~TOCModelPrivate()
103 delete root;
106 void TOCModelPrivate::addChildren( const QDomNode & parentNode, TOCItem * parentItem )
108 TOCItem * currentItem = 0;
109 QDomNode n = parentNode.firstChild();
110 while( !n.isNull() )
112 // convert the node to an element (sure it is)
113 QDomElement e = n.toElement();
115 // insert the entry as top level (listview parented) or 2nd+ level
116 currentItem = new TOCItem( parentItem, e );
118 // descend recursively and advance to the next node
119 if ( e.hasChildNodes() )
120 addChildren( n, currentItem );
122 // open/keep close the item
123 bool isOpen = false;
124 if ( e.hasAttribute( "Open" ) )
125 isOpen = QVariant( e.attribute( "Open" ) ).toBool();
126 if ( isOpen )
127 itemsToOpen.append( currentItem );
129 n = n.nextSibling();
133 QModelIndex TOCModelPrivate::indexForItem( TOCItem *item ) const
135 if ( item->parent )
137 int id = item->parent->children.indexOf( item );
138 if ( id >= 0 && id < item->parent->children.count() )
139 return q->createIndex( id, 0, item );
141 return QModelIndex();
144 void TOCModelPrivate::findViewport( const Okular::DocumentViewport &viewport, TOCItem *item, QList< TOCItem* > &list ) const
146 if ( item->viewport.isValid() && item->viewport.pageNumber == viewport.pageNumber )
147 list.append( item );
149 foreach ( TOCItem *child, item->children )
150 findViewport( viewport, child, list );
154 TOCModel::TOCModel( Okular::Document *document, QObject *parent )
155 : QAbstractItemModel( parent ), d( new TOCModelPrivate( this ) )
157 d->document = document;
159 qRegisterMetaType< QModelIndex >();
162 TOCModel::~TOCModel()
164 delete d;
167 int TOCModel::columnCount( const QModelIndex &parent ) const
169 Q_UNUSED( parent )
170 return 1;
173 QVariant TOCModel::data( const QModelIndex &index, int role ) const
175 if ( !index.isValid() )
176 return QVariant();
178 TOCItem *item = static_cast< TOCItem* >( index.internalPointer() );
179 switch ( role )
181 case Qt::DisplayRole:
182 case Qt::ToolTipRole:
183 return item->text;
184 break;
185 case Qt::DecorationRole:
186 if ( item->highlight )
187 return KIcon( QApplication::layoutDirection() == Qt::RightToLeft ? "arrow-left" : "arrow-right" );
188 break;
189 case PageItemDelegate::PageRole:
190 if ( item->viewport.isValid() )
191 return item->viewport.pageNumber + 1;
192 break;
193 case PageItemDelegate::PageLabelRole:
194 if ( item->viewport.isValid() )
195 return d->document->page( item->viewport.pageNumber )->label();
196 break;
198 return QVariant();
201 bool TOCModel::hasChildren( const QModelIndex &parent ) const
203 if ( !parent.isValid() )
204 return true;
206 TOCItem *item = static_cast< TOCItem* >( parent.internalPointer() );
207 return !item->children.isEmpty();
210 QVariant TOCModel::headerData( int section, Qt::Orientation orientation, int role ) const
212 if ( orientation != Qt::Horizontal )
213 return QVariant();
215 if ( section == 0 && role == Qt::DisplayRole )
216 return "Topics";
218 return QVariant();
221 QModelIndex TOCModel::index( int row, int column, const QModelIndex &parent ) const
223 if ( row < 0 || column != 0 )
224 return QModelIndex();
226 TOCItem *item = parent.isValid() ? static_cast< TOCItem* >( parent.internalPointer() ) : d->root;
227 if ( row < item->children.count() )
228 return createIndex( row, column, item->children.at( row ) );
230 return QModelIndex();
233 QModelIndex TOCModel::parent( const QModelIndex &index ) const
235 if ( !index.isValid() )
236 return QModelIndex();
238 TOCItem *item = static_cast< TOCItem* >( index.internalPointer() );
239 return d->indexForItem( item->parent );
242 int TOCModel::rowCount( const QModelIndex &parent ) const
244 TOCItem *item = parent.isValid() ? static_cast< TOCItem* >( parent.internalPointer() ) : d->root;
245 return item->children.count();
248 void TOCModel::fill( const Okular::DocumentSynopsis *toc )
250 if ( !toc )
251 return;
253 clear();
254 emit layoutAboutToBeChanged();
255 d->addChildren( *toc, d->root );
256 d->dirty = true;
257 emit layoutChanged();
258 foreach ( TOCItem *item, d->itemsToOpen )
260 QModelIndex index = d->indexForItem( item );
261 if ( !index.isValid() )
262 continue;
264 QMetaObject::invokeMethod( QObject::parent(), "expand", Qt::QueuedConnection, Q_ARG( QModelIndex, index ) );
266 d->itemsToOpen.clear();
269 void TOCModel::clear()
271 if ( !d->dirty )
272 return;
274 qDeleteAll( d->root->children );
275 d->root->children.clear();
276 d->currentPage.clear();
277 reset();
278 d->dirty = false;
281 void TOCModel::setCurrentViewport( const Okular::DocumentViewport &viewport )
283 foreach ( TOCItem* item, d->currentPage )
285 QModelIndex index = d->indexForItem( item );
286 if ( !index.isValid() )
287 continue;
289 item->highlight = false;
290 emit dataChanged( index, index );
292 d->currentPage.clear();
294 QList< TOCItem* > newCurrentPage;
295 d->findViewport( viewport, d->root, newCurrentPage );
296 // HACK: for now, support only the first item found
297 if ( newCurrentPage.count() > 0 )
299 TOCItem *first = newCurrentPage.first();
300 newCurrentPage.clear();
301 newCurrentPage.append( first );
304 d->currentPage = newCurrentPage;
306 foreach ( TOCItem* item, d->currentPage )
308 QModelIndex index = d->indexForItem( item );
309 if ( !index.isValid() )
310 continue;
312 item->highlight = true;
313 emit dataChanged( index, index );
317 bool TOCModel::isEmpty() const
319 return d->root->children.isEmpty();
322 QString TOCModel::externalFileNameForIndex( const QModelIndex &index ) const
324 if ( !index.isValid() )
325 return QString();
327 TOCItem *item = static_cast< TOCItem* >( index.internalPointer() );
328 return item->extFileName;
331 Okular::DocumentViewport TOCModel::viewportForIndex( const QModelIndex &index ) const
333 if ( !index.isValid() )
334 return Okular::DocumentViewport();
336 TOCItem *item = static_cast< TOCItem* >( index.internalPointer() );
337 return item->viewport;
340 #include "tocmodel.moc"