parent
d11d5d8106
commit
9c000ce8b1
7 changed files with 533 additions and 0 deletions
@ -0,0 +1,35 @@ |
||||
/* |
||||
* Copyright 2011 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU Library General Public License as |
||||
* published by the Free Software Foundation; either version 2, 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 Library General Public License for more details |
||||
* |
||||
* You should have received a copy of the GNU Library General Public |
||||
* License along with this program; if not, write to the |
||||
* Free Software Foundation, Inc., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 1.1 |
||||
import org.kde.plasma.components 0.1 as PlasmaComponents |
||||
import org.kde.plasma.core 0.1 as PlasmaCore |
||||
|
||||
Column { |
||||
id: treeView |
||||
Repeater { |
||||
model: VisualDataModel { |
||||
id: tocModel |
||||
model: documentItem.tableOfContents |
||||
delegate: TreeDelegate { |
||||
sourceModel: tocModel |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,62 @@ |
||||
/* |
||||
* Copyright 2011 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU Library General Public License as |
||||
* published by the Free Software Foundation; either version 2, 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 Library General Public License for more details |
||||
* |
||||
* You should have received a copy of the GNU Library General Public |
||||
* License along with this program; if not, write to the |
||||
* Free Software Foundation, Inc., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 1.1 |
||||
import org.kde.plasma.components 0.1 as PlasmaComponents |
||||
import org.kde.plasma.core 0.1 as PlasmaCore |
||||
|
||||
|
||||
Column { |
||||
id: treeDelegate |
||||
property variant sourceModel |
||||
property int rowIndex: index |
||||
Row { |
||||
spacing: 30 |
||||
PlasmaComponents.Label { |
||||
id: label |
||||
text: display |
||||
} |
||||
PlasmaComponents.Label { |
||||
id: pageNumber |
||||
text: page |
||||
} |
||||
} |
||||
Column { |
||||
id: col |
||||
x: 20 |
||||
property variant model: childrenModel |
||||
Repeater { |
||||
id: rep |
||||
model: VisualDataModel { |
||||
id: childrenModel |
||||
model: documentItem.tableOfContents |
||||
} |
||||
} |
||||
} |
||||
onParentChanged: { |
||||
if (treeDelegate.parent && treeDelegate.parent.model) { |
||||
sourceModel = treeDelegate.parent.model |
||||
} |
||||
childrenModel.rootIndex = sourceModel.modelIndex(index) |
||||
|
||||
if (model.hasModelChildren) { |
||||
childrenModel.delegate = Qt.createComponent("TreeDelegate.qml") |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,355 @@ |
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Pino Toscano <pino@kde.org> * |
||||
* * |
||||
* 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. * |
||||
***************************************************************************/ |
||||
|
||||
#include "tocmodel.h" |
||||
|
||||
#include <qapplication.h> |
||||
#include <qdom.h> |
||||
#include <qlist.h> |
||||
|
||||
#include <kicon.h> |
||||
|
||||
#include "core/document.h" |
||||
#include "core/page.h" |
||||
|
||||
Q_DECLARE_METATYPE( QModelIndex ) |
||||
|
||||
struct TOCItem |
||||
{ |
||||
TOCItem(); |
||||
TOCItem( TOCItem *parent, const QDomElement &e ); |
||||
~TOCItem(); |
||||
|
||||
QString text; |
||||
Okular::DocumentViewport viewport; |
||||
QString extFileName; |
||||
QString url; |
||||
bool highlight : 1; |
||||
TOCItem *parent; |
||||
QList< TOCItem* > children; |
||||
TOCModelPrivate *model; |
||||
}; |
||||
|
||||
|
||||
class TOCModelPrivate |
||||
{ |
||||
public: |
||||
TOCModelPrivate( TOCModel *qq ); |
||||
~TOCModelPrivate(); |
||||
|
||||
void addChildren( const QDomNode &parentNode, TOCItem * parentItem ); |
||||
QModelIndex indexForItem( TOCItem *item ) const; |
||||
void findViewport( const Okular::DocumentViewport &viewport, TOCItem *item, QList< TOCItem* > &list ) const; |
||||
|
||||
TOCModel *q; |
||||
TOCItem *root; |
||||
bool dirty : 1; |
||||
Okular::Document *document; |
||||
QList< TOCItem* > itemsToOpen; |
||||
QList< TOCItem* > currentPage; |
||||
}; |
||||
|
||||
|
||||
TOCItem::TOCItem() |
||||
: highlight( false ), parent( 0 ), model( 0 ) |
||||
{ |
||||
} |
||||
|
||||
TOCItem::TOCItem( TOCItem *_parent, const QDomElement &e ) |
||||
: highlight( false ), parent( _parent ) |
||||
{ |
||||
parent->children.append( this ); |
||||
model = parent->model; |
||||
text = e.tagName(); |
||||
|
||||
// viewport loading
|
||||
if ( e.hasAttribute( "Viewport" ) ) |
||||
{ |
||||
// if the node has a viewport, set it
|
||||
viewport = Okular::DocumentViewport( e.attribute( "Viewport" ) ); |
||||
} |
||||
else if ( e.hasAttribute( "ViewportName" ) ) |
||||
{ |
||||
// if the node references a viewport, get the reference and set it
|
||||
const QString & page = e.attribute( "ViewportName" ); |
||||
QString viewport_string = model->document->metaData( "NamedViewport", page ).toString(); |
||||
if ( !viewport_string.isEmpty() ) |
||||
viewport = Okular::DocumentViewport( viewport_string ); |
||||
} |
||||
|
||||
extFileName = e.attribute( "ExternalFileName" ); |
||||
url = e.attribute( "URL" ); |
||||
} |
||||
|
||||
TOCItem::~TOCItem() |
||||
{ |
||||
qDeleteAll( children ); |
||||
} |
||||
|
||||
|
||||
TOCModelPrivate::TOCModelPrivate( TOCModel *qq ) |
||||
: q( qq ), root( new TOCItem ), dirty( false ) |
||||
{ |
||||
root->model = this; |
||||
} |
||||
|
||||
TOCModelPrivate::~TOCModelPrivate() |
||||
{ |
||||
delete root; |
||||
} |
||||
|
||||
void TOCModelPrivate::addChildren( const QDomNode & parentNode, TOCItem * parentItem ) |
||||
{ |
||||
TOCItem * currentItem = 0; |
||||
QDomNode n = parentNode.firstChild(); |
||||
while( !n.isNull() ) |
||||
{ |
||||
// convert the node to an element (sure it is)
|
||||
QDomElement e = n.toElement(); |
||||
|
||||
// insert the entry as top level (listview parented) or 2nd+ level
|
||||
currentItem = new TOCItem( parentItem, e ); |
||||
|
||||
// descend recursively and advance to the next node
|
||||
if ( e.hasChildNodes() ) |
||||
addChildren( n, currentItem ); |
||||
|
||||
// open/keep close the item
|
||||
bool isOpen = false; |
||||
if ( e.hasAttribute( "Open" ) ) |
||||
isOpen = QVariant( e.attribute( "Open" ) ).toBool(); |
||||
if ( isOpen ) |
||||
itemsToOpen.append( currentItem ); |
||||
|
||||
n = n.nextSibling(); |
||||
} |
||||
} |
||||
|
||||
QModelIndex TOCModelPrivate::indexForItem( TOCItem *item ) const |
||||
{ |
||||
if ( item->parent ) |
||||
{ |
||||
int id = item->parent->children.indexOf( item ); |
||||
if ( id >= 0 && id < item->parent->children.count() ) |
||||
return q->createIndex( id, 0, item ); |
||||
} |
||||
return QModelIndex(); |
||||
} |
||||
|
||||
void TOCModelPrivate::findViewport( const Okular::DocumentViewport &viewport, TOCItem *item, QList< TOCItem* > &list ) const |
||||
{ |
||||
if ( item->viewport.isValid() && item->viewport.pageNumber == viewport.pageNumber ) |
||||
list.append( item ); |
||||
|
||||
foreach ( TOCItem *child, item->children ) |
||||
findViewport( viewport, child, list ); |
||||
} |
||||
|
||||
|
||||
TOCModel::TOCModel( Okular::Document *document, QObject *parent ) |
||||
: QAbstractItemModel( parent ), d( new TOCModelPrivate( this ) ) |
||||
{ |
||||
d->document = document; |
||||
|
||||
qRegisterMetaType< QModelIndex >(); |
||||
|
||||
QHash<int, QByteArray> roles = roleNames(); |
||||
roles.insert(PageRole, "page"); |
||||
roles.insert(PageLabelRole, "pageLabel"); |
||||
setRoleNames(roles); |
||||
} |
||||
|
||||
TOCModel::~TOCModel() |
||||
{ |
||||
delete d; |
||||
} |
||||
|
||||
int TOCModel::columnCount( const QModelIndex &parent ) const |
||||
{ |
||||
Q_UNUSED( parent ) |
||||
return 1; |
||||
} |
||||
|
||||
QVariant TOCModel::data( const QModelIndex &index, int role ) const |
||||
{ |
||||
if ( !index.isValid() ) |
||||
return QVariant(); |
||||
|
||||
TOCItem *item = static_cast< TOCItem* >( index.internalPointer() ); |
||||
switch ( role ) |
||||
{ |
||||
case Qt::DisplayRole: |
||||
case Qt::ToolTipRole: |
||||
return item->text; |
||||
break; |
||||
case Qt::DecorationRole: |
||||
if ( item->highlight ) |
||||
return KIcon( QApplication::layoutDirection() == Qt::RightToLeft ? "arrow-left" : "arrow-right" ); |
||||
break; |
||||
case PageRole: |
||||
if ( item->viewport.isValid() ) |
||||
return item->viewport.pageNumber + 1; |
||||
break; |
||||
case PageLabelRole: |
||||
if ( item->viewport.isValid() && item->viewport.pageNumber < int(d->document->pages()) ) |
||||
return d->document->page( item->viewport.pageNumber )->label(); |
||||
break; |
||||
} |
||||
return QVariant(); |
||||
} |
||||
|
||||
bool TOCModel::hasChildren( const QModelIndex &parent ) const |
||||
{ |
||||
if ( !parent.isValid() ) |
||||
return true; |
||||
|
||||
TOCItem *item = static_cast< TOCItem* >( parent.internalPointer() ); |
||||
return !item->children.isEmpty(); |
||||
} |
||||
|
||||
QVariant TOCModel::headerData( int section, Qt::Orientation orientation, int role ) const |
||||
{ |
||||
if ( orientation != Qt::Horizontal ) |
||||
return QVariant(); |
||||
|
||||
if ( section == 0 && role == Qt::DisplayRole ) |
||||
return "Topics"; |
||||
|
||||
return QVariant(); |
||||
} |
||||
|
||||
QModelIndex TOCModel::index( int row, int column, const QModelIndex &parent ) const |
||||
{ |
||||
if ( row < 0 || column != 0 ) |
||||
return QModelIndex(); |
||||
|
||||
TOCItem *item = parent.isValid() ? static_cast< TOCItem* >( parent.internalPointer() ) : d->root; |
||||
if ( row < item->children.count() ) |
||||
return createIndex( row, column, item->children.at( row ) ); |
||||
|
||||
return QModelIndex(); |
||||
} |
||||
|
||||
QModelIndex TOCModel::parent( const QModelIndex &index ) const |
||||
{ |
||||
if ( !index.isValid() ) |
||||
return QModelIndex(); |
||||
|
||||
TOCItem *item = static_cast< TOCItem* >( index.internalPointer() ); |
||||
return d->indexForItem( item->parent ); |
||||
} |
||||
|
||||
int TOCModel::rowCount( const QModelIndex &parent ) const |
||||
{ |
||||
TOCItem *item = parent.isValid() ? static_cast< TOCItem* >( parent.internalPointer() ) : d->root; |
||||
return item->children.count(); |
||||
} |
||||
|
||||
void TOCModel::fill( const Okular::DocumentSynopsis *toc ) |
||||
{ |
||||
if ( !toc ) |
||||
return; |
||||
|
||||
clear(); |
||||
emit layoutAboutToBeChanged(); |
||||
d->addChildren( *toc, d->root ); |
||||
d->dirty = true; |
||||
emit layoutChanged(); |
||||
foreach ( TOCItem *item, d->itemsToOpen ) |
||||
{ |
||||
QModelIndex index = d->indexForItem( item ); |
||||
if ( !index.isValid() ) |
||||
continue; |
||||
|
||||
QMetaObject::invokeMethod( QObject::parent(), "expand", Qt::QueuedConnection, Q_ARG( QModelIndex, index ) ); |
||||
} |
||||
d->itemsToOpen.clear(); |
||||
} |
||||
|
||||
void TOCModel::clear() |
||||
{ |
||||
if ( !d->dirty ) |
||||
return; |
||||
|
||||
qDeleteAll( d->root->children ); |
||||
d->root->children.clear(); |
||||
d->currentPage.clear(); |
||||
reset(); |
||||
d->dirty = false; |
||||
} |
||||
|
||||
void TOCModel::setCurrentViewport( const Okular::DocumentViewport &viewport ) |
||||
{ |
||||
foreach ( TOCItem* item, d->currentPage ) |
||||
{ |
||||
QModelIndex index = d->indexForItem( item ); |
||||
if ( !index.isValid() ) |
||||
continue; |
||||
|
||||
item->highlight = false; |
||||
emit dataChanged( index, index ); |
||||
} |
||||
d->currentPage.clear(); |
||||
|
||||
QList< TOCItem* > newCurrentPage; |
||||
d->findViewport( viewport, d->root, newCurrentPage ); |
||||
// HACK: for now, support only the first item found
|
||||
if ( newCurrentPage.count() > 0 ) |
||||
{ |
||||
TOCItem *first = newCurrentPage.first(); |
||||
newCurrentPage.clear(); |
||||
newCurrentPage.append( first ); |
||||
} |
||||
|
||||
d->currentPage = newCurrentPage; |
||||
|
||||
foreach ( TOCItem* item, d->currentPage ) |
||||
{ |
||||
QModelIndex index = d->indexForItem( item ); |
||||
if ( !index.isValid() ) |
||||
continue; |
||||
|
||||
item->highlight = true; |
||||
emit dataChanged( index, index ); |
||||
} |
||||
} |
||||
|
||||
bool TOCModel::isEmpty() const |
||||
{ |
||||
return d->root->children.isEmpty(); |
||||
} |
||||
|
||||
QString TOCModel::externalFileNameForIndex( const QModelIndex &index ) const |
||||
{ |
||||
if ( !index.isValid() ) |
||||
return QString(); |
||||
|
||||
TOCItem *item = static_cast< TOCItem* >( index.internalPointer() ); |
||||
return item->extFileName; |
||||
} |
||||
|
||||
Okular::DocumentViewport TOCModel::viewportForIndex( const QModelIndex &index ) const |
||||
{ |
||||
if ( !index.isValid() ) |
||||
return Okular::DocumentViewport(); |
||||
|
||||
TOCItem *item = static_cast< TOCItem* >( index.internalPointer() ); |
||||
return item->viewport; |
||||
} |
||||
|
||||
QString TOCModel::urlForIndex( const QModelIndex &index ) const |
||||
{ |
||||
if ( !index.isValid() ) |
||||
return QString(); |
||||
|
||||
TOCItem *item = static_cast< TOCItem* >( index.internalPointer() ); |
||||
return item->url; |
||||
} |
||||
|
||||
#include "tocmodel.moc" |
||||
@ -0,0 +1,61 @@ |
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Pino Toscano <pino@kde.org> * |
||||
* * |
||||
* 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. * |
||||
***************************************************************************/ |
||||
|
||||
#ifndef TOCMODEL_H |
||||
#define TOCMODEL_H |
||||
|
||||
#include <qabstractitemmodel.h> |
||||
|
||||
namespace Okular { |
||||
class Document; |
||||
class DocumentSynopsis; |
||||
class DocumentViewport; |
||||
} |
||||
|
||||
class TOCModelPrivate; |
||||
|
||||
class TOCModel : public QAbstractItemModel |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
enum TOCRoles { |
||||
PageRole = Qt::UserRole + 1, |
||||
PageLabelRole = Qt::UserRole + 2 |
||||
}; |
||||
|
||||
explicit TOCModel( Okular::Document *document, QObject *parent = 0 ); |
||||
virtual ~TOCModel(); |
||||
|
||||
// reimplementations from QAbstractItemModel
|
||||
virtual int columnCount( const QModelIndex &parent = QModelIndex() ) const; |
||||
virtual QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const; |
||||
virtual bool hasChildren( const QModelIndex &parent = QModelIndex() ) const; |
||||
virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; |
||||
virtual QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const; |
||||
virtual QModelIndex parent( const QModelIndex &index ) const; |
||||
virtual int rowCount( const QModelIndex &parent = QModelIndex() ) const; |
||||
|
||||
void fill( const Okular::DocumentSynopsis *toc ); |
||||
void clear(); |
||||
void setCurrentViewport( const Okular::DocumentViewport &viewport ); |
||||
|
||||
bool isEmpty() const; |
||||
|
||||
QString externalFileNameForIndex( const QModelIndex &index ) const; |
||||
Okular::DocumentViewport viewportForIndex( const QModelIndex &index ) const; |
||||
QString urlForIndex( const QModelIndex &index ) const; |
||||
|
||||
private: |
||||
// storage
|
||||
friend class TOCModelPrivate; |
||||
TOCModelPrivate *const d; |
||||
}; |
||||
|
||||
#endif |
||||
Loading…
Reference in new issue