1
/* poppler-optcontent.cc: qt interface to poppler
3
* Copyright (C) 2007, Brad Hards <bradh@kde.org>
4
* Copyright (C) 2008, Pino Toscano <pino@kde.org>
5
* Copyright (C) 2008, Carlos Garcia Campos <carlosgc@gnome.org>
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2, or (at your option)
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
22
#include "poppler-optcontent.h"
24
#include "poppler-optcontent-private.h"
26
#include "poppler-private.h"
28
#include <QtCore/QDebug>
29
#include <QtCore/QtAlgorithms>
31
#include "poppler/OptionalContent.h"
36
RadioButtonGroup::RadioButtonGroup( OptContentModelPrivate *ocModel, Array *rbarray )
38
for (int i = 0; i < rbarray->getLength(); ++i) {
40
rbarray->getNF( i, &ref );
41
if ( ! ref.isRef() ) {
42
qDebug() << "expected ref, but got:" << ref.getType();
44
OptContentItem *item = ocModel->itemFromRef( QString::number(ref.getRefNum() ) );
45
itemsInGroup.append( item );
47
for (int i = 0; i < itemsInGroup.size(); ++i) {
48
OptContentItem *item = itemsInGroup.at(i);
49
item->appendRBGroup( this );
53
RadioButtonGroup::~RadioButtonGroup()
57
QSet<OptContentItem *> RadioButtonGroup::setItemOn( OptContentItem *itemToSetOn )
59
QSet<OptContentItem *> changedItems;
60
for (int i = 0; i < itemsInGroup.size(); ++i) {
61
OptContentItem *thisItem = itemsInGroup.at(i);
62
if (thisItem != itemToSetOn) {
63
QSet<OptContentItem *> newChangedItems;
64
thisItem->setState(OptContentItem::Off, newChangedItems);
65
changedItems += newChangedItems;
73
OptContentItem::OptContentItem( OptionalContentGroup *group )
77
m_name = UnicodeParsedString( group->getName() );
78
if ( group->getState() == OptionalContentGroup::On ) {
79
m_state = OptContentItem::On;
81
m_state = OptContentItem::Off;
83
m_stateBackup = m_state;
87
OptContentItem::OptContentItem( const QString &label )
92
m_state = OptContentItem::HeadingOnly;
93
m_stateBackup = m_state;
97
OptContentItem::OptContentItem() :
98
m_parent( 0 ), m_enabled(true)
102
OptContentItem::~OptContentItem()
106
void OptContentItem::appendRBGroup( RadioButtonGroup *rbgroup )
108
m_rbGroups.append( rbgroup );
112
bool OptContentItem::setState(ItemState state, QSet<OptContentItem *> &changedItems)
115
m_stateBackup = m_state;
116
changedItems.insert(this);
117
QSet<OptContentItem *> empty;
118
Q_FOREACH (OptContentItem *child, m_children) {
119
ItemState oldState = child->m_stateBackup;
120
child->setState(state == OptContentItem::On ? child->m_stateBackup : OptContentItem::Off, empty);
121
child->m_enabled = state == OptContentItem::On;
122
child->m_stateBackup = oldState;
127
if ( state == OptContentItem::On ) {
128
m_group->setState( OptionalContentGroup::On );
129
for (int i = 0; i < m_rbGroups.size(); ++i) {
130
RadioButtonGroup *rbgroup = m_rbGroups.at(i);
131
changedItems += rbgroup->setItemOn( this );
133
} else if ( state == OptContentItem::Off ) {
134
m_group->setState( OptionalContentGroup::Off );
139
void OptContentItem::addChild( OptContentItem *child )
142
child->setParent( this );
145
QSet<OptContentItem*> OptContentItem::recurseListChildren(bool includeMe) const
147
QSet<OptContentItem*> ret;
149
ret.insert(const_cast<OptContentItem*>(this));
151
Q_FOREACH (OptContentItem *child, m_children) {
152
ret += child->recurseListChildren(true);
157
OptContentModelPrivate::OptContentModelPrivate( OptContentModel *qq, OCGs *optContent )
160
m_rootNode = new OptContentItem();
161
GooList *ocgs = optContent->getOCGs();
163
for (int i = 0; i < ocgs->getLength(); ++i) {
164
OptionalContentGroup *ocg = static_cast<OptionalContentGroup*>(ocgs->get(i));
165
OptContentItem *node = new OptContentItem( ocg );
166
m_optContentItems.insert( QString::number(ocg->getRef().num), node);
169
if ( optContent->getOrderArray() == 0 ) {
170
// no Order array, so drop them all at the top level
171
QMapIterator<QString, OptContentItem*> i(m_optContentItems);
172
while ( i.hasNext() ) {
174
qDebug() << "iterator" << i.key() << ":" << i.value();
175
addChild( i.value(), m_rootNode );
178
parseOrderArray( m_rootNode, optContent->getOrderArray() );
181
parseRBGroupsArray( optContent->getRBGroupsArray() );
184
OptContentModelPrivate::~OptContentModelPrivate()
186
qDeleteAll( m_optContentItems );
187
qDeleteAll( m_rbgroups );
191
void OptContentModelPrivate::parseOrderArray( OptContentItem *parentNode, Array *orderArray )
193
OptContentItem *lastItem = parentNode;
194
for (int i = 0; i < orderArray->getLength(); ++i) {
196
orderArray->get(i, &orderItem);
197
if ( orderItem.isDict() ) {
199
orderArray->getNF(i, &item);
201
OptContentItem *ocItem = m_optContentItems.value(QString::number(item.getRefNum()), 0);
203
addChild( parentNode, ocItem );
206
qDebug() << "could not find group for object" << item.getRefNum();
210
} else if ( (orderItem.isArray()) && (orderItem.arrayGetLength() > 0) ) {
211
parseOrderArray(lastItem, orderItem.getArray());
212
} else if ( orderItem.isString() ) {
213
GooString *label = orderItem.getString();
214
OptContentItem *header = new OptContentItem ( UnicodeParsedString ( label ) );
215
addChild( parentNode, header );
219
qDebug() << "something unexpected";
225
void OptContentModelPrivate::parseRBGroupsArray( Array *rBGroupArray )
227
if (! rBGroupArray) {
230
// This is an array of array(s)
231
for (int i = 0; i < rBGroupArray->getLength(); ++i) {
233
rBGroupArray->get(i, &rbObj);
234
if ( ! rbObj.isArray() ) {
235
qDebug() << "expected inner array, got:" << rbObj.getType();
238
Array *rbarray = rbObj.getArray();
239
RadioButtonGroup *rbg = new RadioButtonGroup( this, rbarray );
240
m_rbgroups.append( rbg );
245
OptContentModel::OptContentModel( OCGs *optContent, QObject *parent)
246
: QAbstractItemModel(parent)
248
d = new OptContentModelPrivate( this, optContent );
251
OptContentModel::~OptContentModel()
256
void OptContentModelPrivate::setRootNode(OptContentItem *node)
263
QModelIndex OptContentModel::index(int row, int column, const QModelIndex &parent) const
265
if (row < 0 || column != 0) {
266
return QModelIndex();
269
OptContentItem *parentNode = d->nodeFromIndex( parent );
270
if (row < parentNode->childList().count()) {
271
return createIndex(row, column, parentNode->childList().at(row));
273
return QModelIndex();
276
QModelIndex OptContentModel::parent(const QModelIndex &child) const
278
OptContentItem *childNode = d->nodeFromIndex( child );
280
return QModelIndex();
282
return d->indexFromItem(childNode->parent(), child.column());
285
QModelIndex OptContentModelPrivate::indexFromItem(OptContentItem *node, int column) const
288
return QModelIndex();
290
OptContentItem *parentNode = node->parent();
292
return QModelIndex();
294
const int row = parentNode->childList().indexOf(node);
295
return q->createIndex(row, column, node);
298
int OptContentModel::rowCount(const QModelIndex &parent) const
300
OptContentItem *parentNode = d->nodeFromIndex( parent );
304
return parentNode->childList().count();
308
int OptContentModel::columnCount(const QModelIndex &parent) const
314
QVariant OptContentModel::data(const QModelIndex &index, int role) const
316
OptContentItem *node = d->nodeFromIndex(index, true);
322
case Qt::DisplayRole:
326
if (node->state() == OptContentItem::On) {
328
} else if (node->state() == OptContentItem::Off) {
332
case Qt::CheckStateRole:
333
if (node->state() == OptContentItem::On) {
335
} else if (node->state() == OptContentItem::Off) {
336
return Qt::Unchecked;
344
bool OptContentModel::setData ( const QModelIndex & index, const QVariant & value, int role )
346
OptContentItem *node = d->nodeFromIndex(index, true);
352
case Qt::CheckStateRole:
354
const bool newvalue = value.toBool();
356
if (node->state() != OptContentItem::On) {
357
QSet<OptContentItem *> changedItems;
358
node->setState(OptContentItem::On, changedItems);
359
changedItems += node->recurseListChildren(false);
360
QModelIndexList indexes;
361
Q_FOREACH (OptContentItem *item, changedItems) {
362
indexes.append(d->indexFromItem(item, 0));
364
qStableSort(indexes);
365
Q_FOREACH (const QModelIndex &changedIndex, indexes) {
366
emit dataChanged(changedIndex, changedIndex);
371
if (node->state() != OptContentItem::Off) {
372
QSet<OptContentItem *> changedItems;
373
node->setState(OptContentItem::Off, changedItems);
374
changedItems += node->recurseListChildren(false);
375
QModelIndexList indexes;
376
Q_FOREACH (OptContentItem *item, changedItems) {
377
indexes.append(d->indexFromItem(item, 0));
379
qStableSort(indexes);
380
Q_FOREACH (const QModelIndex &changedIndex, indexes) {
381
emit dataChanged(changedIndex, changedIndex);
393
Qt::ItemFlags OptContentModel::flags ( const QModelIndex & index ) const
395
OptContentItem *node = d->nodeFromIndex(index);
396
Qt::ItemFlags itemFlags = Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
397
if (node->isEnabled()) {
398
itemFlags |= Qt::ItemIsEnabled;
403
QVariant OptContentModel::headerData( int section, Qt::Orientation orientation, int role ) const
405
return QAbstractItemModel::headerData( section, orientation, role );
408
void OptContentModelPrivate::addChild( OptContentItem *parent, OptContentItem *child )
410
parent->addChild( child );
413
OptContentItem* OptContentModelPrivate::itemFromRef( const QString &ref ) const
415
return m_optContentItems.value(ref, 0);
418
OptContentItem* OptContentModelPrivate::nodeFromIndex(const QModelIndex &index, bool canBeNull) const
420
if (index.isValid()) {
421
return static_cast<OptContentItem *>(index.internalPointer());
423
return canBeNull ? 0 : m_rootNode;
428
#include "poppler-optcontent.moc"