Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
profilemodel.cpp 24.02 KiB
/****************************************************************************
 *   Copyright (C) 2013-2014 by Savoir-Faire Linux                          *
 *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
 *                                                                          *
 *   This library is free software; you can redistribute it and/or          *
 *   modify it under the terms of the GNU Lesser General Public             *
 *   License as published by the Free Software Foundation; either           *
 *   version 2.1 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      *
 *   Lesser General Public License for more details.                        *
 *                                                                          *
 *   You should have received a copy of the GNU General Public License      *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
 ***************************************************************************/
#include "profilemodel.h"

//Qt
#include <QtCore/QTimer>
#include <QtCore/QObject>
#include <QtCore/QUrl>
#include <QMimeData>
#include <QtCore/QCoreApplication>
#include <QtCore/QPointer>

//SFLPhone library
#include "accountmodel.h"
#include "collectioninterface.h"
#include "collectioneditor.h"
#include "personmodel.h"
#include "callmodel.h"
#include "person.h"
#include "delegates/profilepersisterdelegate.h"
#include "delegates/pixmapmanipulationdelegate.h"
#include "vcardutils.h"
#include "mime.h"

//Qt
class QObject;

//SFLPhone
class Person;
class Account;
struct Node;

class ProfileEditor : public CollectionEditor<Person>
{
public:
   ProfileEditor(CollectionMediator<Person>* m) : CollectionEditor<Person>(m) {};
   ~ProfileEditor();
   virtual bool save       ( const Person* item ) override;
   virtual bool remove     ( const Person* item ) override;
   virtual bool edit       (       Person* item ) override;
   virtual bool addNew     ( const Person* item ) override;
   virtual bool addExisting( const Person* item ) override;

   Node* getProfileById(const QByteArray& id);
   QList<Account*> getAccountsForProfile(const QString& id);
   QList<Node*> m_lProfiles;
   QHash<QByteArray,Node*> m_hProfileByAccountId;
   QVector<Person*> m_lProfilePersons;

private:
   virtual QVector<Person*> items() const override;
};

///ProfileContentBackend: Implement a backend for Profiles
class ProfileContentBackend : public QObject, public CollectionInterface {
   Q_OBJECT
public:
   template<typename T>
   explicit ProfileContentBackend(CollectionMediator<T>* mediator);
   virtual ~ProfileContentBackend ();

   //Re-implementation
   virtual QString  name              (             ) const override;
   virtual QString  category          (             ) const override;
   virtual QVariant icon              (             ) const override;
   virtual bool     isEnabled         (             ) const override;
   virtual bool     enable            ( bool enable )       override;
   virtual QByteArray  id             (             ) const override;
   virtual bool     load              (             )       override;
   virtual bool     reload            (             )       override;
   SupportedFeatures supportedFeatures(             ) const override;

   //Attributes
   bool m_needSaving;

   QList<Person*> m_bSaveBuffer;
   bool saveAll();

   Node* m_pDefault;
   ProfileEditor* m_pEditor;

   //Helper
   void  setupDefaultProfile();
   void  addAccount(Node* parent, Account* acc);

public Q_SLOTS:
   void contactChanged();
   void save();
   void loadProfiles();
};


struct Node {
   Node(): account(nullptr),contact(nullptr),type(Node::Type::PROFILE), parent(nullptr),m_Index(0) {}

   enum class Type : bool {
      PROFILE,
      ACCOUNT,
   };

   Node*           parent;
   QVector<Node*>  children;
   Type            type;
   Account*        account;
   Person*        contact;
   int             m_Index;
};

bool ProfileEditor::save(const Person* contact)
{
   QDir profilesDir = ProfilePersisterDelegate::instance()->getProfilesDir();
   qDebug() << "Saving vcf in:" << profilesDir.absolutePath()+"/"+contact->uid()+".vcf";
   const QByteArray result = contact->toVCard(getAccountsForProfile(contact->uid()));

   QFile file(profilesDir.absolutePath()+"/"+contact->uid()+".vcf");
   file.open(QIODevice::WriteOnly);
   file.write(result);
   file.close();
   return true;
}

ProfileEditor::~ProfileEditor()
{
   while (m_lProfiles.size()) {
      Node* c = m_lProfiles[0];
      m_lProfiles.removeAt(0);
      delete c;
   }
}

bool ProfileEditor::remove(const Person* item)
{
   Q_UNUSED(item)
   mediator()->removeItem(item);
   return false;
}

bool ProfileEditor::edit( Person* contact)
{
   qDebug() << "Attempt to edit a profile contact" << contact->uid();
   return false;
}

bool ProfileEditor::addNew(const Person* contact)
{
   qDebug() << "Creating new profile" << contact->uid();
   m_lProfilePersons << const_cast<Person*>(contact);
   mediator()->addItem(contact);
   save(contact);
//    load(); //FIXME
   return true;
}

bool ProfileEditor::addExisting(const Person* contact)
{
   m_lProfilePersons << const_cast<Person*>(contact);
   mediator()->addItem(contact);
   return true;
}

QVector<Person*> ProfileEditor::items() const
{
   return m_lProfilePersons;
}



ProfileModel* ProfileModel::m_spInstance = nullptr;

template<typename T>
ProfileContentBackend::ProfileContentBackend(CollectionMediator<T>* mediator) :
  CollectionInterface(new ProfileEditor(mediator),nullptr), m_pDefault(nullptr),
  m_needSaving(false)
{
   m_pEditor = static_cast<ProfileEditor*>(editor<Person>());
}

QString ProfileContentBackend::name () const
{
   return tr("Profile backend");
}

QString ProfileContentBackend::category () const
{
   return tr("Profile");
}

QVariant ProfileContentBackend::icon() const
{
   return QVariant();
}

bool ProfileContentBackend::isEnabled() const
{
   return true;
}

bool ProfileContentBackend::enable (bool enable)
{
   Q_UNUSED(enable);
   static bool isLoaded = false;
   if (!isLoaded) {
     load();
     isLoaded = true;
   }
   return true;
}

QByteArray  ProfileContentBackend::id() const
{
   return "Profile_backend";
}

// bool ProfileContentBackend::edit( Person* contact )
// {
//    qDebug() << "Attempt to edit a profile contact" << contact->uid();
//    return false;
// }

// bool ProfileContentBackend::addNew( Person* contact )
// {
//    qDebug() << "Creating new profile" << contact->uid();
//    save(contact);
//    load();
//    return true;
// }

// bool ProfileContentBackend::remove( Person* c )
// {
//    Q_UNUSED(c)
//    return false;
// }

// bool ProfileContentBackend::append(const Person* item)
// {
//    Q_UNUSED(item)
//    return false;
// }

ProfileContentBackend::~ProfileContentBackend( )
{

}

void ProfileContentBackend::setupDefaultProfile()
{

   QHash<Account*,bool> accounts;
   QList<Account*> orphans;

   //Ugly reverse mapping, but we want to keep the profile concept
   //hidden as low as possible for now
   //TODO remove this atrocity when the profile before available in Account::
   //BUG this doesn't work with new accounts
   for (int i=0; i < AccountModel::instance()->size();i++) {
      accounts[(*AccountModel::instance())[i]] = false;
   }

   foreach (Node* node, m_pEditor->m_lProfiles) {
      foreach (Node* acc, node->children) {
         accounts[acc->account] = true;
      }
   }

   for (QHash<Account*,bool>::iterator i = accounts.begin(); i != accounts.end(); ++i) {
      if (i.value() == false) {
         orphans << i.key();
      }
   }
   qDebug() << "ORPHAN" << orphans.size() << m_pEditor << m_pEditor->m_lProfiles.size();

   if (orphans.size() && (!m_pDefault)) {
      qDebug() << "No profile found, creating one";
      Person* profile = new Person(this);
      m_pEditor->addNew(profile);
      profile->setFormattedName(tr("Default"));

      m_pDefault          = new Node           ;
      m_pDefault->type    = Node::Type::PROFILE;
      m_pDefault->contact = profile            ;
      m_pDefault->m_Index = m_pEditor->m_lProfiles.size() ;

      ProfileModel::instance()->beginInsertRows(QModelIndex(), m_pEditor->m_lProfiles.size(), m_pEditor->m_lProfiles.size());
      m_pEditor->m_lProfiles << m_pDefault;
      ProfileModel::instance()->endInsertRows();
   }

   foreach(Account* a, orphans) {
      addAccount(m_pDefault, a);
   }
}

void ProfileContentBackend::addAccount(Node* parent, Account* acc)
{
   qDebug() << "ADDING ACCOUNT" << acc->id();
   Node* account_pro = new Node;
   account_pro->type    = Node::Type::ACCOUNT;
   account_pro->contact = parent->contact;
   account_pro->parent  = parent;
   account_pro->account = acc;
   account_pro->m_Index = parent->children.size();

   ProfileModel::instance()->beginInsertRows(ProfileModel::instance()->index(parent->m_Index,0), parent->children.size(), parent->children.size());
   parent->children << account_pro;
   ProfileModel::instance()->endInsertRows();
   m_pEditor->m_hProfileByAccountId[acc->id()] = account_pro;
}


void ProfileContentBackend::loadProfiles()
{
   if (ProfilePersisterDelegate::instance()) {
      m_pEditor->m_lProfiles.clear();

      const QDir profilesDir = ProfilePersisterDelegate::instance()->getProfilesDir();

      qDebug() << "Loading vcf from:" << profilesDir;

      QStringList entries = profilesDir.entryList({"*.vcf"}, QDir::Files);

      foreach (const QString& item , entries) {

         Person* profile = new Person(this);

         Node* pro    = new Node           ;
         pro->type    = Node::Type::PROFILE;
         pro->contact = profile            ;
         pro->m_Index = m_pEditor->m_lProfiles.size() ;

         Account* acc = nullptr;
         VCardUtils::mapToPerson(profile,QUrl(item),&acc);
         if (acc)
            addAccount(pro,acc);

         ProfileModel::instance()->beginInsertRows(QModelIndex(), m_pEditor->m_lProfiles.size(), m_pEditor->m_lProfiles.size());
         m_pEditor->m_lProfiles << pro;
         ProfileModel::instance()->endInsertRows();

         connect(profile, SIGNAL(changed()), this, SLOT(contactChanged()));
         PersonModel::instance()->addPerson(profile);
      }

      //Ring need a profile for all account
      setupDefaultProfile();
   }
   else {
      qDebug() << "No ProfilePersistor loaded!";
   }
}

bool ProfileContentBackend::load()
{
   QTimer::singleShot(0,this,SLOT(loadProfiles()));
   return true;
}

bool ProfileContentBackend::reload()
{
   return false;
}

// bool ProfileContentBackend::save(const Person* contact)
// {
//    QDir profilesDir = ProfilePersisterDelegate::instance()->getProfilesDir();
//    qDebug() << "Saving vcf in:" << profilesDir.absolutePath()+"/"+contact->uid()+".vcf";
//    const QByteArray result = contact->toVCard(getAccountsForProfile(contact->uid()));
// 
//    QFile file(profilesDir.absolutePath()+"/"+contact->uid()+".vcf");
//    file.open(QIODevice::WriteOnly);
//    file.write(result);
//    file.close();
//    return true;
// }

bool ProfileContentBackend::saveAll()
{
   for(Node* pro : m_pEditor->m_lProfiles) {
      editor<Person>()->save(pro->contact);
   }
   return true;
}

ProfileContentBackend::SupportedFeatures ProfileContentBackend::supportedFeatures() const
{
   return (ProfileContentBackend::SupportedFeatures)(SupportedFeatures::NONE
      | SupportedFeatures::LOAD        //= 0x1 <<  0, /* Load this backend, DO NOT load anything before "load" is called         */
      | SupportedFeatures::EDIT        //= 0x1 <<  2, /* Edit, but **DOT NOT**, save an item)                                    */
      | SupportedFeatures::ADD         //= 0x1 <<  4, /* Add (and save) a new item to the backend                                */
      | SupportedFeatures::SAVE_ALL    //= 0x1 <<  5, /* Save all items at once, this may or may not be faster than "add"        */
      | SupportedFeatures::REMOVE      //= 0x1 <<  7, /* Remove a single item                                                    */
      | SupportedFeatures::ENABLEABLE  //= 0x1 << 10, /*Can be enabled, I know, it is not a word, but Java use it too            */
      | SupportedFeatures::MANAGEABLE);  //= 0x1 << 12, /* Can be managed the config GUI                                       */
      //TODO ^^ Remove that one once debugging is done
}

// bool ProfileContentBackend::addContactMethod( Person* contact , ContactMethod* number)
// {
//    Q_UNUSED(contact)
//    Q_UNUSED(number)
//    return false;
// }

// QList<Person*> ProfileContentBackend::items() const
// {
//    QList<Person*> contacts;
//    for (int var = 0; var < m_pEditor->m_lProfiles.size(); ++var) {
//       contacts << m_pEditor->m_lProfiles[var]->contact;
//    }
//    return contacts;
// }

QList<Account*> ProfileEditor::getAccountsForProfile(const QString& id)
{
   QList<Account*> result;
   Node* profile = getProfileById(id.toUtf8());
   if(!profile)
      return result;

   for (Node* child : profile->children) {
      result << child->account;
   }
   return result;
}

Node* ProfileEditor::getProfileById(const QByteArray& id)
{
   for (Node* p : m_lProfiles) {
      if(p->contact->uid() == id)
         return p;
   }
   return nullptr;
}

void ProfileContentBackend::contactChanged()
{
   Person* c = qobject_cast<Person*>(sender());
   qDebug() << c->formattedName();
   qDebug() << "contactChanged!";

   if(m_needSaving) {
      m_bSaveBuffer << c;
      QTimer::singleShot(0,this,SLOT(save()));
   }
   else
      m_needSaving = true;
}

void ProfileContentBackend::save()
{
   for (Person* item : m_bSaveBuffer) {
      qDebug() << "saving:" << item->formattedName();
      editor<Person>()->save(item);
   }

   m_bSaveBuffer.clear();
   m_needSaving = false;
   load();
}

ProfileModel* ProfileModel::instance()
{
   if (!m_spInstance)
      m_spInstance = new ProfileModel(QCoreApplication::instance());
   return m_spInstance;
}

class ProfileModelPrivate : public QObject {
   Q_OBJECT
public:
   ProfileModelPrivate(ProfileModel* parent);
   ProfileContentBackend*                 m_pProfileBackend;
   ProfilePersisterDelegate*               m_pDelegate   ;
   QStringList m_lMimes;

   //Helpers
   void updateIndexes();

private Q_SLOTS:
   void slotDataChanged(const QModelIndex& tl,const QModelIndex& br);
   void slotLayoutchanged();
   void slotDelayedInit();

private:
   ProfileModel* q_ptr;
};

ProfileModelPrivate::ProfileModelPrivate(ProfileModel* parent) : QObject(parent), q_ptr(parent),m_pProfileBackend(nullptr)
{

}

///Avoid creating an initialization loop
void ProfileModelPrivate::slotDelayedInit()
{
   connect(AccountModel::instance(),SIGNAL(dataChanged(QModelIndex,QModelIndex)),this,SLOT(slotDataChanged(QModelIndex,QModelIndex)));
   connect(AccountModel::instance(),SIGNAL(layoutChanged()),this,SLOT(slotLayoutchanged()));
}

ProfileModel::ProfileModel(QObject* parent) : QAbstractItemModel(parent), d_ptr(new ProfileModelPrivate(this))
{

   d_ptr->m_lMimes << RingMimes::PLAIN_TEXT << RingMimes::HTML_TEXT << RingMimes::ACCOUNT << RingMimes::PROFILE;

   //Creating the profile contact backend
   d_ptr->m_pProfileBackend = PersonModel::instance()->addCollection<ProfileContentBackend>(LoadOptions::FORCE_ENABLED);

   //Once LibRingClient is ready, start listening
   QTimer::singleShot(0,d_ptr,SLOT(slotDelayedInit()));
}

ProfileModel::~ProfileModel()
{
   delete d_ptr->m_pProfileBackend;
   delete d_ptr;
}

QHash<int,QByteArray> ProfileModel::roleNames() const
{
   static QHash<int, QByteArray> roles = AccountModel::instance()->roleNames();
   /*static bool initRoles = false;
   if (!initRoles) {
      initRoles = true;

   }*/
   return roles;
}

QModelIndex ProfileModel::mapToSource(const QModelIndex& idx) const
{
   if (!idx.isValid() || !idx.parent().isValid() || idx.model() != this)
      return QModelIndex();

   Node* profile = static_cast<Node*>(idx.parent().internalPointer());
   return profile->children[idx.row()]->account->index();
}

#include <unistd.h>
QModelIndex ProfileModel::mapFromSource(const QModelIndex& idx) const
{
   if (!idx.isValid() || idx.model() != AccountModel::instance())
      return QModelIndex();

   Account* acc = AccountModel::instance()->getAccountByModelIndex(idx);
   Node* pro = d_ptr->m_pProfileBackend->m_pEditor->m_hProfileByAccountId[acc->id()];
   //Something is wrong, there is an orphan
   if (!pro) {
      d_ptr->m_pProfileBackend->setupDefaultProfile();
      pro = d_ptr->m_pProfileBackend->m_pEditor->m_hProfileByAccountId[acc->id()];
   }

   return AccountModel::instance()->index(pro->m_Index,0,index(pro->parent->m_Index,0,QModelIndex()));
}

QVariant ProfileModel::data(const QModelIndex& index, int role ) const
{
   if (!index.isValid())
      return QVariant();

   Node* account_node = static_cast<Node*>(index.internalPointer());

   //Accounts
   if (account_node->account) {
      return account_node->account->roleData(role);
   }
   //Profiles
   else {
      switch (role) {
         case Qt::DisplayRole:
            return d_ptr->m_pProfileBackend->items<Person>()[index.row()]->formattedName();
      };
   }
   return QVariant();
}

int ProfileModel::rowCount(const QModelIndex& parent ) const
{
   if (parent.isValid()) {
      Node* account_node = static_cast<Node*>(parent.internalPointer());
      return (account_node->account)?0:account_node->children.size();
   }
   return d_ptr->m_pProfileBackend->items<Person>().size();
}

int ProfileModel::columnCount(const QModelIndex& parent ) const
{
   Q_UNUSED(parent)
   return 1;
}

QModelIndex ProfileModel::parent(const QModelIndex& idx ) const
{
   Node* current = static_cast<Node*>(idx.internalPointer());

   if (!current)
      return QModelIndex();
   switch (current->type) {
      case Node::Type::PROFILE:
         return QModelIndex();
      case Node::Type::ACCOUNT:
         return index(current->parent->m_Index, 0, QModelIndex());
   }
   return QModelIndex();
}

QModelIndex ProfileModel::index( int row, int column, const QModelIndex& parent ) const
{
   Node* current = static_cast<Node*>(parent.internalPointer());
   if(parent.isValid() && current && !column && row < current->children.size()) {
      return createIndex(row, 0, current->children[row]);
   }
   else if(row < d_ptr->m_pProfileBackend->m_pEditor->m_lProfiles.size() && !column) {
      return createIndex(row, 0, d_ptr->m_pProfileBackend->m_pEditor->m_lProfiles[row]);
   }
   return QModelIndex();
}

Qt::ItemFlags ProfileModel::flags(const QModelIndex& index ) const
{
   if (!index.isValid())
      return Qt::ItemIsEnabled;

   Node* current = static_cast<Node*>(index.internalPointer());

   if (current->parent)
      return QAbstractItemModel::flags(index)
              | Qt::ItemIsUserCheckable
              | Qt::ItemIsEnabled
              | Qt::ItemIsSelectable
              | Qt::ItemIsDragEnabled
              | Qt::ItemIsDropEnabled;

   return QAbstractItemModel::flags(index)
         | Qt::ItemIsEnabled
         | Qt::ItemIsSelectable
         | Qt::ItemIsDragEnabled
         | Qt::ItemIsDropEnabled;
}

QStringList ProfileModel::mimeTypes() const
{
   return d_ptr->m_lMimes;
}

QMimeData* ProfileModel::mimeData(const QModelIndexList &indexes) const
{
   QMimeData *mMimeData = new QMimeData();

   for (const QModelIndex &index : indexes) {
      Node* current = static_cast<Node*>(index.internalPointer());

      if (current && index.isValid() && current->parent) {
         mMimeData->setData(RingMimes::ACCOUNT , current->account->id());
      }
      else if (index.isValid() && current) {
        mMimeData->setData(RingMimes::PROFILE , current->contact->uid());
      }
      else
         return nullptr;
   }
   return mMimeData;
}

///Return valid payload types
int ProfileModel::acceptedPayloadTypes() const
{
   return CallModel::DropPayloadType::ACCOUNT;
}

void ProfileModelPrivate::updateIndexes()
{
   for (int i = 0; i < m_pProfileBackend->m_pEditor->m_lProfiles.size(); ++i) {
      m_pProfileBackend->m_pEditor->m_lProfiles[i]->m_Index = i;
      for (int j = 0; j < m_pProfileBackend->m_pEditor->m_lProfiles[i]->children.size(); ++j) {
         m_pProfileBackend->m_pEditor->m_lProfiles[i]->children[j]->m_Index = j;
      }
   }
}

bool ProfileModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
   Q_UNUSED(action)
   if((parent.isValid() && row < 0) || column > 0) {
      qDebug() << "row or column invalid";
      return false;
   }

   if (data->hasFormat(RingMimes::ACCOUNT)) {
      qDebug() << "dropping account";

      const QByteArray accountId = data->data(RingMimes::ACCOUNT);
      Node* newProfile = nullptr;
      int destIdx = 0, indexOfAccountToMove = -1; // Where to insert in account list of profile

      if(!parent.isValid() && row < d_ptr->m_pProfileBackend->m_pEditor->m_lProfiles.size()) {
         qDebug() << "Dropping on profile title";
         qDebug() << "row:" << row;
         newProfile = d_ptr->m_pProfileBackend->m_pEditor->m_lProfiles[row];
         destIdx = 0;
      }
      else if (parent.isValid()) {
         newProfile = static_cast<Node*>(parent.internalPointer());
         destIdx = row;
      }

      if (!newProfile)
         return false;

      Node* accountProfile = d_ptr->m_pProfileBackend->m_pEditor->m_hProfileByAccountId[accountId];
      for (Node* acc : accountProfile->children) {
         if(acc->account->id() == accountId) {
            indexOfAccountToMove = acc->m_Index;
            break;
         }
      }

      if(indexOfAccountToMove == -1) {
         qDebug() << "indexOfAccountToMove:" << indexOfAccountToMove;
         return false;
      }

      if(!beginMoveRows(index(accountProfile->m_Index, 0), indexOfAccountToMove, indexOfAccountToMove, parent, destIdx)) {
         return false;
      }

      Node* accountToMove = accountProfile->children.at(indexOfAccountToMove);
      qDebug() << "Moving:" << accountToMove->account->alias();
      accountProfile->children.remove(indexOfAccountToMove);
      accountToMove->parent = newProfile;
      d_ptr->m_pProfileBackend->m_pEditor->m_hProfileByAccountId[accountId] = newProfile;
      newProfile->children.insert(destIdx, accountToMove);
      d_ptr->updateIndexes();
      d_ptr->m_pProfileBackend->saveAll();
      endMoveRows();
   }
   else if (data->hasFormat(RingMimes::PROFILE)) {
      qDebug() << "dropping profile";
      qDebug() << "row:" << row;

      int destinationRow = -1;
      if(row < 0) {
         // drop on bottom of the list
         destinationRow = d_ptr->m_pProfileBackend->m_pEditor->m_lProfiles.size();
      }
      else {
         destinationRow = row;
      }

      Node* moving = d_ptr->m_pProfileBackend->m_pEditor->getProfileById(data->data(RingMimes::PROFILE));

      if(!beginMoveRows(QModelIndex(), moving->m_Index, moving->m_Index, QModelIndex(), destinationRow)) {
         return false;
      }

      d_ptr->m_pProfileBackend->m_pEditor->m_lProfiles.removeAt(moving->m_Index);
      d_ptr->m_pProfileBackend->m_pEditor->m_lProfiles.insert(destinationRow, moving);
      d_ptr->updateIndexes();
      endMoveRows();

      return true;
   }
   return false;
}

bool ProfileModel::setData(const QModelIndex& index, const QVariant &value, int role )
{
   if (!index.isValid())
      return false;

   Node* current = static_cast<Node*>(index.internalPointer());

   if (current->parent) {
      return AccountModel::instance()->setData(mapToSource(index),value,role);
   }
   return false;
}

QVariant ProfileModel::headerData(int section, Qt::Orientation orientation, int role ) const
{
   Q_UNUSED(section)
   Q_UNUSED(orientation)
   if (role == Qt::DisplayRole) return tr("Profiles");
   return QVariant();
}

// bool ProfileModel::addNewProfile(Person* c, CollectionInterface* backend)
// {
//    Q_UNUSED(backend);
//    return d_ptr->m_pProfileBackend->addNew(c);
// }

void ProfileModelPrivate::slotDataChanged(const QModelIndex& tl,const QModelIndex& br)
{
   Q_UNUSED(br)

   const QModelIndex& idx = q_ptr->mapFromSource(tl);

   emit q_ptr->dataChanged(idx,idx);
}

void ProfileModelPrivate::slotLayoutchanged()
{
   m_pProfileBackend->setupDefaultProfile();
   emit q_ptr->layoutChanged();
}

#include "profilemodel.moc"