[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-pim
Subject:    [Kde-pim] [PATCH] LdapModel functionality
From:       Sean Harmer <sh () theharmers ! co ! uk>
Date:       2007-10-23 5:50:15
Message-ID: 200710230650.15598.sh () theharmers ! co ! uk
[Download RAW message or body]

Hi All,

I know we are very close to the freeze, but is there any objection to me 
committing the following patch to kdepimlibs?

The patch replaces much of the private backend of LdapModel and introduces two 
proxy models that are more suitable for direct use with standard views. The 
two proxy models are LdapStructureProxyModel and LdapAttributeProxyModel. The 
first correctly provides the necessary data to display the hierrarchical 
structure of ldap trees. The second will shortly provide data for 
showing/editing attributes of objects in the tree. Examle use of these 
classes can be seen in playground/sysadmin/arboretum.

The LdapAttributeProxyModel needs fixing so that it correctly provides the 
data. I think I know how to do this with the use of a QPersistentModelIndex 
in the proxy model.

I'd just like to get this in before the KDE 4.0 freeze so that I can continue 
working on fixing it before release.

Thanks,

Sean

["ldapmodel.patch" (text/x-diff)]

Index: kldap/ldapmodel.h
===================================================================
--- kldap/ldapmodel.h	(revision 728366)
+++ kldap/ldapmodel.h	(working copy)
@@ -33,6 +33,15 @@
 {
   Q_OBJECT
   public:
+    enum Roles {
+      NodeTypeRole = Qt::UserRole + 1
+    };
+
+    enum LdapDataType {
+      DistinguishedName = 0,
+      Attribute
+    };
+
     explicit LdapModel( QObject *parent = 0 );
     explicit LdapModel( LdapConnection &connection, QObject *parent = 0 );
     virtual ~LdapModel();
@@ -50,6 +59,11 @@
     virtual bool canFetchMore( const QModelIndex &parent ) const;
     virtual void fetchMore( const QModelIndex &parent );
 
+    bool hasChildrenOfType( const QModelIndex &parent, LdapDataType type ) const;
+
+  signals:
+    void ready();
+
   private:
     class LdapModelPrivate;
     LdapModelPrivate *const m_d;
Index: kldap/ldapmodeltreeitem_p.cpp
===================================================================
--- kldap/ldapmodeltreeitem_p.cpp	(revision 728366)
+++ kldap/ldapmodeltreeitem_p.cpp	(working copy)
@@ -1,97 +0,0 @@
-/*
-  This file is part of libkldap.
-  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
-
-  This library 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 of the License, or (at your option) any later version.
-
-  This library 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 library; see the file COPYING.LIB.  If not, write to
-  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA 02110-1301, USA.
-*/
-
-#include "ldapmodeltreeitem_p.h"
-
-#include <kdebug.h>
-
-using namespace KLDAP;
-
-LdapModelTreeItem::LdapModelTreeItem( LdapModelTreeItem *parent, const LdapObject \
                &data )
-  : m_childItems(),
-    m_parent( parent ),
-    m_itemData( data ),
-    m_isPopulated( false )
-{
-  kDebug(5322) << "LdapModelTreeItem::LdapModelTreeItem() : Object =" << \
                data.toString();
-  if ( m_parent ) {
-    m_parent->appendChild( this );
-  }
-}
-
-LdapModelTreeItem::~LdapModelTreeItem()
-{
-  qDeleteAll( m_childItems );
-}
-
-void LdapModelTreeItem::appendChild( LdapModelTreeItem *pItem )
-{
-  m_childItems.append( pItem );
-  setPopulated( true );
-}
-
-LdapModelTreeItem *LdapModelTreeItem::child( int row )
-{
-  return m_childItems.value( row );
-}
-
-LdapModelTreeItem *LdapModelTreeItem::parent()
-{
-  return m_parent;
-}
-
-int LdapModelTreeItem::childCount() const
-{
-  return m_childItems.count();
-}
-
-int LdapModelTreeItem::columnCount() const
-{
-  return 1;
-}
-
-const LdapObject &LdapModelTreeItem::data() const
-{
-  return m_itemData;
-}
-
-int LdapModelTreeItem::row() const
-{
-  if ( m_parent ) {
-    return m_parent->m_childItems.indexOf( const_cast<LdapModelTreeItem*>( this ) );
-  }
-  return 0;
-}
-
-LdapObject &LdapModelTreeItem::ldapObject()
-{
-  return m_itemData;
-}
-
-const LdapObject &LdapModelTreeItem::ldapObject() const
-{
-  return m_itemData;
-}
-
-void LdapModelTreeItem::setLdapObject( const LdapObject &object )
-{
-  kDebug(5322) << "LdapModelTreeItem::setLdapObject() : Object =" << \
                object.toString();
-  m_itemData = object;
-}
Index: kldap/ldapmodel_p.cpp
===================================================================
--- kldap/ldapmodel_p.cpp	(revision 728366)
+++ kldap/ldapmodel_p.cpp	(working copy)
@@ -19,7 +19,7 @@
 */
 
 #include "ldapmodel_p.h"
-#include "ldapmodeltreeitem_p.h"
+#include "ldapmodelnode_p.h"
 #include "ldapsearch.h"
 
 #include <kdebug.h>
@@ -28,7 +28,7 @@
 
 LdapModel::LdapModelPrivate::LdapModelPrivate( LdapModel *parent )
   : m_parent( parent ),
-    m_root( new LdapModelTreeItem ),
+    m_root( new LdapModelDNNode ),
     m_search( new LdapSearch ),
     m_searchResultObjects(),
     m_baseDN(),
@@ -39,7 +39,7 @@
 
 LdapModel::LdapModelPrivate::LdapModelPrivate( LdapModel *parent, LdapConnection \
&connection )  : m_parent( parent ),
-    m_root( new LdapModelTreeItem ),
+    m_root( new LdapModelDNNode ),
     m_search( new LdapSearch( connection ) ),
     m_searchResultObjects(),
     m_baseDN(),
@@ -73,22 +73,22 @@
   return m_search->search( searchBase, scope, filter, attributes, pagesize );
 }
 
-void LdapModel::LdapModelPrivate::setSearchType( SearchType t, LdapModelTreeItem \
*item ) +void LdapModel::LdapModelPrivate::setSearchType( SearchType t, \
LdapModelDNNode *item )  {
-  kDebug(5322) << "LdapModel::LdapModelPrivate::setSearchType() : item =" << item;
+  //kDebug(5322) << "LdapModel::LdapModelPrivate::setSearchType() : item =" << item;
   m_searchType = t;
   m_searchItem = item;
 }
 
 void LdapModel::LdapModelPrivate::recreateRootItem()
 {
-  kDebug(5322) << "LdapModel::LdapModelPrivate::recreateRootItem()";
+  //kDebug(5322) << "LdapModel::LdapModelPrivate::recreateRootItem()";
   if ( m_root ) {
     delete m_root;
     m_root = 0;
   }
-  m_root = new LdapModelTreeItem;
-  kDebug(5322) << "&m_root =" << &m_root;
+  m_root = new LdapModelDNNode;
+  //kDebug(5322) << "&m_root =" << &m_root;
 }
 
 void LdapModel::LdapModelPrivate::createConnections()
@@ -101,19 +101,20 @@
 
 void LdapModel::LdapModelPrivate::populateRootToBaseDN()
 {
-  kDebug(5322) << "LdapModel::LdapModelPrivate::populateRootToBaseDN()";
+  //kDebug(5322) << "LdapModel::LdapModelPrivate::populateRootToBaseDN()";
 
   if ( baseDN().isEmpty() ) {
     // Query the server for the base DN
-    setSearchType( LdapModelPrivate::NamingContexts, rootItem() );
+    //kDebug(5322) << "Searching for the baseDN";
+    setSearchType( LdapModelPrivate::NamingContexts, rootNode() );
     search( LdapDN(), LdapUrl::Base, QString(), QStringList() << "namingContexts" );
     return;
   }
 
   // Start a search for the details of the baseDN object
+  //kDebug(5322) << "Searching for attributes of the baseDN";
   searchResults().clear();
-  LdapModelTreeItem *searchItem = rootItem();
-  setSearchType( LdapModelPrivate::BaseDN, searchItem );
+  setSearchType( LdapModelPrivate::BaseDN, rootNode() );
   search( baseDN(), LdapUrl::Base, QString(), QStringList() << "dn" << "objectClass" \
);  }
 
@@ -130,7 +131,7 @@
     if ( !searchResults().isEmpty() &&
          searchResults().at( 0 ).hasAttribute( "namingContexts" ) ) {
       baseDN = searchResults().at( 0 ).value( "namingContexts" );
-      kDebug(5322) << "Found baseDN =" << baseDN;
+      //kDebug(5322) << "Found baseDN =" << baseDN;
     }
     setBaseDN( LdapDN( baseDN ) );
 
@@ -144,8 +145,8 @@
   }
   case LdapModelPrivate::BaseDN:
   {
-    kDebug(5322) << "Found details of the baseDN object."
-                 << "Creating objects down to this level.";
+    //kDebug(5322) << "Found details of the baseDN object."
+    //             << "Creating objects down to this level.";
 
     // Get the baseDN LdapObject
     LdapObject baseDNObj = searchResults().at( 0 );
@@ -154,43 +155,45 @@
     int depth = baseDNObj.dn().depth();
 
     // Create items that represent objects down to the baseDN
-    LdapModelTreeItem *parent = rootItem();
-    LdapModelTreeItem *item = 0;
+    LdapModelDNNode *parent = rootNode();
+    LdapModelDNNode *item = 0;
     for ( int i = 0; i < depth; i++ ) {
       QString dn = baseDN().toString( i );
       kDebug(5322) << "Creating item for DN :" << dn;
-      LdapObject obj( dn );
-      item = new LdapModelTreeItem( parent, obj );
+
+      //LdapObject obj( dn );
+      item = new LdapModelDNNode( parent, LdapDN( dn ) );
       parent = item;
     }
 
     // Store the search result
-    item->setLdapObject( searchResults().at( 0 ) );
+    item->setLdapObject( baseDNObj );
 
     // Flag that we are no longer searching
     setSearchType( LdapModelPrivate::NotSearching );
     //emit( layoutChanged() );
 
+    // Let the world know we are ready for action
+    emit m_parent->ready();
+
     break;
   }
   case LdapModelPrivate::ChildObjects:
   {
-    kDebug(5322) << "Found" << searchResults().size() << "child objects";
+    //kDebug(5322) << "Found" << searchResults().size() << "child objects";
 
     if ( searchResults().size() != 0 )
     {
       // Create an index for the soon-to-be-a-parent item
-      LdapModelTreeItem *parentItem = searchItem();
-      int r = parentItem->row();
-      QModelIndex parentIndex = m_parent->createIndex( r, 0, parentItem );
+      LdapModelDNNode *parentNode = searchItem();
+      int r = parentNode->row();
+      QModelIndex parentIndex = m_parent->createIndex( r, 0, parentNode );
 
       m_parent->beginInsertRows( parentIndex, 0, searchResults().size() );
       for ( int i = 0; i < searchResults().size(); i++ ) {
-        LdapObject itemData = searchResults().at( i );
-        LdapModelTreeItem *item = new LdapModelTreeItem( parentItem, itemData );
-        if ( !item ) {
-            kDebug(5322) << "Could not create LdapModelTreeItem";
-        }
+        LdapObject object = searchResults().at( i );
+        LdapModelDNNode *item = new LdapModelDNNode( parentNode, object.dn() );
+        item->setLdapObject( object );
       }
 
       m_parent->endInsertRows();
@@ -210,7 +213,7 @@
 void LdapModel::LdapModelPrivate::gotSearchData( KLDAP::LdapSearch *search, const \
KLDAP::LdapObject &obj )  {
   Q_UNUSED( search );
-  kDebug(5322) << "LdapModel::LdapModelPrivate::gotSearchData()";
+  //kDebug(5322) << "LdapModel::LdapModelPrivate::gotSearchData()";
   //kDebug(5322) << "Object:";
   //kDebug(5322) << obj.toString();
   searchResults().append( obj );
Index: kldap/ldapstructureproxymodel.h
===================================================================
--- kldap/ldapstructureproxymodel.h	(revision 0)
+++ kldap/ldapstructureproxymodel.h	(revision 0)
@@ -0,0 +1,50 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library 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 of the License, or (at your option) any later version.
+
+  This library 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 library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPSTRUCTUREPROXYMODEL_H
+#define KLDAP_LDAPSTRUCTUREPROXYMODEL_H
+
+#include <QSortFilterProxyModel>
+
+#include "kldap_export.h"
+
+namespace KLDAP {
+
+class KLDAP_EXPORT LdapStructureProxyModel : public QSortFilterProxyModel
+{
+  Q_OBJECT
+  public:
+    explicit LdapStructureProxyModel( QObject *parent = 0 );
+    ~LdapStructureProxyModel();
+
+    virtual QVariant data( const QModelIndex &index, int role ) const;
+    virtual bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) \
const; +    virtual QVariant headerData( int section, Qt::Orientation orientation, \
int role ) const; +    virtual int columnCount( const QModelIndex &parent ) const;
+    virtual Qt::ItemFlags flags( const QModelIndex &index ) const;
+    virtual bool hasChildren( const QModelIndex &parent ) const;
+
+  private:
+    class LdapStructureProxyModelPrivate;
+    LdapStructureProxyModelPrivate *const m_d;
+};
+
+}
+#endif
Index: kldap/ldapmodelnode_p.h
===================================================================
--- kldap/ldapmodelnode_p.h	(revision 0)
+++ kldap/ldapmodelnode_p.h	(revision 0)
@@ -0,0 +1,122 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library 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 of the License, or (at your option) any later version.
+
+  This library 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 library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPMODELTREEITEM_P_H
+#define KLDAP_LDAPMODELTREEITEM_P_H
+
+#include <QByteArray>
+#include <QString>
+#include <QtCore/QList>
+#include <QtCore/QVariant>
+
+#include "ldapdn.h"
+#include "ldapobject.h"
+#include "kldap_export.h"
+
+namespace KLDAP {
+
+class LdapModelDNNode;
+
+/**
+ * @internal
+ */
+class LdapModelNode
+{
+  public:
+    explicit LdapModelNode( LdapModelDNNode *parent = 0 );
+    virtual ~LdapModelNode();
+
+    enum NodeType {
+      DN,
+      Attr
+    };
+
+    virtual NodeType nodeType() const = 0;
+
+    LdapModelDNNode *parent();
+    int columnCount() const { return 2; }
+    int row() const;
+
+    void setPopulated( bool b ) { m_isPopulated = b; }
+    bool isPopulated() const { return m_isPopulated; }
+
+  private:
+    LdapModelDNNode *m_parent;
+    bool m_isPopulated;
+};
+
+
+/**
+ * @internal
+ */
+class LdapModelDNNode : public LdapModelNode
+{
+  public:
+    explicit LdapModelDNNode( LdapModelDNNode *parent = 0,
+                              const LdapDN &dn = LdapDN() );
+    ~LdapModelDNNode();
+
+    LdapModelNode::NodeType nodeType() const { return LdapModelNode::DN; }
+
+    void appendChild( LdapModelNode *pItem );
+    LdapModelNode *child( int row );
+    int childCount() const { return m_childItems.size(); }
+    const QList<LdapModelNode*>& children() const { return m_childItems; }
+
+    const LdapDN &dn() const { return m_dn; }
+
+    /**
+     * Creates child LdapModelAttrNode object to store \p object's attributes
+     * and adds them as children of this node.
+     *
+     * \param The LdapObject to store in this node.
+     */
+    void setLdapObject( const LdapObject &object );
+
+  private:
+    QList<LdapModelNode*> m_childItems;
+    LdapDN m_dn;
+};
+
+
+/**
+ * @internal
+ */
+class LdapModelAttrNode : public LdapModelNode
+{
+  public:
+    explicit LdapModelAttrNode( LdapModelDNNode *parent = 0,
+                                const QString &attrName = QString(),
+                                const QByteArray &attrData = QByteArray() );
+    ~LdapModelAttrNode();
+
+    LdapModelNode::NodeType nodeType() const { return LdapModelNode::Attr; }
+
+    const QString &attributeName() { return m_attrName; }
+    const QByteArray &attributeData() { return m_attrData; }
+
+  private:
+    QString m_attrName;
+    QByteArray m_attrData;
+};
+
+}
+
+#endif
Index: kldap/ldapattributeproxymodel.h
===================================================================
--- kldap/ldapattributeproxymodel.h	(revision 0)
+++ kldap/ldapattributeproxymodel.h	(revision 0)
@@ -0,0 +1,50 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library 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 of the License, or (at your option) any later version.
+
+  This library 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 library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPATTRIBUTEPROXYMODEL_H
+#define KLDAP_LDAPATTRIBUTEPROXYMODEL_H
+
+#include <QSortFilterProxyModel>
+
+#include "kldap_export.h"
+
+namespace KLDAP {
+
+class KLDAP_EXPORT LdapAttributeProxyModel : public QSortFilterProxyModel
+{
+  Q_OBJECT
+  public:
+    explicit LdapAttributeProxyModel( QObject *parent = 0 );
+    ~LdapAttributeProxyModel();
+
+    virtual QVariant data( const QModelIndex &index, int role ) const;
+    virtual bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) \
const; +    virtual QVariant headerData( int section, Qt::Orientation orientation, \
int role ) const; +    virtual int columnCount( const QModelIndex &parent ) const;
+    virtual Qt::ItemFlags flags( const QModelIndex &index ) const;
+    virtual bool hasChildren( const QModelIndex &parent ) const;
+
+  private:
+    class LdapAttributeProxyModelPrivate;
+    LdapAttributeProxyModelPrivate *const m_d;
+};
+
+}
+#endif
Index: kldap/CMakeLists.txt
===================================================================
--- kldap/CMakeLists.txt	(revision 728366)
+++ kldap/CMakeLists.txt	(working copy)
@@ -44,7 +44,7 @@
 ########### next target ###############
 
 
-set(kldap_LIB_SRCS 
+set(kldap_LIB_SRCS
    ber.cpp
    ldif.cpp
    ldapurl.cpp
@@ -56,9 +56,11 @@
    ldapsearch.cpp
    ldapconfigwidget.cpp
    ldapdn.cpp
-   ldapmodeltreeitem_p.cpp
+   ldapmodelnode_p.cpp
    ldapmodel.cpp
-   ldapmodel_p.cpp )
+   ldapmodel_p.cpp
+   ldapstructureproxymodel.cpp
+   ldapattributeproxymodel.cpp)
 
 
 kde4_add_library(kldap SHARED ${kldap_LIB_SRCS})
@@ -68,7 +70,7 @@
 target_link_libraries(kldap ${KDE4_KIO_LIBS} ${kldap_EXTRA_LIBS} )
 
 set_target_properties(kldap PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION \
                ${GENERIC_LIB_SOVERSION})
-install(TARGETS kldap 
+install(TARGETS kldap
     RUNTIME DESTINATION ${BIN_INSTALL_DIR}
     LIBRARY DESTINATION ${LIB_INSTALL_DIR}
     ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
@@ -76,7 +78,8 @@
 
 ########### install files ###############
 
-install( FILES ber.h kldap_export.h ldapdefs.h ldif.h ldapurl.h ldapserver.h \
                ldapobject.h 
-  ldapconnection.h ldapoperation.h 
+install( FILES ber.h kldap_export.h ldapdefs.h ldif.h ldapurl.h ldapserver.h \
ldapobject.h +  ldapconnection.h ldapoperation.h
   ldapconfigwidget.h ldapcontrol.h ldapsearch.h
-  ldapdn.h ldapmodel.h DESTINATION ${INCLUDE_INSTALL_DIR}/kldap)
+  ldapdn.h ldapmodel.h ldapstructureproxymodel.h ldapattributeproxymodel.h
+  DESTINATION ${INCLUDE_INSTALL_DIR}/kldap)
Index: kldap/ldapmodel.cpp
===================================================================
--- kldap/ldapmodel.cpp	(revision 728366)
+++ kldap/ldapmodel.cpp	(working copy)
@@ -20,10 +20,11 @@
 
 #include "ldapmodel.h"
 #include "ldapmodel_p.h"
-#include "ldapmodeltreeitem_p.h"
+#include "ldapmodelnode_p.h"
 #include "ldapsearch.h"
 
 #include <kdebug.h>
+#include <klocale.h>
 
 using namespace KLDAP;
 
@@ -60,68 +61,91 @@
   m_d->populateRootToBaseDN();
 }
 
-QModelIndex LdapModel::index( int row, int col, const QModelIndex &parent ) const
-{
-  LdapModelTreeItem *parentItem;
-  if ( !parent.isValid() ) {
-    parentItem = m_d->rootItem();
-  } else {
-    parentItem = static_cast<LdapModelTreeItem*>( parent.internalPointer() );
-  }
-
-  LdapModelTreeItem *childItem = parentItem->child( row );
-  if ( childItem ) {
-    return createIndex( row, col, childItem );
-  } else {
-    return QModelIndex();
-  }
-}
-
 QModelIndex LdapModel::parent( const QModelIndex &child ) const
 {
   if ( !child.isValid() ) {
     return QModelIndex();
   }
 
-  LdapModelTreeItem *childItem = static_cast<LdapModelTreeItem*>( \
                child.internalPointer() );
-  LdapModelTreeItem *parentItem = childItem->parent();
+  LdapModelNode *childItem = static_cast<LdapModelNode*>( child.internalPointer() );
+  LdapModelDNNode *parentItem = childItem->parent();
 
-  if ( parentItem == m_d->rootItem() ) {
+  if ( parentItem == m_d->rootNode() ) {
     return QModelIndex();
   }
 
   return createIndex( parentItem->row(), 0, parentItem );
 }
 
+QModelIndex LdapModel::index( int row, int col, const QModelIndex &parent ) const
+{
+  // Retrieve a pointer to the parent item
+  LdapModelDNNode *parentItem;
+  if ( !parent.isValid() ) {
+    parentItem = m_d->rootNode();
+  } else {
+    parentItem = static_cast<LdapModelDNNode*>( parent.internalPointer() );
+  }
+
+  LdapModelNode *childItem = parentItem->child( row );
+  if ( childItem ) {
+    return createIndex( row, col, childItem );
+  }
+  kDebug(5322) << "Could not create valid index for row =" << row << ", col =" << \
col; +  return QModelIndex();
+}
+
 QVariant LdapModel::data( const QModelIndex &index, int role ) const
 {
   if ( !index.isValid() ) {
     return QVariant();
   }
 
-  LdapModelTreeItem *item = static_cast<LdapModelTreeItem*>( index.internalPointer() \
                );
-
   if ( role == Qt::DisplayRole ) {
-    kDebug(5322) << "***** LdapModel::data(): rdn =" << \
                item->data().dn().rdnString();
-    return item->data().dn().rdnString();
-  } else if ( role == Qt::ToolTipRole ) {
-    /** \TODO Make the tooltips look nicer - perhaps themeable? */
-    kDebug(5322) << "***** LdapModel::data(): Object =" << item->data().toString();
-    return item->data().toString();
+    // This is what gets displayed by the view delegates.
+    // kDebug(5322) << "row =" << index.row() << ", col =" << index.column();
+    LdapModelNode *node = static_cast<LdapModelNode*>( index.internalPointer() );
+    if ( node->nodeType() == LdapModelNode::DN ) {
+      LdapModelDNNode* dn = static_cast<LdapModelDNNode*>( node );
+      if ( index.column() == 0 ) {
+        return dn->dn().rdnString();
+      } else {
+        return QVariant();
+      }
+    } else {
+      LdapModelAttrNode* attr = static_cast<LdapModelAttrNode*>( node );
+      if ( index.column() == 0 ) {
+        return QVariant( attr->attributeName() );
+      } else {
+        return QVariant( QString( attr->attributeData().constData() ) );
+      }
+    }
+  } else if ( role == NodeTypeRole ) {
+    LdapModelNode* node = static_cast<LdapModelNode*>( index.internalPointer() );
+    return QVariant( int( node->nodeType() ) );
   }
 
+
+  //else if ( role == Qt::ToolTipRole ) {
+    /** \TODO Make the tooltips look nicer - perhaps themeable? */
+    //kDebug(5322) << "***** LdapModel::data(): Object =" << \
item->data().toString(); +  //  return item->data().toString();
+  //}
+
   /** \TODO Include support for nice decorative icons dependent upon
       the objectClass + other role data. */
 
   return QVariant();
 }
 
-QVariant LdapModel::headerData( int /*section*/, Qt::Orientation orientation, int \
role ) const +QVariant LdapModel::headerData( int section, Qt::Orientation \
orientation, int role ) const  {
   if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) {
-    /** @TODO Hmm, what to do here? Override in proxymodels perhaps as
-        could be "DN" or "Attribute". */
-    return QString( "Distinguished Name" );
+    if ( section == 0 ) {
+      return QString( i18n( "Attribute" ) );
+    } else {
+      return QString( i18n( "Value" ) );
+    }
   }
 
   return QVariant();
@@ -139,62 +163,99 @@
 
 int LdapModel::columnCount( const QModelIndex &parent ) const
 {
-  LdapModelTreeItem *parentItem =
-    parent.isValid() ? static_cast<LdapModelTreeItem*>( parent.internalPointer() ) : \
                m_d->rootItem();
-  return parentItem->columnCount();
+  LdapModelDNNode *parentNode =
+    parent.isValid() ? static_cast<LdapModelDNNode*>( parent.internalPointer() ) : \
m_d->rootNode(); +  return parentNode->columnCount();
 }
 
 int LdapModel::rowCount( const QModelIndex &parent ) const
 {
-  kDebug(5322) << "LdapModel::rowCount";
+  //kDebug(5322) << "LdapModel::rowCount";
   if ( parent.column() > 0 ) {
     return 0;
   }
 
-  const LdapModelTreeItem *item =
-    parent.isValid() ? static_cast<LdapModelTreeItem*>( parent.internalPointer() ) : \
                m_d->rootItem();
-  kDebug(5322) << "Parent (" << item->ldapObject().dn().toString() << ") has"
-               << item->childCount() << "children";
-  return item->childCount();
+  const LdapModelDNNode *parentNode =
+    parent.isValid() ? static_cast<LdapModelDNNode*>( parent.internalPointer() ) : \
m_d->rootNode(); +  //kDebug(5322) << "Parent (" << parentNode->dn().toString() << ") \
has" +  //             << parentNode->childCount() << "children";
+  return parentNode->childCount();
 }
 
 bool LdapModel::hasChildren( const QModelIndex &parent ) const
 {
-  // We always return true. This means that the branch expansion symbol will
-  // always be drawn. However, once the user clicks on it, rowCount() will
-  // get called and the view will not draw the expander if the item has no
-  // children.
-  const LdapModelTreeItem *item =
-    parent.isValid() ? static_cast<LdapModelTreeItem*>( parent.internalPointer() ) : \
                m_d->rootItem();
-  if ( !parent.isValid() || item->isPopulated() ) {
-    return item->childCount() > 0;
+  // We return true unless the item has been populated and we are able to do a \
definitive test +  const LdapModelNode *node = parent.isValid()
+    ? static_cast<const LdapModelNode*>( parent.internalPointer() )
+    : m_d->rootNode();
+
+  if ( node->nodeType() != LdapModelNode::DN )
+    return false;
+
+  const LdapModelDNNode* parentNode = static_cast<const LdapModelDNNode*>( node );
+  if ( !parent.isValid() || parentNode->isPopulated() ) {
+    return parentNode->childCount() > 0;
   }
   return true;
 }
 
 bool LdapModel::canFetchMore( const QModelIndex &parent ) const
 {
-  const LdapModelTreeItem *item =
-    parent.isValid() ? static_cast<LdapModelTreeItem*>( parent.internalPointer() ) : \
                m_d->rootItem();
-  kDebug(5322) << "LdapModel::canFetchMore() :" << !item->isPopulated();
-  return !item->isPopulated();
+  const LdapModelDNNode *parentNode =
+    parent.isValid() ? static_cast<LdapModelDNNode*>( parent.internalPointer() ) : \
m_d->rootNode(); +  return !parentNode->isPopulated();
 }
 
 void LdapModel::fetchMore( const QModelIndex &parent )
 {
-  /** @TODO This should be altered to search for all attributes we can
-      filter out those not required with a proxy model */
-  kDebug(5322) << "LdapModel::fetchMore()";
+  LdapModelDNNode *parentNode =
+    parent.isValid() ? static_cast<LdapModelDNNode*>( parent.internalPointer() ) : \
m_d->rootNode();  
-  LdapModelTreeItem *parentItem =
-    parent.isValid() ? static_cast<LdapModelTreeItem*>( parent.internalPointer() ) : \
                m_d->rootItem();
-
   // Search for the immediate children of parentItem.
   m_d->searchResults().clear();
-  m_d->setSearchType( LdapModelPrivate::ChildObjects, parentItem );
-  m_d->search( parentItem->data().dn(), LdapUrl::One, QString(),
-               QStringList() << "dn" << "objectClass" );
-  parentItem->setPopulated( true );
+  m_d->setSearchType( LdapModelPrivate::ChildObjects, parentNode );
+  m_d->search( parentNode->dn(),  // DN to search from
+               LdapUrl::One,      // What to search
+               QString() );       // Attributes to retrieve
+  parentNode->setPopulated( true );
 }
 
+bool LdapModel::hasChildrenOfType( const QModelIndex &parent, LdapDataType type ) \
const +{
+  // Map from LdapDataType to our internal NodeType
+  LdapModelNode::NodeType nodeType;
+  switch ( type ) {
+    case Attribute:
+      nodeType = LdapModelNode::Attr;
+      break;
+
+    case DistinguishedName:
+    default:
+      nodeType = LdapModelNode::DN;
+      break;
+  }
+
+  const LdapModelNode *node = parent.isValid()
+    ? static_cast<const LdapModelNode*>( parent.internalPointer() )
+    : m_d->rootNode();
+
+  const LdapModelDNNode* parentNode = static_cast<const LdapModelDNNode*>( node );
+  if ( !parent.isValid() || parentNode->isPopulated() ) {
+    // Check to see if the parent has any children of the specified type
+    const QList<LdapModelNode*>& children = parentNode->children();
+    foreach ( LdapModelNode *child, children ) {
+      if ( child->nodeType() == nodeType ) {
+        return true;
+      }
+    }
+
+    // Either there are no children or only children of a different type
+    return false;
+  }
+
+  // If the node is not populated or is the root node (invalid), then return
+  // true to be on the safe side.
+  return true;
+}
+
 #include "ldapmodel.moc"
Index: kldap/ldapmodeltreeitem_p.h
===================================================================
--- kldap/ldapmodeltreeitem_p.h	(revision 728366)
+++ kldap/ldapmodeltreeitem_p.h	(working copy)
@@ -1,66 +0,0 @@
-/*
-  This file is part of libkldap.
-  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
-
-  This library 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 of the License, or (at your option) any later version.
-
-  This library 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 library; see the file COPYING.LIB.  If not, write to
-  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-  Boston, MA 02110-1301, USA.
-*/
-
-#ifndef KLDAP_LDAPMODELTREEITEM_P_H
-#define KLDAP_LDAPMODELTREEITEM_P_H
-
-#include <QtCore/QList>
-#include <QtCore/QVariant>
-
-#include "ldapobject.h"
-#include "kldap_export.h"
-
-namespace KLDAP {
-
-/**
- * @internal
- */
-class LdapModelTreeItem
-{
-  public:
-    explicit LdapModelTreeItem( LdapModelTreeItem *parent = 0,
-                                const LdapObject &data = LdapObject() );
-    ~LdapModelTreeItem();
-
-    void appendChild( LdapModelTreeItem *pItem );
-    LdapModelTreeItem *child( int row );
-    LdapModelTreeItem *parent();
-    int childCount() const;
-    int columnCount() const;
-    const LdapObject &data() const;
-    int row() const;
-
-    LdapObject &ldapObject();
-    const LdapObject &ldapObject() const;
-    void setLdapObject( const LdapObject &object );
-
-    void setPopulated( bool b ) { m_isPopulated = b; }
-    bool isPopulated() const { return m_isPopulated; }
-
-  private:
-    QList<LdapModelTreeItem*> m_childItems;
-    LdapModelTreeItem *m_parent;
-    LdapObject m_itemData;
-    bool m_isPopulated;
-};
-
-}
-
-#endif
Index: kldap/ldapstructureproxymodel.cpp
===================================================================
--- kldap/ldapstructureproxymodel.cpp	(revision 0)
+++ kldap/ldapstructureproxymodel.cpp	(revision 0)
@@ -0,0 +1,103 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library 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 of the License, or (at your option) any later version.
+
+  This library 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 library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapstructureproxymodel.h"
+#include "ldapmodel.h"
+#include "ldapmodelnode_p.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+
+using namespace KLDAP;
+
+class LdapStructureProxyModel::LdapStructureProxyModelPrivate
+{
+  public:
+    LdapStructureProxyModelPrivate();
+
+};
+
+LdapStructureProxyModel::LdapStructureProxyModelPrivate::LdapStructureProxyModelPrivate()
 +{
+
+}
+
+LdapStructureProxyModel::LdapStructureProxyModel( QObject *parent )
+  : QSortFilterProxyModel( parent ),
+    m_d( new LdapStructureProxyModelPrivate() )
+{
+
+}
+
+LdapStructureProxyModel::~LdapStructureProxyModel()
+{
+  delete m_d;
+}
+
+QVariant LdapStructureProxyModel::data( const QModelIndex &index,
+                                        int role ) const
+{
+  // Included just in case we decide to do any special presentation of the data
+  // at some other point throughout the 4.x series.
+  return sourceModel()->data( mapToSource( index ), role );
+}
+
+bool LdapStructureProxyModel::filterAcceptsRow( int sourceRow,
+                                                const QModelIndex& sourceParent ) \
const +{
+  QModelIndex idx = sourceModel()->index( sourceRow, 0, sourceParent );
+  LdapModelNode::NodeType nodeType =
+    static_cast<LdapModelNode::NodeType>(
+      sourceModel()->data( idx, LdapModel::NodeTypeRole ).toUInt() );
+  return ( nodeType == LdapModelNode::DN );
+}
+
+QVariant LdapStructureProxyModel::headerData( int /*section*/,
+                                              Qt::Orientation orientation,
+                                              int role ) const
+{
+  if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) {
+    return QString( i18n( "Distinguished Name" ) );
+  }
+
+  return QVariant();
+}
+
+int LdapStructureProxyModel::columnCount( const QModelIndex &/*parent*/ ) const
+{
+  // No need for more than one column just to show the structure
+  return 1;
+}
+
+Qt::ItemFlags LdapStructureProxyModel::flags( const QModelIndex &index ) const
+{
+  // Included so as not to break BC in case we wish to use this later in 4.x
+  return sourceModel()->flags( mapToSource( index ) );
+}
+
+bool LdapStructureProxyModel::hasChildren( const QModelIndex &parent ) const
+{
+  // We need to handle this carefully bacause of the filtering out of attributes
+  // and the lazy population approach.
+  LdapModel *model = static_cast<LdapModel*>( sourceModel() );
+  return model->hasChildrenOfType( mapToSource( parent ), \
LdapModel::DistinguishedName ); +}
+
+#include "ldapstructureproxymodel.moc"
Index: kldap/ldapmodel_p.h
===================================================================
--- kldap/ldapmodel_p.h	(revision 728366)
+++ kldap/ldapmodel_p.h	(working copy)
@@ -28,7 +28,7 @@
 
 namespace KLDAP {
 
-class LdapModelTreeItem;
+class LdapModelDNNode;
 class LdapSearch;
 
 /**
@@ -57,7 +57,7 @@
                  const QStringList &attributes = QStringList(),
                  int pagesize = 0 );
 
-    LdapModelTreeItem *rootItem() { return m_root; }
+    LdapModelDNNode *rootNode() { return m_root; }
     LdapSearch *search() { return m_search; }
 
     LdapObjects &searchResults() { return m_searchResultObjects; }
@@ -69,10 +69,10 @@
     LdapDN &baseDN() { return m_baseDN; }
     const LdapDN &baseDN() const { return m_baseDN; }
 
-    void setSearchType( SearchType t, LdapModelTreeItem *item = 0 );
+    void setSearchType( SearchType t, LdapModelDNNode *item = 0 );
 
     SearchType searchType() { return m_searchType; }
-    LdapModelTreeItem *searchItem() { return m_searchItem; }
+    LdapModelDNNode *searchItem() { return m_searchItem; }
 
     void createConnections();
     void populateRootToBaseDN();
@@ -81,12 +81,12 @@
 
   private:
     LdapModel *m_parent;
-    LdapModelTreeItem *m_root;
+    LdapModelDNNode *m_root;
     LdapSearch *m_search;
     LdapObjects m_searchResultObjects;
     LdapDN m_baseDN;
     SearchType m_searchType;
-    LdapModelTreeItem *m_searchItem;
+    LdapModelDNNode *m_searchItem;
 };
 
 }
Index: kldap/ldapmodelnode_p.cpp
===================================================================
--- kldap/ldapmodelnode_p.cpp	(revision 0)
+++ kldap/ldapmodelnode_p.cpp	(revision 0)
@@ -0,0 +1,134 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library 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 of the License, or (at your option) any later version.
+
+  This library 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 library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapmodelnode_p.h"
+
+#include <kdebug.h>
+
+using namespace KLDAP;
+
+LdapModelNode::LdapModelNode( LdapModelDNNode *parent )
+  : m_parent( parent ),
+    m_isPopulated( false )
+{
+  if ( m_parent ) {
+    m_parent->appendChild( this );
+  }
+}
+
+LdapModelNode::~LdapModelNode()
+{
+
+}
+
+LdapModelDNNode *LdapModelNode::parent()
+{
+  return m_parent;
+}
+
+int LdapModelNode::row() const
+{
+  if ( m_parent ) {
+    return m_parent->children().indexOf( const_cast<LdapModelNode*>( this ) );
+  }
+  return 0;
+}
+
+
+//
+// LdapModelDNNode imlpementation
+//
+
+LdapModelDNNode::LdapModelDNNode( LdapModelDNNode *parent,
+                                  const LdapDN &dn )
+  : LdapModelNode( parent ),
+    m_childItems(),
+    m_dn( dn )
+{
+  kDebug(5322) << "Creating LdapModelDNNode: DN =" << m_dn.toString();
+}
+
+LdapModelDNNode::~LdapModelDNNode()
+{
+  qDeleteAll( m_childItems );
+}
+
+void LdapModelDNNode::appendChild( LdapModelNode *pItem )
+{
+  m_childItems.append( pItem );
+  setPopulated( true );
+}
+
+LdapModelNode *LdapModelDNNode::child( int row )
+{
+  return m_childItems.value( row );
+}
+
+void LdapModelDNNode::setLdapObject( const LdapObject &object )
+{
+  // Remember whether this item is populated or not
+  bool populated = isPopulated();
+
+  const LdapAttrMap &attrs = object.attributes();
+  /*
+  int attributeCount = 0;
+  for ( LdapAttrMap::ConstIterator it = attrs.begin(); it != attrs.end(); ++it ) {
+    attributeCount += (*it).size();
+  }
+
+  for ( int i = 0; i < attributeCount; i++ )
+  {
+    LdapModelNode* node = new LdapModelAttrNode( this, QString::number( i ) );
+    Q_UNUSED( node );
+  }
+  */
+
+  for ( LdapAttrMap::ConstIterator it = attrs.begin(); it != attrs.end(); ++it ) {
+    QString attr = it.key();
+    for ( LdapAttrValue::ConstIterator it2 = (*it).begin(); it2 != (*it).end(); \
++it2 ) { +      LdapModelNode* node = new LdapModelAttrNode( this, attr, *it2 );
+      Q_UNUSED( node );
+    }
+  }
+
+  // Reset the populated flag so that we don't stop the model querying for children
+  setPopulated( populated );
+}
+
+
+//
+// LdapModelAttrNode imlpementation
+//
+
+LdapModelAttrNode::LdapModelAttrNode( LdapModelDNNode *parent,
+                                      const QString &attrName,
+                                      const QByteArray &attrData )
+  : LdapModelNode( parent ),
+    m_attrName( attrName ),
+    m_attrData( attrData )
+{
+  kDebug(5322) << "Creating LdapModelAttrNode: Name =" << m_attrName
+               << " Data =" << m_attrData;
+}
+
+LdapModelAttrNode::~LdapModelAttrNode()
+{
+
+}
Index: kldap/ldapattributeproxymodel.cpp
===================================================================
--- kldap/ldapattributeproxymodel.cpp	(revision 0)
+++ kldap/ldapattributeproxymodel.cpp	(revision 0)
@@ -0,0 +1,106 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library 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 of the License, or (at your option) any later version.
+
+  This library 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 library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapattributeproxymodel.h"
+#include "ldapmodel.h"
+#include "ldapmodelnode_p.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+
+using namespace KLDAP;
+
+class LdapAttributeProxyModel::LdapAttributeProxyModelPrivate
+{
+  public:
+    LdapAttributeProxyModelPrivate();
+
+};
+
+LdapAttributeProxyModel::LdapAttributeProxyModelPrivate::LdapAttributeProxyModelPrivate()
 +{
+
+}
+
+LdapAttributeProxyModel::LdapAttributeProxyModel( QObject *parent )
+  : QSortFilterProxyModel( parent ),
+    m_d( new LdapAttributeProxyModelPrivate() )
+{
+
+}
+
+LdapAttributeProxyModel::~LdapAttributeProxyModel()
+{
+  delete m_d;
+}
+
+QVariant LdapAttributeProxyModel::data( const QModelIndex &index,
+                                        int role ) const
+{
+  // Included just in case we decide to do any special presentation of the data
+  // at some other point throughout the 4.x series.
+  return sourceModel()->data( mapToSource( index ), role );
+}
+
+bool LdapAttributeProxyModel::filterAcceptsRow( int sourceRow,
+                                                const QModelIndex& sourceParent ) \
const +{
+  QModelIndex idx = sourceModel()->index( sourceRow, 0, sourceParent );
+  LdapModelNode::NodeType nodeType =
+    static_cast<LdapModelNode::NodeType>(
+      sourceModel()->data( idx, LdapModel::NodeTypeRole ).toUInt() );
+  return ( nodeType == LdapModelNode::Attr );
+}
+
+QVariant LdapAttributeProxyModel::headerData( int section,
+                                              Qt::Orientation orientation,
+                                              int role ) const
+{
+  if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) {
+    if ( section == 0 ) {
+      return QVariant( QString( i18n( "Attribute" ) ) );
+    } else if ( section == 1 ) {
+      return QVariant( QString( i18n( "Value" ) ) );
+    }
+  }
+
+  return QVariant();
+}
+
+int LdapAttributeProxyModel::columnCount( const QModelIndex &/*parent*/ ) const
+{
+  return 2;
+}
+
+Qt::ItemFlags LdapAttributeProxyModel::flags( const QModelIndex &index ) const
+{
+  // Included so as not to break BC in case we wish to use this later in 4.x
+  return sourceModel()->flags( mapToSource( index ) );
+}
+
+bool LdapAttributeProxyModel::hasChildren( const QModelIndex &parent ) const
+{
+  // We need to handle this carefully bacause of the filtering out of attributes
+  // and the lazy population approach.
+  LdapModel *model = static_cast<LdapModel*>( sourceModel() );
+  return model->hasChildrenOfType( mapToSource( parent ), LdapModel::Attribute );
+}
+
+#include "ldapattributeproxymodel.moc"



_______________________________________________
KDE PIM mailing list kde-pim@kde.org
https://mail.kde.org/mailman/listinfo/kde-pim
KDE PIM home page at http://pim.kde.org/

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic