00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "browserwidget.h"
00021 #include "collectionattributespage.h"
00022 #include "collectioninternalspage.h"
00023 #include "collectionaclpage.h"
00024
00025 #include <akonadi/attributefactory.h>
00026 #include <akonadi/job.h>
00027 #include <akonadi/collectionmodel.h>
00028 #include <akonadi/collectionview.h>
00029 #include <akonadi/item.h>
00030 #include <akonadi/itemfetchjob.h>
00031 #include <akonadi/itemfetchscope.h>
00032 #include <akonadi/itemmodifyjob.h>
00033 #include <akonadi/collectionfilterproxymodel.h>
00034 #include <akonadi/collectionpropertiesdialog.h>
00035
00036 #include <kcal/kcalmodel.h>
00037 #include <kabc/kabcmodel.h>
00038 #include <kabc/kabcitembrowser.h>
00039 #include <akonadi/kmime/messagemodel.h>
00040
00041 #include <libkdepim/addresseeview.h>
00042
00043 #include <kdebug.h>
00044 #include <kconfig.h>
00045 #include <kmessagebox.h>
00046 #include <kxmlguiwindow.h>
00047 #include <nepomuk/resource.h>
00048 #include <nepomuk/variant.h>
00049
00050 #include <QSplitter>
00051 #include <QTextEdit>
00052 #include <QVBoxLayout>
00053 #include <QStackedWidget>
00054 #include <QtGui/QSortFilterProxyModel>
00055 #include <QStandardItemModel>
00056 #include <QTimer>
00057
00058 using namespace Akonadi;
00059
00060 AKONADI_COLLECTION_PROPERTIES_PAGE_FACTORY(CollectionAttributePageFactory, CollectionAttributePage)
00061 AKONADI_COLLECTION_PROPERTIES_PAGE_FACTORY(CollectionInternalsPageFactory, CollectionInternalsPage)
00062 AKONADI_COLLECTION_PROPERTIES_PAGE_FACTORY(CollectionAclPageFactory, CollectionAclPage)
00063
00064 BrowserWidget::BrowserWidget(KXmlGuiWindow *xmlGuiWindow, QWidget * parent) :
00065 QWidget( parent ),
00066 mItemModel( 0 ),
00067 mCurrentCollection( 0 ),
00068 mNepomukModel( 0 )
00069 {
00070 QVBoxLayout *layout = new QVBoxLayout( this );
00071
00072 QSplitter *splitter = new QSplitter( Qt::Horizontal, this );
00073 splitter->setObjectName( "collectionSplitter" );
00074 layout->addWidget( splitter );
00075
00076 mCollectionView = new Akonadi::CollectionView( xmlGuiWindow );
00077 connect( mCollectionView, SIGNAL(clicked(QModelIndex)), SLOT(collectionActivated(QModelIndex)) );
00078 splitter->addWidget( mCollectionView );
00079
00080 mCollectionModel = new Akonadi::CollectionModel( this );
00081 QSortFilterProxyModel *sortModel = new QSortFilterProxyModel( this );
00082 sortModel->setDynamicSortFilter( true );
00083 sortModel->setSortCaseSensitivity( Qt::CaseInsensitive );
00084 sortModel->setSourceModel( mCollectionModel );
00085 mCollectionView->setModel( sortModel );
00086
00087 QSplitter *splitter2 = new QSplitter( Qt::Vertical, this );
00088 splitter2->setObjectName( "itemSplitter" );
00089 splitter->addWidget( splitter2 );
00090
00091 QWidget *itemViewParent = new QWidget( this );
00092 itemUi.setupUi( itemViewParent );
00093
00094 itemUi.modelBox->addItem( "Generic" );
00095 itemUi.modelBox->addItem( "Mail" );
00096 itemUi.modelBox->addItem( "Contacts" );
00097 itemUi.modelBox->addItem( "Calendar" );
00098 connect( itemUi.modelBox, SIGNAL(activated(int)), SLOT(modelChanged()) );
00099 QTimer::singleShot( 0, this, SLOT(modelChanged()) );
00100
00101 itemUi.itemView->setXmlGuiWindow( xmlGuiWindow );
00102 itemUi.itemView->setModel( mItemModel );
00103 itemUi.itemView->setSelectionMode( QAbstractItemView::ExtendedSelection );
00104 connect( itemUi.itemView, SIGNAL(clicked(QModelIndex)), SLOT(itemActivated(QModelIndex)) );
00105 splitter2->addWidget( itemViewParent );
00106 itemViewParent->layout()->setMargin( 0 );
00107
00108 QWidget *contentViewParent = new QWidget( this );
00109 contentUi.setupUi( contentViewParent );
00110 connect( contentUi.saveButton, SIGNAL(clicked()), SLOT(save()) );
00111 splitter2->addWidget( contentViewParent );
00112
00113 connect( contentUi.attrAddButton, SIGNAL(clicked()), SLOT(addAttribute()) );
00114 connect( contentUi.attrDeleteButton, SIGNAL(clicked()), SLOT(delAttribute()) );
00115
00116 CollectionPropertiesDialog::registerPage( new CollectionAclPageFactory() );
00117 CollectionPropertiesDialog::registerPage( new CollectionAttributePageFactory() );
00118 CollectionPropertiesDialog::registerPage( new CollectionInternalsPageFactory() );
00119 }
00120
00121 void BrowserWidget::collectionActivated(const QModelIndex & index)
00122 {
00123 mCurrentCollection = mCollectionView->model()->data( index, CollectionModel::CollectionIdRole ).toLongLong();
00124 if ( mCurrentCollection <= 0 )
00125 return;
00126 mItemModel->setCollection( Collection( mCurrentCollection ) );
00127 }
00128
00129 void BrowserWidget::itemActivated(const QModelIndex & index)
00130 {
00131 const Item item = mItemModel->itemForIndex( index );
00132 if ( !item.isValid() )
00133 return;
00134
00135 ItemFetchJob *job = new ItemFetchJob( item, this );
00136 job->fetchScope().fetchFullPayload();
00137 job->fetchScope().fetchAllAttributes();
00138 connect( job, SIGNAL(result(KJob*)), SLOT(itemFetchDone(KJob*)) );
00139 job->start();
00140 }
00141
00142 void BrowserWidget::itemFetchDone(KJob * job)
00143 {
00144 ItemFetchJob *fetch = static_cast<ItemFetchJob*>( job );
00145 if ( job->error() ) {
00146 kWarning( 5265 ) << "Item fetch failed: " << job->errorString();
00147 } else if ( fetch->items().isEmpty() ) {
00148 kWarning( 5265 ) << "No item found!";
00149 } else {
00150 const Item item = fetch->items().first();
00151 mCurrentItem = item;
00152 if ( item.hasPayload<KABC::Addressee>() ) {
00153 const KABC::Addressee addr = item.payload<KABC::Addressee>();
00154
00155 contentUi.addresseeView->setAddressee( addr );
00156 contentUi.stack->setCurrentWidget( contentUi.addresseeViewPage );
00157 } else if ( item.mimeType().startsWith( "application/x-vnd.akonadi.calendar" ) ) {
00158 contentUi.incidenceView->setItem( item );
00159 contentUi.stack->setCurrentWidget( contentUi.incidenceViewPage );
00160 } else {
00161 contentUi.stack->setCurrentWidget( contentUi.unsupportedTypePage );
00162 }
00163
00164 QByteArray data = item.payloadData();
00165 contentUi.dataView->setPlainText( data );
00166
00167 contentUi.id->setText( QString::number( item.id() ) );
00168 contentUi.remoteId->setText( item.remoteId() );
00169 contentUi.mimeType->setText( item.mimeType() );
00170 contentUi.revision->setText( QString::number( item.revision() ) );
00171 contentUi.modificationtime->setText( item.modificationTime().toString() + ( " UTC" ) );
00172 QStringList flags;
00173 foreach ( const Item::Flag &f, item.flags() )
00174 flags << QString::fromUtf8( f );
00175 contentUi.flags->setItems( flags );
00176
00177 Attribute::List list = item.attributes();
00178 mAttrModel = new QStandardItemModel( list.count(), 2 );
00179 QStringList labels;
00180 labels << i18n( "Attribute" ) << i18n( "Value" );
00181 mAttrModel->setHorizontalHeaderLabels( labels );
00182 for ( int i = 0; i < list.count(); ++i ) {
00183 QModelIndex index = mAttrModel->index( i, 0 );
00184 Q_ASSERT( index.isValid() );
00185 mAttrModel->setData( index, QString::fromLatin1( list[i]->type() ) );
00186 index = mAttrModel->index( i, 1 );
00187 Q_ASSERT( index.isValid() );
00188 mAttrModel->setData( index, QString::fromLatin1( list[i]->serialized() ) );
00189 mAttrModel->itemFromIndex( index )->setFlags( Qt::ItemIsEditable | mAttrModel->flags( index ) );
00190 }
00191 contentUi.attrView->setModel( mAttrModel );
00192
00193 Nepomuk::Resource res( item.url() );
00194 delete mNepomukModel;
00195 mNepomukModel = 0;
00196 if ( res.isValid() ) {
00197 QHash<QUrl, Nepomuk::Variant> props = res.properties();
00198 mNepomukModel = new QStandardItemModel( props.count(), 2, this );
00199 QStringList labels;
00200 labels << i18n( "Property" ) << i18n( "Value" );
00201 mNepomukModel->setHorizontalHeaderLabels( labels );
00202 int row = 0;
00203 for ( QHash<QUrl, Nepomuk::Variant>::ConstIterator it = props.begin(); it != props.end(); ++it, ++row ) {
00204 QModelIndex index = mNepomukModel->index( row, 0 );
00205 Q_ASSERT( index.isValid() );
00206 mNepomukModel->setData( index, it.key().toString() );
00207 index = mNepomukModel->index( row, 1 );
00208 Q_ASSERT( index.isValid() );
00209 mNepomukModel->setData( index, it.value().toString() );
00210 }
00211 contentUi.nepomukView->setEnabled( true );
00212 } else {
00213 contentUi.nepomukView->setEnabled( false );
00214 }
00215 contentUi.nepomukView->setModel( mNepomukModel );
00216 }
00217 }
00218
00219 void BrowserWidget::modelChanged()
00220 {
00221 delete mItemModel;
00222 switch ( itemUi.modelBox->currentIndex() ) {
00223 case 1:
00224 mItemModel = new MessageModel( this );
00225 break;
00226 case 2:
00227 mItemModel = new KABCModel( this );
00228 break;
00229 case 3:
00230 mItemModel = new KCalModel( this );
00231 break;
00232 default:
00233 mItemModel = new ItemModel( this );
00234 }
00235 itemUi.itemView->setModel( mItemModel );
00236 if ( mCurrentCollection > 0 )
00237 mItemModel->setCollection( Collection( mCurrentCollection ) );
00238 }
00239
00240 void BrowserWidget::save()
00241 {
00242 const QByteArray data = contentUi.dataView->toPlainText().toUtf8();
00243 Item item = mCurrentItem;
00244 item.setRemoteId( contentUi.remoteId->text() );
00245 foreach ( const Item::Flag &f, mCurrentItem.flags() )
00246 item.clearFlag( f );
00247 foreach ( const QString &s, contentUi.flags->items() )
00248 item.setFlag( s.toUtf8() );
00249 item.setPayloadFromData( data );
00250
00251 item.clearAttributes();
00252 for ( int i = 0; i < mAttrModel->rowCount(); ++i ) {
00253 const QModelIndex typeIndex = mAttrModel->index( i, 0 );
00254 Q_ASSERT( typeIndex.isValid() );
00255 const QModelIndex valueIndex = mAttrModel->index( i, 1 );
00256 Q_ASSERT( valueIndex.isValid() );
00257 Attribute* attr = AttributeFactory::createAttribute( mAttrModel->data( typeIndex ).toString().toLatin1() );
00258 Q_ASSERT( attr );
00259 attr->deserialize( mAttrModel->data( valueIndex ).toString().toLatin1() );
00260 item.addAttribute( attr );
00261 }
00262
00263 ItemModifyJob *store = new ItemModifyJob( item, this );
00264 connect( store, SIGNAL(result(KJob*)), SLOT(saveResult(KJob*)) );
00265 }
00266
00267 QItemSelectionModel * BrowserWidget::collectionSelectionModel() const
00268 {
00269 return mCollectionView->selectionModel();
00270 }
00271
00272 QItemSelectionModel * BrowserWidget::itemSelectionModel() const
00273 {
00274 return itemUi.itemView->selectionModel();
00275 }
00276
00277 void BrowserWidget::saveResult(KJob * job)
00278 {
00279 if ( job->error() ) {
00280 KMessageBox::error( this, i18n( "Failed to save changes: %1", job->errorString() ) );
00281 }
00282 }
00283
00284 void BrowserWidget::addAttribute()
00285 {
00286 if ( contentUi.attrName->text().isEmpty() )
00287 return;
00288 const int row = mAttrModel->rowCount();
00289 mAttrModel->insertRow( row );
00290 QModelIndex index = mAttrModel->index( row, 0 );
00291 Q_ASSERT( index.isValid() );
00292 mAttrModel->setData( index, contentUi.attrName->text() );
00293 contentUi.attrName->clear();
00294 }
00295
00296 void BrowserWidget::delAttribute()
00297 {
00298 QModelIndexList selection = contentUi.attrView->selectionModel()->selectedRows();
00299 if ( selection.count() != 1 )
00300 return;
00301 mAttrModel->removeRow( selection.first().row() );
00302 }
00303
00304 #include "browserwidget.moc"