1 /**********************************************************************
2 PrimitiveItemModel - Model for representing primitives.
4 Copyright (C) 2007 Donald Ephraim Curtis <dcurtis3@sourceforge.net>
6 This file is part of the Avogadro molecular editor project.
7 For more information, see <http://avogadro.sourceforge.net/>
9 Avogadro is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 Avogadro is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 **********************************************************************/
25 #include <avogadro/primitiveitemmodel.h>
31 class PrimitiveItemModelPrivate
34 PrimitiveItemModelPrivate() : engine(0), molecule(0) {}
40 // use this to optimize insert / delete
41 QMap
<int, Primitive::Type
> rowTypeMap
;
43 // keep track of the model sizes for each parent
47 * for Molecules we have to cache additions / subtractions
48 * because when we get the signal we haven't actually added
49 * the atom to the molecule, rather it's been created but not
52 QVector
<QVector
<Primitive
*> > moleculeCache
;
55 PrimitiveItemModel::PrimitiveItemModel( Engine
*engine
, QObject
*parent
) : QAbstractItemModel(parent
), d(new PrimitiveItemModelPrivate
)
59 d
->rowTypeMap
.insert(0, Primitive::AtomType
);
60 d
->rowTypeMap
.insert(1, Primitive::BondType
);
61 d
->rowTypeMap
.insert(2, Primitive::ResidueType
);
63 d
->size
.resize(d
->rowTypeMap
.size());
65 connect(engine
, SIGNAL(changed()), this, SLOT(engineChanged()));
66 PrimitiveList list
= engine
->primitives();
67 foreach(int row
, d
->rowTypeMap
.keys())
69 d
->size
[row
] = list
.count(d
->rowTypeMap
[row
]);
73 PrimitiveItemModel::PrimitiveItemModel( Molecule
*molecule
, QObject
*parent
) : QAbstractItemModel(parent
), d(new PrimitiveItemModelPrivate
)
75 d
->molecule
= molecule
;
77 d
->rowTypeMap
.insert(0, Primitive::AtomType
);
78 d
->rowTypeMap
.insert(1, Primitive::BondType
);
79 d
->rowTypeMap
.insert(2, Primitive::ResidueType
);
81 d
->size
.resize(d
->rowTypeMap
.size());
82 d
->moleculeCache
.resize(d
->rowTypeMap
.size());
84 d
->size
[0] = molecule
->NumAtoms();
85 d
->size
[1] = molecule
->NumBonds();
86 d
->size
[2] = molecule
->NumResidues();
88 connect(molecule
, SIGNAL(primitiveAdded(Primitive
*)),
89 this, SLOT(addPrimitive(Primitive
*)));
90 connect(molecule
, SIGNAL(primitiveUpdated(Primitive
*)),
91 this, SLOT(updatePrimitive(Primitive
*)));
92 connect(molecule
, SIGNAL(primitiveRemoved(Primitive
*)),
93 this, SLOT(removePrimitive(Primitive
*)));
96 void PrimitiveItemModel::addPrimitive(Primitive
*primitive
)
98 int parentRow
= d
->rowTypeMap
.key(primitive
->type());
100 if(parentRow
< d
->size
.size())
102 int last
= d
->size
[parentRow
]++;
103 beginInsertRows(createIndex(parentRow
, 0, 0), last
, last
);
105 d
->moleculeCache
[parentRow
].append(primitive
);
111 void PrimitiveItemModel::updatePrimitive(Primitive
*primitive
)
113 int parentRow
= d
->rowTypeMap
.key(primitive
->type());
115 if(parentRow
< d
->size
.size())
117 int row
= primitiveIndex(primitive
);
118 emit
dataChanged(createIndex(row
, 0, primitive
), createIndex(row
, 0, primitive
));
122 void PrimitiveItemModel::removePrimitive(Primitive
*primitive
)
124 int parentRow
= d
->rowTypeMap
.key(primitive
->type());
125 if(parentRow
< d
->size
.size())
127 int row
= primitiveIndex(primitive
);
131 beginRemoveRows(createIndex(parentRow
, 0, 0), row
, row
);
134 d
->moleculeCache
[parentRow
].remove(row
);
136 d
->size
[parentRow
]--;
141 int PrimitiveItemModel::primitiveIndex(Primitive
*primitive
)
145 int parentRow
= d
->rowTypeMap
.key(primitive
->type());
146 return d
->moleculeCache
[parentRow
].indexOf(primitive
);
150 QList
<Primitive
*> subList
= d
->engine
->primitives().subList(primitive
->type());
151 return subList
.indexOf(primitive
);
158 void PrimitiveItemModel::engineChanged()
160 PrimitiveList list
= d
->engine
->primitives();
161 foreach(int row
, d
->rowTypeMap
.keys())
163 Primitive::Type type
= d
->rowTypeMap
[row
];
164 int newsize
= list
.count(type
);
165 int oldsize
= d
->size
.at(row
);
166 if(newsize
< oldsize
)
168 d
->size
[row
] = newsize
;
170 beginRemoveRows(createIndex(row
,0,0), newsize
, oldsize
-1);
171 QList
<Primitive
*> subList
= list
.subList(type
);
174 // this is a minor hack to simplify things although it doesn't currently update the view
175 emit
layoutChanged();
179 else if(newsize
> oldsize
)
181 d
->size
[row
] = newsize
;
182 beginInsertRows(createIndex(row
,0,0), oldsize
, newsize
-1);
188 QModelIndex
PrimitiveItemModel::parent( const QModelIndex
& index
) const
192 return QModelIndex();
195 Primitive
*primitive
= static_cast<Primitive
*>(index
.internalPointer());
198 int row
= d
->rowTypeMap
.key(primitive
->type());
199 return createIndex(row
, 0, 0);
201 return QModelIndex();
204 int PrimitiveItemModel::rowCount( const QModelIndex
& parent
) const
206 if(!parent
.isValid())
208 return d
->rowTypeMap
.size();
211 Primitive
*primitive
= static_cast<Primitive
*>(parent
.internalPointer());
214 return d
->size
[parent
.row()];
220 int PrimitiveItemModel::columnCount( const QModelIndex
& ) const
225 QVariant
PrimitiveItemModel::data ( const QModelIndex
& index
, int role
) const
227 if(!index
.isValid() || index
.column() != 0)
232 Primitive
*primitive
= static_cast<Primitive
*>(index
.internalPointer());
235 if(role
== Qt::DisplayRole
) {
236 Primitive::Type type
= primitive
->type();
239 if(type
== Primitive::MoleculeType
) {
240 str
= tr("Molecule");
242 else if(type
== Primitive::AtomType
) {
243 Atom
*atom
= (Atom
*)primitive
;
244 str
= tr("Atom") + ' '
245 + QString(OpenBabel::etab
.GetSymbol(atom
->GetAtomicNum()))
246 + ' ' + QString::number(atom
->GetIdx());
248 else if(type
== Primitive::BondType
){
249 Bond
*bond
= (Bond
*)primitive
;
250 Atom
*beginAtom
= (Atom
*)bond
->GetBeginAtom();
251 Atom
*endAtom
= (Atom
*)bond
->GetEndAtom();
252 str
= tr("Bond") + ' ' + QString::number(bond
->GetIdx()) + " (";
254 str
+= QString::number(beginAtom
->GetIdx());
256 // this should never happen: Bond always has a beginning -GRH
263 str
+= QString::number(endAtom
->GetIdx());
265 // this should never happen: Bond always has an end -GRH
270 else if(type
== Primitive::ResidueType
) {
271 Residue
*residue
= (Residue
*)primitive
;
272 str
= tr("Residue") + ' ';
273 str
+= QString(residue
->GetName().c_str()) + ' '
274 + QString(residue
->GetNumString().c_str());
279 } else if ( role
== PrimitiveItemModel::PrimitiveRole
) {
280 return qVariantFromValue(primitive
);
284 if(role
== Qt::DisplayRole
&& index
.row() < d
->rowTypeMap
.size())
286 Primitive::Type type
= d
->rowTypeMap
[index
.row()];
287 if(type
== Primitive::AtomType
) {
289 } else if (type
== Primitive::BondType
) {
291 } else if (type
== Primitive::ResidueType
) {
292 return tr("Residues");
299 Qt::ItemFlags
PrimitiveItemModel::flags ( const QModelIndex
& index
) const
301 if(!index
.isValid()) {
305 Primitive
*primitive
= static_cast<Primitive
*>(index
.internalPointer());
308 return Qt::ItemIsSelectable
| Qt::ItemIsEnabled
;
311 return Qt::ItemIsEnabled
;
314 QModelIndex
PrimitiveItemModel::index ( int row
, int column
, const QModelIndex
& parent
) const
316 if(!parent
.isValid())
318 return createIndex(row
, column
);
321 Primitive
*primitive
= static_cast<Primitive
*>(parent
.internalPointer());
324 return QModelIndex();
329 QList
<Primitive
*> subList
=
330 d
->engine
->primitives().subList(d
->rowTypeMap
[parent
.row()]);
331 if(row
< subList
.size()) {
332 return createIndex(row
, column
, subList
.at(row
));
334 } else if (d
->molecule
) {
335 // Primitive::Type type = d->rowTypeMap[parent.row()];
336 int parentRow
= parent
.row();
338 Primitive
*primitive
;
339 primitive
= d
->moleculeCache
[parentRow
].at(row
);
340 return createIndex(row
, column
, primitive
);
343 return QModelIndex();
346 } // end namespace Avogadro
348 #include "primitiveitemmodel.moc"