Branch 'dev/resourcemanagement' - incidenceeditor-ng/attendeecomboboxdelegate.cpp incidenceeditor-ng/attendeecomboboxdelegate.h incidenceeditor-ng/CMakeLists.txt incidenceeditor-ng/incidenceattendee.cpp incidenceeditor-ng/incidencedialog.cpp incidenceeditor-ng/incidencedialog.h incidenceeditor-ng/incidenceresource.cpp incidenceeditor-ng/incidenceresource.h incidenceeditor-ng/resourcetablemodel.cpp incidenceeditor-ng/resourcetablemodel.h

Sandro Knauß knauss at kolabsys.com
Fri May 2 01:20:06 CEST 2014


 incidenceeditor-ng/CMakeLists.txt               |    2 
 incidenceeditor-ng/attendeecomboboxdelegate.cpp |   73 +++++
 incidenceeditor-ng/attendeecomboboxdelegate.h   |   59 ++++
 incidenceeditor-ng/incidenceattendee.cpp        |   18 -
 incidenceeditor-ng/incidencedialog.cpp          |   19 +
 incidenceeditor-ng/incidencedialog.h            |    1 
 incidenceeditor-ng/incidenceresource.cpp        |  338 ++++++++++--------------
 incidenceeditor-ng/incidenceresource.h          |    7 
 incidenceeditor-ng/resourcetablemodel.cpp       |  191 +++++++++++++
 incidenceeditor-ng/resourcetablemodel.h         |   92 ++++++
 10 files changed, 601 insertions(+), 199 deletions(-)

New commits:
commit 427de16b1f7e4d4304f05813b7332199819a5cc9
Author: Sandro Knauß <knauss at kolabsys.com>
Date:   Fri May 2 00:51:49 2014 +0200

    Model für Attendees auslagern

diff --git a/incidenceeditor-ng/CMakeLists.txt b/incidenceeditor-ng/CMakeLists.txt
index 1d56da2..551ea12 100644
--- a/incidenceeditor-ng/CMakeLists.txt
+++ b/incidenceeditor-ng/CMakeLists.txt
@@ -65,6 +65,8 @@ set(incidenceeditors_ng_shared_LIB_SRCS
   resourcemanagement.cpp
   resourceitem.cpp
   resourcemodel.cpp
+  resourcetablemodel.cpp
+  attendeecomboboxdelegate.cpp
 )
 
 kde4_add_kcfg_files(incidenceeditors_ng_shared_LIB_SRCS globalsettings_base.kcfgc)
diff --git a/incidenceeditor-ng/attendeecomboboxdelegate.cpp b/incidenceeditor-ng/attendeecomboboxdelegate.cpp
new file mode 100644
index 0000000..fda6a7e
--- /dev/null
+++ b/incidenceeditor-ng/attendeecomboboxdelegate.cpp
@@ -0,0 +1,73 @@
+#include "attendeecomboboxdelegate.h"
+
+#include "attendeeline.h"
+
+#include <QApplication>
+
+using namespace IncidenceEditorNG;
+
+AttendeeComboBoxDelegate::AttendeeComboBoxDelegate(QObject *parent)
+:QStyledItemDelegate(parent)
+,standardIndex(0)
+{
+
+}
+
+void AttendeeComboBoxDelegate::addItem(const QIcon &icon, const QString &text)
+{
+  QPair<QIcon,QString> pair;
+  pair.first = icon;
+  pair.second = text;
+  entries << pair;
+}
+
+void AttendeeComboBoxDelegate::setStandardIndex(int index)
+{
+  standardIndex = index;
+}
+
+
+QWidget *AttendeeComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &/* index */) const
+{
+  AttendeeComboBox* editor = new AttendeeComboBox(parent);
+  QPair<QIcon,QString> pair;
+
+  foreach(pair, entries) {
+    editor->addItem(pair.first, pair.second);
+  }
+
+  return editor;
+}
+
+void AttendeeComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+  AttendeeComboBox *comboBox = static_cast<AttendeeComboBox*>(editor);
+  int value = index.model()->data(index, Qt::EditRole).toUInt();
+  if (value >= entries.count())
+    value = standardIndex;
+  comboBox->setCurrentIndex(value);
+}
+
+void AttendeeComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
+{
+  AttendeeComboBox *comboBox = static_cast<AttendeeComboBox*>(editor);
+  model->setData(index, comboBox->currentIndex(), Qt::EditRole);
+}
+
+void AttendeeComboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
+{
+  editor->setGeometry(option.rect);
+}
+
+void AttendeeComboBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+  QStyleOptionButton pushButton;
+  int value = index.model()->data(index).toUInt();
+  pushButton.rect = option.rect;
+  pushButton.features |= QStyleOptionButton::HasMenu;
+  if (value >= entries.count())
+    value = standardIndex;
+  pushButton.icon = entries[value].first;
+
+  QApplication::style()->drawControl(QStyle::CE_PushButton, &pushButton, painter);
+}
diff --git a/incidenceeditor-ng/attendeecomboboxdelegate.h b/incidenceeditor-ng/attendeecomboboxdelegate.h
new file mode 100644
index 0000000..7d5f455
--- /dev/null
+++ b/incidenceeditor-ng/attendeecomboboxdelegate.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2014  Sandro Knauß <knauss at kolabsys.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program 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 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/>.
+ *
+ */
+
+#ifndef INCIDENCEEDITOR_ATTENDEECOMBOBOXDELEGATE_H
+#define INCIDENCEEDITOR_ATTENDEECOMBOBOXDELEGATE_H
+
+#include <QStyledItemDelegate>
+#include <QModelIndex>
+#include <QIcon>
+#include <QString>
+
+
+namespace IncidenceEditorNG
+{
+
+class AttendeeComboBoxDelegate : public QStyledItemDelegate
+{
+Q_OBJECT
+public:
+  AttendeeComboBoxDelegate(QObject *parent = 0);
+
+  QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+  void setEditorData(QWidget *editor, const QModelIndex &index) const;
+  void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
+  void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+  void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+  void addItem(const QIcon&, const QString&);
+  void setStandardIndex(int);
+
+private:
+  QList<QPair<QIcon,QString> > entries;
+  int standardIndex;
+
+};
+
+
+
+}
+
+#endif
\ No newline at end of file
diff --git a/incidenceeditor-ng/incidenceattendee.cpp b/incidenceeditor-ng/incidenceattendee.cpp
index fa1811f..32d7f04 100644
--- a/incidenceeditor-ng/incidenceattendee.cpp
+++ b/incidenceeditor-ng/incidenceattendee.cpp
@@ -185,7 +185,9 @@ void IncidenceAttendee::load( const KCalCore::Incidence::Ptr &incidence )
 
   const KCalCore::Attendee::List attendees = incidence->attendees();
   foreach ( const KCalCore::Attendee::Ptr &a, attendees ) {
-    mAttendeeEditor->addAttendee( a );
+    if (!(a->cuType() == KCalCore::Attendee::Resource || a->cuType() == KCalCore::Attendee::Room)) {
+      mAttendeeEditor->addAttendee( a );
+    }
   }
 
   mWasDirty = false;
@@ -193,7 +195,7 @@ void IncidenceAttendee::load( const KCalCore::Incidence::Ptr &incidence )
 
 void IncidenceAttendee::save( const KCalCore::Incidence::Ptr &incidence )
 {
-  incidence->clearAttendees();
+  /*incidence->clearAttendees();
   AttendeeData::List attendees = mAttendeeEditor->attendees();
 
   foreach ( AttendeeData::Ptr attendee, attendees ) {
@@ -219,7 +221,7 @@ void IncidenceAttendee::save( const KCalCore::Incidence::Ptr &incidence )
   // Must not have an organizer for items without attendees
   if ( !incidence->attendeeCount() ) {
     return;
-  }
+  }*/
 
   if ( mUi->mOrganizerStack->currentIndex() == 0 ) {
     incidence->setOrganizer( mUi->mOrganizerCombo->currentText() );
@@ -247,13 +249,16 @@ bool IncidenceAttendee::isDirty() const
 
   // The lists sizes *must* be the same. When the organizer is attending the
   // event as well, he should be in the attendees list as well.
-  if ( originalList.size() != newList.size() ) {
+  /*if ( originalList.size() != newList.size() ) {
     return true;
-  }
+  }*/
 
   // Okay, again not the most efficient algorithm, but I'm assuming that in the
   // bulk of the use cases, the number of attendees is not much higher than 10 or so.
   foreach ( const KCalCore::Attendee::Ptr &attendee, originalList ) {
+    if (attendee->cuType() == KCalCore::Attendee::Resource || attendee->cuType() == KCalCore::Attendee::Room) {
+      continue;
+    }
     bool found = false;
     for ( int i = 0; i < newList.size(); ++i ) {
       if ( compareAttendees( newList.at( i )->attendee(), attendee) ) {
@@ -265,6 +270,7 @@ bool IncidenceAttendee::isDirty() const
 
     if ( !found ) {
       // One of the attendees in the original list was not found in the new list.
+      kDebug() << "One of the attendees in the original list was not found in the new list";
       return true;
     }
   }
@@ -605,6 +611,7 @@ void IncidenceAttendee::printDebugInfo() const
                << attendee->RSVP()
                << attendee->role()
                << attendee->uid()
+               << attendee->cuType()
                << attendee->delegate()
                << attendee->delegator()
                << "; we have:";
@@ -616,6 +623,7 @@ void IncidenceAttendee::printDebugInfo() const
                  << attendee->RSVP()
                  << attendee->role()
                  << attendee->uid()
+                 << attendee->cuType()
                  << attendee->delegate()
                  << attendee->delegator();
       }
diff --git a/incidenceeditor-ng/incidencedialog.cpp b/incidenceeditor-ng/incidencedialog.cpp
index bcc1923..11a0e88 100644
--- a/incidenceeditor-ng/incidencedialog.cpp
+++ b/incidenceeditor-ng/incidencedialog.cpp
@@ -99,6 +99,7 @@ class IncidenceDialogPrivate : public ItemEditorUi
     void storeTemplatesInConfig( const QStringList &newTemplates );
     void updateAttachmentCount( int newCount );
     void updateAttendeeCount( int newCount );
+    void updateResourceCount( int newCount );
     void updateButtonStatus( bool isDirty );
     void showMessage( const QString &text, KMessageWidget::MessageType type );
 
@@ -192,6 +193,8 @@ IncidenceDialogPrivate::IncidenceDialogPrivate( Akonadi::IncidenceChanger *chang
               SLOT(updateAttachmentCount(int)) );
   q->connect( mIeAttendee, SIGNAL(attendeeCountChanged(int)),
               SLOT(updateAttendeeCount(int)) );
+  q->connect( mIeResource, SIGNAL(resourceCountChanged(int)),
+              SLOT(updateResourceCount(int)) );
 }
 
 IncidenceDialogPrivate::~IncidenceDialogPrivate()
@@ -420,6 +423,21 @@ void IncidenceDialogPrivate::updateAttendeeCount( int newCount )
   }
 }
 
+void IncidenceDialogPrivate::updateResourceCount( int newCount )
+{
+  if ( newCount > 0 ) {
+    mUi->mTabWidget->setTabText(
+      ResourcesTab,
+      i18nc( "@title:tab Tab to modify attendees of an event or todo",
+             "&Resources (%1)", newCount ) );
+  } else {
+    mUi->mTabWidget->setTabText(
+      ResourcesTab,
+      i18nc( "@title:tab Tab to modify attendees of an event or todo",
+             "&Resources" ) );
+  }
+}
+
 void IncidenceDialogPrivate::updateButtonStatus( bool isDirty )
 {
   Q_Q( IncidenceDialog );
@@ -565,6 +583,7 @@ void IncidenceDialogPrivate::load( const Akonadi::Item &item )
 
   // Initialize tab's titles
   updateAttachmentCount( incidence->attachments().size() );
+  updateResourceCount( mIeResource->resourcesCount() );
   handleRecurrenceChange( mIeRecurrence->currentRecurrenceType() );
   handleAlarmCountChange( incidence->alarms().count() );
 
diff --git a/incidenceeditor-ng/incidencedialog.h b/incidenceeditor-ng/incidencedialog.h
index 7d7c36c..4d22699 100644
--- a/incidenceeditor-ng/incidencedialog.h
+++ b/incidenceeditor-ng/incidencedialog.h
@@ -108,6 +108,7 @@ class INCIDENCEEDITORS_NG_EXPORT IncidenceDialog : public KDialog
     Q_PRIVATE_SLOT( d_ptr, void storeTemplatesInConfig(QStringList) )
     Q_PRIVATE_SLOT( d_ptr, void updateAttachmentCount(int) )
     Q_PRIVATE_SLOT( d_ptr, void updateAttendeeCount(int) )
+    Q_PRIVATE_SLOT( d_ptr, void updateResourceCount(int) )
     Q_PRIVATE_SLOT( d_ptr, void updateButtonStatus(bool) )
     Q_PRIVATE_SLOT( d_ptr, void showMessage(QString,KMessageWidget::MessageType) )
 };
diff --git a/incidenceeditor-ng/incidenceresource.cpp b/incidenceeditor-ng/incidenceresource.cpp
index c40bfcc..9086104 100644
--- a/incidenceeditor-ng/incidenceresource.cpp
+++ b/incidenceeditor-ng/incidenceresource.cpp
@@ -20,6 +20,7 @@
 #include "incidenceresource.h"
 #include "resourcemanagement.h"
 #include "resourcemodel.h"
+#include "attendeecomboboxdelegate.h"
 
 #ifdef KDEPIM_MOBILE_UI
 #include "ui_dialogmoremobile.h"
@@ -27,14 +28,19 @@
 #include "ui_dialogdesktop.h"
 #endif
 
-#include <kdebug.h>
+#include <KDebug>
+#include <KMessageBox>
+
+#include <KCalUtils/Stringify>
+#include <KPIMUtils/Email>
+
 
 #include <QCompleter>
 using namespace IncidenceEditorNG;
 
 #include <QStandardItem>
 #include <QAbstractProxyModel>
-
+#include <QSortFilterProxyModel>
 /* Flatten the TreeModel of Resources */
 class SortProxy : public QAbstractProxyModel
 {
@@ -110,183 +116,9 @@ private:
     QMap<QPersistentModelIndex, QPersistentModelIndex> mapping;
 };
 
-//Own line of resource in the resource editor table
-class Resource
-{
-public:
-    Resource() {
-        name = QString("");
-        role = 0;
-        available = false;
-        status = 0;
-    }
-    void setName(const QString &name) {
-        this->name = name;
-    }
-    void setRole(int role) {
-        this->role = role;
-    }
-    void setAvailable(bool available) {
-        this->available = available;
-    }
-    void setStatus(int status) {
-        this->status = status;
-    }
-public:
-    QString name;
-    int role;
-    bool available;
-    int status;
-};
-
-#include <QAbstractTableModel>
-
-/* TableView for the Resource Tab
- * 0 = role
- * 1 = name
- * 2 = available
- * 3 = status
- */
-
-class ResourceTableModel : public QAbstractTableModel
-{
-    Q_OBJECT
-
-public:
-    ResourceTableModel(const QList <Resource> &resources, QObject *parent = 0)
-        : QAbstractTableModel(parent), resourceList(resources) {}
-
-    int rowCount(const QModelIndex &parent = QModelIndex()) const;
-    int columnCount(const QModelIndex &parent = QModelIndex()) const;
-    QVariant data(const QModelIndex &index, int role) const;
-    QVariant headerData(int section, Qt::Orientation orientation,
-                        int role = Qt::DisplayRole) const;
-
-    Qt::ItemFlags flags(const QModelIndex &index) const;
-    bool setData(const QModelIndex &index, const QVariant &value,
-                 int role = Qt::EditRole);
 
-    bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex());
-    bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex());
-
-private:
-    QList<Resource> resourceList;
-};
 
 
-int ResourceTableModel::rowCount(const QModelIndex &/*parent*/) const
-{
-    return resourceList.count();
-}
-
-int ResourceTableModel::columnCount(const QModelIndex &/*parent*/) const
-{
-    return 4;
-}
-
-Qt::ItemFlags ResourceTableModel::flags(const QModelIndex &index) const
-{
-    if (!index.isValid())
-        return Qt::ItemIsEnabled;
-
-    return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
-}
-
-QVariant ResourceTableModel::data(const QModelIndex &index, int role) const
-{
-    if (!index.isValid())
-        return QVariant();
-
-    if (index.row() >= resourceList.size())
-        return QVariant();
-
-    if (role == Qt::DisplayRole || role == Qt::EditRole) {
-        switch (index.column()) {
-        case 0:
-            return resourceList.at(index.row()).role;
-        case 1:
-            return resourceList.at(index.row()).name;
-        case 2:
-            return resourceList.at(index.row()).available;
-        case 3:
-            return resourceList.at(index.row()).status;
-        }
-
-    }
-    return QVariant();
-}
-
-bool ResourceTableModel::setData(const QModelIndex& index, const QVariant& value, int role)
-{
-    if (index.isValid() && role == Qt::EditRole) {
-        switch (index.column()) {
-        case 0:
-            resourceList[index.row()].role = value.toInt();
-            break;
-        case 1:
-            resourceList[index.row()].name = value.toString() ;
-            break;
-        case 2:
-            resourceList[index.row()].available = value.toBool();
-            break;
-        case 3:
-            resourceList[index.row()].status = value.toInt();
-            break;
-        default:
-            return false;
-        }
-        emit dataChanged(index, index);
-        return true;
-    }
-    return false;
-}
-
-QVariant ResourceTableModel::headerData(int section, Qt::Orientation orientation,
-                                        int role) const
-{
-    if (role != Qt::DisplayRole)
-        return QVariant();
-
-    if (orientation == Qt::Horizontal) {
-        switch (section) {
-        case 0:
-            return QString("role");
-        case 1:
-            return QString("name");
-        case 2:
-            return QString("available");
-        case 3:
-            return QString("status");
-        }
-    }
-
-    return QVariant();
-}
-
-bool ResourceTableModel::insertRows(int position, int rows, const QModelIndex &parent)
-{
-    beginInsertRows(QModelIndex(), position, position + rows - 1);
-
-    for (int row = 0; row < rows; ++row) {
-        resourceList.insert(position, Resource());
-    }
-
-    endInsertRows();
-    return true;
-}
-
-bool ResourceTableModel::removeRows(int position, int rows, const QModelIndex &parent)
-{
-    beginRemoveRows(QModelIndex(), position, position + rows - 1);
-
-    for (int row = 0; row < rows; ++row) {
-        resourceList.removeAt(position);
-    }
-
-    endRemoveRows();
-    return true;
-}
-
 #ifdef KDEPIM_MOBILE_UI
 IncidenceResource::IncidenceResource(Ui::EventOrTodoMore *ui)
 #else
@@ -297,6 +129,54 @@ IncidenceResource::IncidenceResource(Ui::EventOrTodoDesktop *ui)
 {
     setObjectName("IncidenceResource");
 
+   AttendeeComboBoxDelegate* roleDelegate(new AttendeeComboBoxDelegate(this));
+#ifdef KDEPIM_MOBILE_UI
+  roleDelegate->addItem( DesktopIcon( "meeting-participant", 48 ),
+                       KCalUtils::Stringify::attendeeRole( KCalCore::Attendee::ReqParticipant ) );
+  roleDelegate->addItem( DesktopIcon( "meeting-participant-optional", 48 ),
+                       KCalUtils::Stringify::attendeeRole( KCalCore::Attendee::OptParticipant ) );
+  roleDelegate->addItem( DesktopIcon( "meeting-observer", 48 ),
+                       KCalUtils::Stringify::attendeeRole( KCalCore::Attendee::NonParticipant ) );
+  roleDelegate->addItem( DesktopIcon( "meeting-chair", 48 ),
+                       KCalUtils::Stringify::attendeeRole( KCalCore::Attendee::Chair ) );
+
+#else
+  roleDelegate->addItem( SmallIcon( "meeting-participant" ),
+                       KCalUtils::Stringify::attendeeRole( KCalCore::Attendee::ReqParticipant ) );
+  roleDelegate->addItem( SmallIcon( "meeting-participant-optional" ),
+                       KCalUtils::Stringify::attendeeRole( KCalCore::Attendee::OptParticipant ) );
+  roleDelegate->addItem( SmallIcon( "meeting-observer" ),
+                       KCalUtils::Stringify::attendeeRole( KCalCore::Attendee::NonParticipant ) );
+  roleDelegate->addItem( SmallIcon( "meeting-chair" ),
+                       KCalUtils::Stringify::attendeeRole( KCalCore::Attendee::Chair ) );
+#endif
+
+  AttendeeComboBoxDelegate *stateDelegate(new AttendeeComboBoxDelegate(this));
+
+  #ifdef KDEPIM_MOBILE_UI
+    stateDelegate->addItem( DesktopIcon( "task-attention", 48 ),
+                          KCalUtils::Stringify::attendeeStatus( KCalCore::Attendee::NeedsAction ) );
+    stateDelegate->addItem( DesktopIcon( "task-accepted", 48 ),
+                          KCalUtils::Stringify::attendeeStatus( KCalCore::Attendee::Accepted ) );
+    stateDelegate->addItem( DesktopIcon( "task-reject", 48 ),
+                          KCalUtils::Stringify::attendeeStatus( KCalCore::Attendee::Declined ) );
+    stateDelegate->addItem( DesktopIcon( "task-attempt", 48 ),
+                          KCalUtils::Stringify::attendeeStatus( KCalCore::Attendee::Tentative ) );
+    stateDelegate->addItem( DesktopIcon( "task-delegate", 48 ),
+                          KCalUtils::Stringify::attendeeStatus( KCalCore::Attendee::Delegated ) );
+#else
+    stateDelegate->addItem( SmallIcon( "task-attention" ),
+                          KCalUtils::Stringify::attendeeStatus( KCalCore::Attendee::NeedsAction ) );
+    stateDelegate->addItem( SmallIcon( "task-accepted" ),
+                          KCalUtils::Stringify::attendeeStatus( KCalCore::Attendee::Accepted ) );
+    stateDelegate->addItem( SmallIcon( "task-reject" ),
+                          KCalUtils::Stringify::attendeeStatus( KCalCore::Attendee::Declined ) );
+    stateDelegate->addItem( SmallIcon( "task-attempt" ),
+                          KCalUtils::Stringify::attendeeStatus( KCalCore::Attendee::Tentative ) );
+    stateDelegate->addItem( SmallIcon( "task-delegate" ),
+                          KCalUtils::Stringify::attendeeStatus( KCalCore::Attendee::Delegated ) );
+#endif
+
 #ifndef KDEPIM_MOBILE_UI
     QStringList attrs;
     attrs << QLatin1String("cn");
@@ -309,47 +189,104 @@ IncidenceResource::IncidenceResource(Ui::EventOrTodoDesktop *ui)
     completer->setWrapAround(false);
     mUi->mNewResource->setCompleter(completer);
 
-    Resource resource;
-    resource.name = QString("test");
-    resource.role = 1;
-    resource.available = false;
-    resource.status = 0;
+    KCalCore::Attendee::List resources;
 
-    QList<Resource> resources;
-    resources << resource;
-
-    ResourceTableModel *resourceModel = new ResourceTableModel(resources, this);
-    mUi->mResourcesTable->setModel(resourceModel);
+    dataModel = new ResourceTableModel(resources, this);
+    ResourceFilterProxyModel *filterProxyModel = new ResourceFilterProxyModel(this);
+    filterProxyModel->setDynamicSortFilter(true);
+    filterProxyModel->setSourceModel(dataModel);
 
+    mUi->mResourcesTable->setModel(filterProxyModel);
+    mUi->mResourcesTable->setColumnHidden(4, true);
+    mUi->mResourcesTable->setItemDelegateForColumn(0, roleDelegate);
+    mUi->mResourcesTable->setItemDelegateForColumn(3, stateDelegate);
 
     connect(mUi->mFindResourcesButton, SIGNAL(clicked()), SLOT(findResources()));
     connect(mUi->mBookResourceButton, SIGNAL(clicked()), SLOT(bookResource()));
+    connect(dataModel, SIGNAL(layoutChanged()), SLOT(layoutChanged()));
+    connect(dataModel, SIGNAL(rowsInserted(const QModelIndex&, int , int)), SLOT(layoutChanged()));
+    connect(dataModel, SIGNAL(rowsRemoved(const QModelIndex&, int , int)), SLOT(layoutChanged()));
 #endif
 }
 
 void IncidenceResource::load(const KCalCore::Incidence::Ptr &incidence)
 {
-
+  mLoadedIncidence = incidence;
+  dataModel->setAttendees(incidence->attendees());
 }
 
 void IncidenceResource::save(const KCalCore::Incidence::Ptr &incidence)
 {
+  incidence->clearAttendees();
+  KCalCore::Attendee::List attendees = dataModel->attendees();
+
+  foreach ( KCalCore::Attendee::Ptr attendee, attendees ) {
+    Q_ASSERT( attendee );
+
+    bool skip = false;
+    if ( KPIMUtils::isValidAddress( attendee->email() ) ) {
+      if ( KMessageBox::warningYesNo(
+             0,
+             i18nc( "@info",
+                    "%1 does not look like a valid email address. "
+                    "Are you sure you want to invite this participant?",
+                    attendee->email() ),
+             i18nc( "@title:window", "Invalid Email Address" ) ) != KMessageBox::Yes ) {
+        skip = true;
+      }
+    }
+    if ( !skip ) {
+      incidence->addAttendee( attendee );
+    }
+  }
+
+  // Must not have an organizer for items without attendees
+  if ( !incidence->attendeeCount() ) {
+    return;
+  }
 }
 
 bool IncidenceResource::isDirty() const
 {
-    return false;
+  const KCalCore::Attendee::List originalList = mLoadedIncidence->attendees();
+  KCalCore::Attendee::List newList = dataModel->attendees();
+
+  // The lists sizes *must* be the same. When the organizer is attending the
+  // event as well, he should be in the attendees list as well.
+  if ( originalList.size() != newList.size() ) {
+    return true;
+  }
+
+  // Okay, again not the most efficient algorithm, but I'm assuming that in the
+  // bulk of the use cases, the number of attendees is not much higher than 10 or so.
+  foreach ( const KCalCore::Attendee::Ptr &attendee, originalList ) {
+    bool found = false;
+    for ( int i = 0; i < newList.count(); ++i ) {
+      if ( newList[i] == attendee ) {
+        newList.remove( i );
+        found = true;
+        break;
+      }
+    }
+
+    if ( !found ) {
+      // One of the attendees in the original list was not found in the new list.
+      return true;
+    }
+  }
+
+  return false;
 }
 
 void IncidenceResource::bookResource()
 {
 #ifndef KDEPIM_MOBILE_UI
-    kDebug() << "bookResource: " << mUi->mNewResource->text();
-   
-    // create new line and set name to mUi->mNewResource->text()
-    mUi->mResourcesTable->model()->insertRows(mUi->mResourcesTable->model()->rowCount(), 1, QModelIndex());
-    QModelIndex index = mUi->mResourcesTable->model()->index(mUi->mResourcesTable->model()->rowCount() - 1, 1, QModelIndex());
-    mUi->mResourcesTable->model()->setData(index, mUi->mNewResource->text(), Qt::EditRole);
+    QString name, email;
+
+    KPIMUtils::extractEmailAddressAndName( mUi->mNewResource->text(), email, name );
+    KCalCore::Attendee::Ptr attendee(new KCalCore::Attendee(name,email));
+    attendee->setCuType(KCalCore::Attendee::Resource);
+    dataModel->insertAttendee(dataModel->rowCount(), attendee);
 #endif
 }
 
@@ -359,4 +296,17 @@ void IncidenceResource::findResources()
     dialog->show();
 }
 
+void IncidenceResource::layoutChanged()
+{
+  emit resourceCountChanged(resourcesCount());
+}
+
+int IncidenceResource::resourcesCount() const
+{
+#ifndef KDEPIM_MOBILE_UI
+  return mUi->mResourcesTable->model()->rowCount(QModelIndex());
+#endif
+  return 0;
+}
+
 #include "incidenceresource.moc"
\ No newline at end of file
diff --git a/incidenceeditor-ng/incidenceresource.h b/incidenceeditor-ng/incidenceresource.h
index 6d283fa..42a49b9 100644
--- a/incidenceeditor-ng/incidenceresource.h
+++ b/incidenceeditor-ng/incidenceresource.h
@@ -21,6 +21,7 @@
 #define INCIDENCEEDITOR_INCIDENCERESOURCE_H
 
 #include "incidenceeditor-ng.h"
+#include "resourcetablemodel.h"
 
 #include <QModelIndex>
 #include <QCompleter>
@@ -47,10 +48,15 @@ public:
     void load(const KCalCore::Incidence::Ptr &incidence);
     void save(const KCalCore::Incidence::Ptr &incidence);
     bool isDirty() const;
+    int resourcesCount() const;
+
+signals:
+    void resourceCountChanged( int );
 
 private slots:
     void findResources();
     void bookResource();
+    void layoutChanged();
 
 private:
 #ifdef KDEPIM_MOBILE_UI
@@ -59,6 +65,7 @@ private:
     Ui::EventOrTodoDesktop *mUi;
 #endif
     QCompleter *completer;
+    ResourceTableModel *dataModel;
 };
 
 }
diff --git a/incidenceeditor-ng/resourcetablemodel.cpp b/incidenceeditor-ng/resourcetablemodel.cpp
new file mode 100644
index 0000000..2678283
--- /dev/null
+++ b/incidenceeditor-ng/resourcetablemodel.cpp
@@ -0,0 +1,191 @@
+#include "resourcetablemodel.h"
+
+#include <KCalCore/Attendee>
+#include <KPIMUtils/Email>
+
+#include <KDebug>
+
+using namespace IncidenceEditorNG;
+
+ResourceTableModel::ResourceTableModel(const KCalCore::Attendee::List &resources, QObject *parent )
+: QAbstractTableModel(parent)
+, resourceList(resources)
+{
+
+}
+
+int ResourceTableModel::rowCount(const QModelIndex &/*parent*/) const
+{
+    return resourceList.count();
+}
+
+int ResourceTableModel::columnCount(const QModelIndex &/*parent*/) const
+{
+    return 5;
+}
+
+Qt::ItemFlags ResourceTableModel::flags(const QModelIndex &index) const
+{
+    if (!index.isValid())
+        return Qt::ItemIsEnabled;
+
+    return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
+}
+
+QVariant ResourceTableModel::data(const QModelIndex &index, int role) const
+{
+    if (!index.isValid())
+        return QVariant();
+
+    if (index.row() >= resourceList.size())
+        return QVariant();
+
+    if (role == Qt::DisplayRole || role == Qt::EditRole) {
+       switch (index.column()) {
+        case 0:
+            return resourceList[index.row()]->role();
+        case 1:
+            return resourceList[index.row()]->fullName();
+        case 2:
+            return 0;//resourceList.at(index.row()).available;
+        case 3:
+            return resourceList[index.row()]->status();
+        case 4:
+            return resourceList[index.row()]->cuType();
+        }
+
+    }
+    return QVariant();
+}
+
+bool ResourceTableModel::setData(const QModelIndex& index, const QVariant& value, int role)
+{
+    QString email, name;
+    if (index.isValid() && role == Qt::EditRole) {
+        switch (index.column()) {
+        case 0:
+            resourceList[index.row()]->setRole(static_cast<KCalCore::Attendee::Role>(value.toInt()));
+            break;
+        case 1:
+            KPIMUtils::extractEmailAddressAndName( value.toString(), email, name );
+            resourceList[index.row()]->setName(name);
+            resourceList[index.row()]->setEmail(email);
+            break;
+        case 2:
+            //resourceList[index.row()].available = value.toBool();
+            break;
+        case 3:
+            resourceList[index.row()]->setStatus(static_cast<KCalCore::Attendee::PartStat>(value.toInt()));
+            break;
+        case 4:
+            resourceList[index.row()]->setCuType(static_cast<KCalCore::Attendee::CuType>(value.toInt()));
+            break;
+        default:
+            return false;
+        }
+        emit dataChanged(index, index);
+        return true;
+    }
+    return false;
+}
+
+QVariant ResourceTableModel::headerData(int section, Qt::Orientation orientation,
+                                        int role) const
+{
+    if (role != Qt::DisplayRole)
+        return QVariant();
+
+    if (orientation == Qt::Horizontal) {
+        switch (section) {
+        case 0:
+            return QString("role");
+        case 1:
+            return QString("name");
+        case 2:
+            return QString("available");
+        case 3:
+            return QString("status");
+        case 4:
+            return QString("cuType");
+        }
+    }
+
+    return QVariant();
+}
+
+bool ResourceTableModel::insertRows(int position, int rows, const QModelIndex &parent)
+{
+    beginInsertRows(QModelIndex(), position, position + rows);
+
+    for (int row = 0; row < rows; ++row) {
+        KCalCore::Attendee::Ptr attendee(new KCalCore::Attendee("",""));
+        resourceList.insert(position, attendee);
+    }
+
+    endInsertRows();
+    return true;
+}
+
+bool ResourceTableModel::removeRows(int position, int rows, const QModelIndex &parent)
+{
+    beginRemoveRows(QModelIndex(), position, position + rows);
+
+    for (int row = 0; row < rows; ++row) {
+        resourceList.remove(position);
+    }
+
+    endRemoveRows();
+    return true;
+}
+
+bool ResourceTableModel::insertAttendee(int position, const KCalCore::Attendee::Ptr& attendee)
+{
+    beginInsertRows(QModelIndex(), position, position + 1);
+
+    resourceList.insert(position, attendee);
+
+    endInsertRows();
+
+    return true;
+}
+
+void ResourceTableModel::setAttendees(const KCalCore::Attendee::List resources)
+{
+  emit layoutAboutToBeChanged();
+
+  resourceList = resources;
+
+  emit layoutChanged();
+}
+
+
+KCalCore::Attendee::List ResourceTableModel::attendees() const
+{
+  return resourceList;
+}
+
+ResourceFilterProxyModel::ResourceFilterProxyModel(QObject *parent)
+: QSortFilterProxyModel(parent)
+{
+}
+
+bool ResourceFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+{
+    QModelIndex cuTypeIndex = sourceModel()->index(sourceRow, 4, sourceParent);
+    KCalCore::Attendee::CuType cuType = static_cast<KCalCore::Attendee::CuType>(sourceModel()->data(cuTypeIndex).toUInt());
+
+    return (cuType == KCalCore::Attendee::Resource || cuType == KCalCore::Attendee::Room);
+}
+
+AttendeeFilterProxyModel::AttendeeFilterProxyModel(QObject *parent)
+: QSortFilterProxyModel(parent)
+{
+}
+
+bool AttendeeFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+{
+    QModelIndex cuTypeIndex = sourceModel()->index(sourceRow, 4, sourceParent);
+    KCalCore::Attendee::CuType cuType = static_cast<KCalCore::Attendee::CuType>(sourceModel()->data(cuTypeIndex).toUInt());
+
+    return !(cuType == KCalCore::Attendee::Resource || cuType == KCalCore::Attendee::Room);
+}
diff --git a/incidenceeditor-ng/resourcetablemodel.h b/incidenceeditor-ng/resourcetablemodel.h
new file mode 100644
index 0000000..6925c1e
--- /dev/null
+++ b/incidenceeditor-ng/resourcetablemodel.h
@@ -0,0 +1,92 @@
+
+/*
+  Copyright (C) 2014 Sandro Knauß <knauss at kolabsys.com>
+
+  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 INCIDENCEEDITOR_INCIDENCERESOURCETABLEMODEL_H
+#define INCIDENCEEDITOR_INCIDENCERESOURCETABLEMODEL_H
+
+#include <KCalCore/Attendee>
+
+#include <QAbstractTableModel>
+#include <QSortFilterProxyModel>
+#include <QModelIndex>
+#include <QVector>
+
+namespace IncidenceEditorNG
+{
+
+/* TableView for the Resource Tab
+ * 0 = role
+ * 1 = name
+ * 2 = available
+ * 3 = status
+ * 4 = cutype
+ */
+
+class ResourceTableModel : public QAbstractTableModel
+{
+    Q_OBJECT
+
+public:
+    ResourceTableModel(const KCalCore::Attendee::List &resources, QObject *parent = 0);
+
+    int rowCount(const QModelIndex &parent = QModelIndex()) const;
+    int columnCount(const QModelIndex &parent = QModelIndex()) const;
+    QVariant data(const QModelIndex &index, int role) const;
+    QVariant headerData(int section, Qt::Orientation orientation,
+                        int role = Qt::DisplayRole) const;
+
+    Qt::ItemFlags flags(const QModelIndex &index) const;
+    bool setData(const QModelIndex &index, const QVariant &value,
+                 int role = Qt::EditRole);
+
+    bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex());
+    bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex());
+
+    bool insertAttendee(int position, const KCalCore::Attendee::Ptr &attendee);
+    void setAttendees(const KCalCore::Attendee::List resources);
+
+    KCalCore::Attendee::List attendees() const;
+
+private:
+    KCalCore::Attendee::List resourceList;
+};
+
+class ResourceFilterProxyModel : public QSortFilterProxyModel
+{
+  Q_OBJECT
+public:
+    ResourceFilterProxyModel(QObject *parent = 0);
+    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+};
+
+class AttendeeFilterProxyModel : public QSortFilterProxyModel
+{
+  Q_OBJECT
+public:
+    AttendeeFilterProxyModel(QObject *parent = 0);
+    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+};
+
+
+}
+
+#endif
+
+




More information about the commits mailing list