1/*
2 This file is part of libkldap.
3 Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21#include "ldapmodel.h"
22#include "ldapmodel_p.h"
23#include "ldapmodelnode_p.h"
24#include "ldapsearch.h"
25
26#include <kdebug.h>
27#include <klocalizedstring.h>
28#include <kglobal.h>
29
30static const KCatalogLoader loader( QLatin1String("libkldap") );
31
32using namespace KLDAP;
33
34LdapModel::LdapModel( QObject *parent )
35 : QAbstractItemModel( parent ),
36 m_d( new LdapModelPrivate( this ) )
37{
38 m_d->createConnections();
39}
40
41LdapModel::LdapModel( LdapConnection &connection, QObject *parent )
42 : QAbstractItemModel( parent ),
43 m_d( new LdapModelPrivate( this, connection ) )
44{
45 m_d->createConnections();
46
47 // Populate items from the root object to that representing the baseDN
48 m_d->populateRootToBaseDN();
49}
50
51LdapModel::~LdapModel()
52{
53 delete m_d;
54}
55
56void LdapModel::setConnection( LdapConnection &connection )
57{
58 m_d->setConnection( connection );
59
60 // Refresh the model
61 m_d->recreateRootItem();
62
63 // Populate the root object by searching the baseDN
64 m_d->populateRootToBaseDN();
65}
66
67QModelIndex LdapModel::parent( const QModelIndex &child ) const
68{
69 if ( !child.isValid() ) {
70 return QModelIndex();
71 }
72
73 LdapModelNode *childItem = static_cast<LdapModelNode*>( child.internalPointer() );
74 LdapModelDNNode *parentItem = childItem->parent();
75
76 if ( parentItem == m_d->rootNode() ) {
77 return QModelIndex();
78 }
79
80 return createIndex( parentItem->row(), 0, parentItem );
81}
82
83QModelIndex LdapModel::index( int row, int col, const QModelIndex &parent ) const
84{
85 // Retrieve a pointer to the parent item
86 LdapModelDNNode *parentItem;
87 if ( !parent.isValid() ) {
88 parentItem = m_d->rootNode();
89 } else {
90 parentItem = static_cast<LdapModelDNNode*>( parent.internalPointer() );
91 }
92
93 LdapModelNode *childItem = parentItem->child( row );
94 if ( childItem ) {
95 return createIndex( row, col, childItem );
96 }
97 kDebug() << "Could not create valid index for row =" << row << ", col =" << col;
98 return QModelIndex();
99}
100
101QVariant LdapModel::data( const QModelIndex &index, int role ) const
102{
103 if ( !index.isValid() ) {
104 return QVariant();
105 }
106
107 if ( role == Qt::DisplayRole ) {
108 // This is what gets displayed by the view delegates.
109 LdapModelNode *node = static_cast<LdapModelNode*>( index.internalPointer() );
110 if ( node->nodeType() == LdapModelNode::DN ) {
111 LdapModelDNNode* dn = static_cast<LdapModelDNNode*>( node );
112 if ( index.column() == 0 ) {
113 return dn->dn().rdnString();
114 } else {
115 return QVariant();
116 }
117 } else {
118 LdapModelAttrNode* attr = static_cast<LdapModelAttrNode*>( node );
119 if ( index.column() == 0 ) {
120 return QVariant( attr->attributeName() );
121 } else {
122 return QVariant( QLatin1String( attr->attributeData().constData() ) );
123 }
124 }
125 } else if ( role == NodeTypeRole ) {
126 LdapModelNode* node = static_cast<LdapModelNode*>( index.internalPointer() );
127 return QVariant( int( node->nodeType() ) );
128 }
129
130 /** \todo Include support for nice decorative icons dependent upon
131 the objectClass + other role data. */
132 /** \todo Include support for other roles as needed */
133
134 return QVariant();
135}
136
137bool LdapModel::setData( const QModelIndex &index,
138 const QVariant &value,
139 int role )
140{
141 Q_UNUSED( index );
142 Q_UNUSED( value );
143 Q_UNUSED( role );
144 return false;
145}
146
147QVariant LdapModel::headerData( int section, Qt::Orientation orientation, int role ) const
148{
149 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) {
150 if ( section == 0 ) {
151 return i18n( "Attribute" );
152 } else {
153 return i18n( "Value" );
154 }
155 }
156
157 return QVariant();
158}
159
160Qt::ItemFlags LdapModel::flags( const QModelIndex &index ) const
161{
162 /** \TODO Read-only for now, make read-write upon request */
163 if ( !index.isValid() ) {
164 return Qt::ItemIsEnabled;
165 }
166
167 return Qt::ItemFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
168}
169
170int LdapModel::columnCount( const QModelIndex &parent ) const
171{
172 LdapModelDNNode *parentNode =
173 parent.isValid() ? static_cast<LdapModelDNNode*>( parent.internalPointer() ) : m_d->rootNode();
174 return parentNode->columnCount();
175}
176
177int LdapModel::rowCount( const QModelIndex &parent ) const
178{
179 if ( parent.column() > 0 ) {
180 return 0;
181 }
182
183 const LdapModelDNNode *parentNode =
184 parent.isValid() ? static_cast<LdapModelDNNode*>( parent.internalPointer() ) : m_d->rootNode();
185 return parentNode->childCount();
186}
187
188bool LdapModel::hasChildren( const QModelIndex &parent ) const
189{
190 // We return true unless the item has been populated and we are able to do a definitive test
191 const LdapModelNode *node = parent.isValid() ?
192 static_cast<const LdapModelNode*>( parent.internalPointer() ) :
193 m_d->rootNode();
194
195 if ( node->nodeType() != LdapModelNode::DN ) {
196 return false;
197 }
198
199 const LdapModelDNNode* parentNode = static_cast<const LdapModelDNNode*>( node );
200 if ( !parent.isValid() || parentNode->isPopulated() ) {
201 return parentNode->childCount() > 0;
202 }
203 return true;
204}
205
206bool LdapModel::canFetchMore( const QModelIndex &parent ) const
207{
208 const LdapModelDNNode *parentNode =
209 parent.isValid() ? static_cast<LdapModelDNNode*>( parent.internalPointer() ) : m_d->rootNode();
210 return !parentNode->isPopulated();
211}
212
213void LdapModel::fetchMore( const QModelIndex &parent )
214{
215 LdapModelDNNode *parentNode =
216 parent.isValid() ? static_cast<LdapModelDNNode*>( parent.internalPointer() ) : m_d->rootNode();
217
218 // Search for the immediate children of parentItem.
219 m_d->searchResults().clear();
220 m_d->setSearchType( LdapModelPrivate::ChildObjects, parentNode );
221 m_d->search( parentNode->dn(), // DN to search from
222 LdapUrl::One, // What to search
223 QString() ); // Attributes to retrieve
224 parentNode->setPopulated( true );
225}
226
227bool LdapModel::insertRows( int row, int count,
228 const QModelIndex &parent )
229{
230 Q_UNUSED( row );
231 Q_UNUSED( count );
232 Q_UNUSED( parent );
233 return false;
234}
235
236bool LdapModel::removeRows( int row, int count,
237 const QModelIndex &parent )
238{
239 Q_UNUSED( row );
240 Q_UNUSED( count );
241 Q_UNUSED( parent );
242 return false;
243}
244
245void LdapModel::sort( int column, Qt::SortOrder order )
246{
247 Q_UNUSED( column );
248 Q_UNUSED( order );
249}
250
251Qt::DropActions LdapModel::supportedDropActions() const
252{
253 return Qt::MoveAction;
254}
255
256QMimeData *LdapModel::mimeData( const QModelIndexList &indexes ) const
257{
258 Q_UNUSED( indexes );
259 return 0;
260}
261
262bool LdapModel::dropMimeData( const QMimeData *data, Qt::DropAction action,
263 int row, int column, const QModelIndex &parent )
264{
265 /** \todo Implement drag and drop for LdapModel */
266 Q_UNUSED( data );
267 Q_UNUSED( action );
268 Q_UNUSED( row );
269 Q_UNUSED( column );
270 Q_UNUSED( parent );
271 return false;
272}
273
274bool LdapModel::hasChildrenOfType( const QModelIndex &parent, LdapDataType type ) const
275{
276 // Map from LdapDataType to our internal NodeType
277 LdapModelNode::NodeType nodeType;
278 switch ( type ) {
279 case Attribute:
280 nodeType = LdapModelNode::Attr;
281 break;
282
283 case DistinguishedName:
284 default:
285 nodeType = LdapModelNode::DN;
286 break;
287 }
288
289 const LdapModelNode *node = parent.isValid() ?
290 static_cast<const LdapModelNode*>( parent.internalPointer() ) :
291 m_d->rootNode();
292
293 const LdapModelDNNode* parentNode = static_cast<const LdapModelDNNode*>( node );
294 if ( !parent.isValid() || parentNode->isPopulated() ) {
295 // Check to see if the parent has any children of the specified type
296 const QList<LdapModelNode*>& children = parentNode->children();
297 foreach ( LdapModelNode *child, children ) {
298 if ( child->nodeType() == nodeType ) {
299 return true;
300 }
301 }
302
303 // Either there are no children or only children of a different type
304 return false;
305 }
306
307 // If the node is not populated or is the root node (invalid), then return
308 // true to be on the safe side.
309 return true;
310}
311
312void LdapModel::revert()
313{
314
315}
316
317bool LdapModel::submit()
318{
319 return false;
320}
321
322#include "moc_ldapmodel.cpp"
323