1 /***************************************************************************
2 * Copyright (C) 2007 by Pino Toscano <pino@kde.org> *
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 ***************************************************************************/
12 #include <qapplication.h>
18 #include "pageitemdelegate.h"
19 #include "core/document.h"
20 #include "core/page.h"
22 Q_DECLARE_METATYPE( QModelIndex
)
27 TOCItem( TOCItem
*parent
, const QDomElement
&e
);
31 Okular::DocumentViewport viewport
;
35 QList
< TOCItem
* > children
;
36 TOCModelPrivate
*model
;
43 TOCModelPrivate( TOCModel
*qq
);
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;
53 Okular::Document
*document
;
54 QList
< TOCItem
* > itemsToOpen
;
55 QList
< TOCItem
* > currentPage
;
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
;
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" );
91 qDeleteAll( children
);
95 TOCModelPrivate::TOCModelPrivate( TOCModel
*qq
)
96 : q( qq
), root( new TOCItem
), dirty( false )
101 TOCModelPrivate::~TOCModelPrivate()
106 void TOCModelPrivate::addChildren( const QDomNode
& parentNode
, TOCItem
* parentItem
)
108 TOCItem
* currentItem
= 0;
109 QDomNode n
= parentNode
.firstChild();
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
124 if ( e
.hasAttribute( "Open" ) )
125 isOpen
= QVariant( e
.attribute( "Open" ) ).toBool();
127 itemsToOpen
.append( currentItem
);
133 QModelIndex
TOCModelPrivate::indexForItem( TOCItem
*item
) const
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
)
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()
167 int TOCModel::columnCount( const QModelIndex
&parent
) const
173 QVariant
TOCModel::data( const QModelIndex
&index
, int role
) const
175 if ( !index
.isValid() )
178 TOCItem
*item
= static_cast< TOCItem
* >( index
.internalPointer() );
181 case Qt::DisplayRole
:
182 case Qt::ToolTipRole
:
185 case Qt::DecorationRole
:
186 if ( item
->highlight
)
187 return KIcon( QApplication::layoutDirection() == Qt::RightToLeft
? "arrow-left" : "arrow-right" );
189 case PageItemDelegate::PageRole
:
190 if ( item
->viewport
.isValid() )
191 return item
->viewport
.pageNumber
+ 1;
193 case PageItemDelegate::PageLabelRole
:
194 if ( item
->viewport
.isValid() )
195 return d
->document
->page( item
->viewport
.pageNumber
)->label();
201 bool TOCModel::hasChildren( const QModelIndex
&parent
) const
203 if ( !parent
.isValid() )
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
)
215 if ( section
== 0 && role
== Qt::DisplayRole
)
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
)
254 emit
layoutAboutToBeChanged();
255 d
->addChildren( *toc
, d
->root
);
257 emit
layoutChanged();
258 foreach ( TOCItem
*item
, d
->itemsToOpen
)
260 QModelIndex index
= d
->indexForItem( item
);
261 if ( !index
.isValid() )
264 QMetaObject::invokeMethod( QObject::parent(), "expand", Qt::QueuedConnection
, Q_ARG( QModelIndex
, index
) );
266 d
->itemsToOpen
.clear();
269 void TOCModel::clear()
274 qDeleteAll( d
->root
->children
);
275 d
->root
->children
.clear();
276 d
->currentPage
.clear();
281 void TOCModel::setCurrentViewport( const Okular::DocumentViewport
&viewport
)
283 foreach ( TOCItem
* item
, d
->currentPage
)
285 QModelIndex index
= d
->indexForItem( item
);
286 if ( !index
.isValid() )
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() )
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() )
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"