<commit_before>/*
    Copyright (c) 2007 <NAME> <<EMAIL>>

    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 "contactgroupeditor.h"

#include <QtGui/QGridLayout>
#include <QtGui/QMessageBox>

#include <kabc/addressee.h>
#include <kabc/contactgroup.h>
#include <klocale.h>
#include <klineedit.h>
#include <kmessagebox.h>
#include <akonadi/itemcreatejob.h>
#include <akonadi/itemfetchjob.h>
#include <akonadi/itemfetchscope.h>
#include <akonadi/itemmodifyjob.h>
#include <akonadi/monitor.h>
#include <akonadi/session.h>

#include "contactcompletionmodel_p.h"
#include "contactgrouplineedit_p.h"
#include "ui_contactgroupeditor.h"
#include "waitingoverlay_p.h"

namespace Akonadi
{

class ContactGroupEditor::Private
{
  public:
    Private( ContactGroupEditor *parent )
      : mParent( parent ), mMonitor( 0 ), mCompletionModel( 0 ), mReadOnly( false )
    {
      mCompletionModel = ContactCompletionModel::self();
    }

    ~Private()
    {
      delete mMonitor;
    }

    void fetchDone( KJob* );
    void storeDone( KJob* );
    void itemChanged( const Akonadi::Item &item, const QSet<QByteArray>& );
    void memberChanged();
    void setReadOnly( bool );

    void loadContactGroup( const KABC::ContactGroup &group );
    bool storeContactGroup( KABC::ContactGroup &group );
    void setupMonitor();
    ContactGroupLineEdit* addMemberEdit();

    ContactGroupEditor *mParent;
    ContactGroupEditor::Mode mMode;
    Item mItem;
    Monitor *mMonitor;
    Collection mDefaultCollection;
    Ui::ContactGroupEditor mGui;
    QVBoxLayout *mMembersLayout;
    QList<ContactGroupLineEdit*> mMembers;
    QAbstractItemModel *mCompletionModel;
    bool mReadOnly;
};

}

using namespace Akonadi;

void ContactGroupEditor::Private::fetchDone( KJob *job )
{
  if ( job->error() )
    return;

  ItemFetchJob *fetchJob = qobject_cast<ItemFetchJob*>( job );
  if ( !fetchJob )
    return;

  if ( fetchJob->items().isEmpty() )
    return;

  mItem = fetchJob->items().first();

  if ( mMode == ContactGroupEditor::EditMode ) {
    mReadOnly = false;

    const Akonadi::Collection parentCollection = mItem.parentCollection();
    if ( parentCollection.isValid() )
      mReadOnly = !(parentCollection.rights() & Collection::CanChangeItem);
  }

  const KABC::ContactGroup group = mItem.payload<KABC::ContactGroup>();
  loadContactGroup( group );

  setReadOnly( mReadOnly );
}

void ContactGroupEditor::Private::storeDone( KJob *job )
{
  if ( job->error() ) {
    emit mParent->error( job->errorString() );
    return;
  }

  if ( mMode == EditMode )
    emit mParent->contactGroupStored( mItem );
  else if ( mMode == CreateMode )
    emit mParent->contactGroupStored( static_cast<ItemCreateJob*>( job )->item() );
}

void ContactGroupEditor::Private::itemChanged( const Item&, const QSet<QByteArray>& )
{
  QMessageBox dlg( mParent );

  dlg.setInformativeText( QLatin1String( "The contact group has been changed by anyone else\nWhat shall be done?" ) );
  dlg.addButton( i18n( "Take over changes" ), QMessageBox::AcceptRole );
  dlg.addButton( i18n( "Ignore and Overwrite changes" ), QMessageBox::RejectRole );

  if ( dlg.exec() == QMessageBox::AcceptRole ) {
    ItemFetchJob *job = new ItemFetchJob( mItem );
    job->fetchScope().fetchFullPayload();
    job->fetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent );

    mParent->connect( job, SIGNAL( result( KJob* ) ), mParent, SLOT( fetchDone( KJob* ) ) );
    new WaitingOverlay( job, mParent );
  }
}

void ContactGroupEditor::Private::loadContactGroup( const KABC::ContactGroup &group )
{
  mGui.groupName->setText( group.name() );

  qDeleteAll( mMembers );
  for ( unsigned int i = 0; i < group.dataCount(); ++i ) {
    const KABC::ContactGroup::Data data = group.data( i );
    ContactGroupLineEdit *lineEdit = addMemberEdit();

    mParent->disconnect( lineEdit, SIGNAL( textChanged( const QString& ) ), mParent, SLOT( memberChanged() ) );
    lineEdit->setContactData( data );
    mParent->connect( lineEdit, SIGNAL( textChanged( const QString& ) ), SLOT( memberChanged() ) );
  }

  for ( unsigned int i = 0; i < group.contactReferenceCount(); ++i ) {
    const KABC::ContactGroup::ContactReference reference = group.contactReference( i );
    ContactGroupLineEdit *lineEdit = addMemberEdit();

    mParent->disconnect( lineEdit, SIGNAL( textChanged( const QString& ) ), mParent, SLOT( memberChanged() ) );
    lineEdit->setContactReference( reference );
    mParent->connect( lineEdit, SIGNAL( textChanged( const QString& ) ), SLOT( memberChanged() ) );
  }

  addMemberEdit();
}

bool ContactGroupEditor::Private::storeContactGroup( KABC::ContactGroup &group )
{
  if ( mGui.groupName->text().isEmpty() ) {
    KMessageBox::error( mParent, i18n( "The name of the contact group must not be empty." ) );
    return false;
  }

  group.setName( mGui.groupName->text() );

  group.removeAllContactData();
  group.removeAllContactReferences();

  // Iterate over all members except the last one, as this is always empty anyway
  for ( int i = 0; i < (mMembers.count() - 1); ++i ) {
    if ( mMembers.at( i )->containsReference() ) {
      const KABC::ContactGroup::ContactReference reference = mMembers.at( i )->contactReference();
      if ( !(reference == KABC::ContactGroup::ContactReference()) )
        group.append( reference );
    } else {
      const KABC::ContactGroup::Data data = mMembers.at( i )->contactData();
      if ( data == KABC::ContactGroup::Data() ) {
        const QString text = mMembers.at( i )->text();

        QString fullName, email;
        KABC::Addressee::parseEmailAddress( text, fullName, email );

        if ( fullName.isEmpty() ) {
          KMessageBox::error( mParent, i18n( "The contact '%1' is missing a name.", text ) );
          return false;<commit_msg>Allow to remove contacts from the middle of the contact group editor.<commit_after>/*
    Copyright (c) 2007 <NAME> <<EMAIL>>

    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 "contactgroupeditor.h"

#include <QtGui/QGridLayout>
#include <QtGui/QMessageBox>

#include <kabc/addressee.h>
#include <kabc/contactgroup.h>
#include <klocale.h>
#include <klineedit.h>
#include <kmessagebox.h>
#include <akonadi/itemcreatejob.h>
#include <akonadi/itemfetchjob.h>
#include <akonadi/itemfetchscope.h>
#include <akonadi/itemmodifyjob.h>
#include <akonadi/monitor.h>
#include <akonadi/session.h>

#include "contactcompletionmodel_p.h"
#include "contactgrouplineedit_p.h"
#include "ui_contactgroupeditor.h"
#include "waitingoverlay_p.h"

namespace Akonadi
{

class ContactGroupEditor::Private
{
  public:
    Private( ContactGroupEditor *parent )
      : mParent( parent ), mMonitor( 0 ), mCompletionModel( 0 ), mReadOnly( false )
    {
      mCompletionModel = ContactCompletionModel::self();
    }

    ~Private()
    {
      delete mMonitor;
    }

    void fetchDone( KJob* );
    void storeDone( KJob* );
    void itemChanged( const Akonadi::Item &item, const QSet<QByteArray>& );
    void memberChanged();
    void setReadOnly( bool );

    void loadContactGroup( const KABC::ContactGroup &group );
    bool storeContactGroup( KABC::ContactGroup &group );
    void setupMonitor();
    ContactGroupLineEdit* addMemberEdit();

    ContactGroupEditor *mParent;
    ContactGroupEditor::Mode mMode;
    Item mItem;
    Monitor *mMonitor;
    Collection mDefaultCollection;
    Ui::ContactGroupEditor mGui;
    QVBoxLayout *mMembersLayout;
    QList<ContactGroupLineEdit*> mMembers;
    QAbstractItemModel *mCompletionModel;
    bool mReadOnly;
};

}

using namespace Akonadi;

void ContactGroupEditor::Private::fetchDone( KJob *job )
{
  if ( job->error() )
    return;

  ItemFetchJob *fetchJob = qobject_cast<ItemFetchJob*>( job );
  if ( !fetchJob )
    return;

  if ( fetchJob->items().isEmpty() )
    return;

  mItem = fetchJob->items().first();

  if ( mMode == ContactGroupEditor::EditMode ) {
    mReadOnly = false;

    const Akonadi::Collection parentCollection = mItem.parentCollection();
    if ( parentCollection.isValid() )
      mReadOnly = !(parentCollection.rights() & Collection::CanChangeItem);
  }

  const KABC::ContactGroup group = mItem.payload<KABC::ContactGroup>();
  loadContactGroup( group );

  setReadOnly( mReadOnly );
}

void ContactGroupEditor::Private::storeDone( KJob *job )
{
  if ( job->error() ) {
    emit mParent->error( job->errorString() );
    return;
  }

  if ( mMode == EditMode )
    emit mParent->contactGroupStored( mItem );
  else if ( mMode == CreateMode )
    emit mParent->contactGroupStored( static_cast<ItemCreateJob*>( job )->item() );
}

void ContactGroupEditor::Private::itemChanged( const Item&, const QSet<QByteArray>& )
{
  QMessageBox dlg( mParent );

  dlg.setInformativeText( QLatin1String( "The contact group has been changed by anyone else\nWhat shall be done?" ) );
  dlg.addButton( i18n( "Take over changes" ), QMessageBox::AcceptRole );
  dlg.addButton( i18n( "Ignore and Overwrite changes" ), QMessageBox::RejectRole );

  if ( dlg.exec() == QMessageBox::AcceptRole ) {
    ItemFetchJob *job = new ItemFetchJob( mItem );
    job->fetchScope().fetchFullPayload();
    job->fetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent );

    mParent->connect( job, SIGNAL( result( KJob* ) ), mParent, SLOT( fetchDone( KJob* ) ) );
    new WaitingOverlay( job, mParent );
  }
}

void ContactGroupEditor::Private::loadContactGroup( const KABC::ContactGroup &group )
{
  mGui.groupName->setText( group.name() );

  qDeleteAll( mMembers );
  for ( unsigned int i = 0; i < group.dataCount(); ++i ) {
    const KABC::ContactGroup::Data data = group.data( i );
    ContactGroupLineEdit *lineEdit = addMemberEdit();

    mParent->disconnect( lineEdit, SIGNAL( textChanged( const QString& ) ), mParent, SLOT( memberChanged() ) );
    lineEdit->setContactData( data );
    mParent->connect( lineEdit, SIGNAL( textChanged( const QString& ) ), SLOT( memberChanged() ) );
  }

  for ( unsigned int i = 0; i < group.contactReferenceCount(); ++i ) {
    const KABC::ContactGroup::ContactReference reference = group.contactReference( i );
    ContactGroupLineEdit *lineEdit = addMemberEdit();

    mParent->disconnect( lineEdit, SIGNAL( textChanged( const QString& ) ), mParent, SLOT( memberChanged() ) );
    lineEdit->setContactReference( reference );
    mParent->connect( lineEdit, SIGNAL( textChanged( const QString& ) ), SLOT( memberChanged() ) );
  }

  addMemberEdit();
}

bool ContactGroupEditor::Private::storeContactGroup( KABC::ContactGroup &group )
{
  if ( mGui.groupName->text().isEmpty() ) {
    KMessageBox::error( mParent, i18n( "The name of the contact group must not be empty." ) );
    return false;
  }

  group.setName( mGui.groupName->text() );

  group.removeAllContactData();
  group.removeAllContactReferences();

  // Iterate over all members except the last one, as this is always empty anyway
  for ( int i = 0; i < (mMembers.count() - 1); ++i ) {
    if ( mMembers.at( i )->containsReference() ) {
      const KABC::ContactGroup::ContactReference reference = mMembers.at( i )->contactReference();
      if ( !(reference == KABC::ContactGroup::ContactReference()) )
        group.append( reference );
    } else {
      const KABC::ContactGroup::Data data = mMembers.at( i )->contactData();
      if ( data == KABC::ContactGroup::Data() ) {
        const QString text = mMembers.at( i )->text();

        if ( text.simplified().isEmpty() ) // we handle empty members as 'to be removed'
          continue;

        QString fullName, email;
        KABC::Addressee::parseEmailAddress( text, fullName, email );

        if ( fullName.isEmpty() ) {
          KMessageBox::error( mParent, i18n( "The contact '%1' is missing a name.", text ) );
          return false;
{'fraction_non_alphanumeric': 0.12388308344691806, 'fraction_numerical': 0.00484628199303347, 'mean_word_length': 3.995083207261725, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 97, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7542498', 'n_tokens_mistral': 4091, 'n_tokens_neox': 3981, 'n_words': 1107}