2 Copyright (c) 2007 Volker Krause <vkrause@kde.org>
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 #include "browserwidget.h"
22 #include "collectionattributespage.h"
23 #include "collectioninternalspage.h"
24 #include "collectionaclpage.h"
27 #include <akonadi/attributefactory.h>
28 #include <akonadi/job.h>
29 #include <akonadi/collectionmodel.h>
30 #include <akonadi/collectionview.h>
31 #include <akonadi/control.h>
32 #include <akonadi/item.h>
33 #include <akonadi/itemfetchjob.h>
34 #include <akonadi/itemfetchscope.h>
35 #include <akonadi/itemmodifyjob.h>
36 #include <akonadi/collectionfilterproxymodel.h>
37 #include <akonadi/collectionpropertiesdialog.h>
38 #include <akonadi/standardactionmanager.h>
39 #include <akonadi/monitor.h>
40 #include <akonadi/xml/xmlwritejob.h>
42 #include <kcal/kcalmodel.h>
43 #include <kcal/incidence.h>
44 #include <kabc/kabcmodel.h>
45 #include <kabc/kabcitembrowser.h>
46 #include <akonadi/kmime/messagemodel.h>
48 #include <libkdepim/addresseeview.h>
52 #include <kfiledialog.h>
53 #include <kmessagebox.h>
54 #include <kxmlguiwindow.h>
57 #include <nepomuk/resource.h>
58 #include <nepomuk/resourcemanager.h>
59 #include <nepomuk/variant.h>
64 #include <QVBoxLayout>
65 #include <QStackedWidget>
66 #include <QtGui/QSortFilterProxyModel>
67 #include <QStandardItemModel>
70 using namespace Akonadi
;
72 AKONADI_COLLECTION_PROPERTIES_PAGE_FACTORY(CollectionAttributePageFactory
, CollectionAttributePage
)
73 AKONADI_COLLECTION_PROPERTIES_PAGE_FACTORY(CollectionInternalsPageFactory
, CollectionInternalsPage
)
74 AKONADI_COLLECTION_PROPERTIES_PAGE_FACTORY(CollectionAclPageFactory
, CollectionAclPage
)
76 BrowserWidget::BrowserWidget(KXmlGuiWindow
*xmlGuiWindow
, QWidget
* parent
) :
79 mCurrentCollection( 0 ),
84 mStdActionManager( 0 ),
87 Q_ASSERT( xmlGuiWindow
);
88 QVBoxLayout
*layout
= new QVBoxLayout( this );
90 QSplitter
*splitter
= new QSplitter( Qt::Horizontal
, this );
91 splitter
->setObjectName( "collectionSplitter" );
92 layout
->addWidget( splitter
);
94 mCollectionView
= new Akonadi::CollectionView( xmlGuiWindow
);
95 connect( mCollectionView
, SIGNAL(clicked(QModelIndex
)), SLOT(collectionActivated(QModelIndex
)) );
96 splitter
->addWidget( mCollectionView
);
98 mCollectionModel
= new Akonadi::CollectionModel( this );
99 QSortFilterProxyModel
*sortModel
= new QSortFilterProxyModel( this );
100 sortModel
->setDynamicSortFilter( true );
101 sortModel
->setSortCaseSensitivity( Qt::CaseInsensitive
);
102 sortModel
->setSourceModel( mCollectionModel
);
103 mCollectionView
->setModel( sortModel
);
105 QSplitter
*splitter2
= new QSplitter( Qt::Vertical
, this );
106 splitter2
->setObjectName( "itemSplitter" );
107 splitter
->addWidget( splitter2
);
109 QWidget
*itemViewParent
= new QWidget( this );
110 itemUi
.setupUi( itemViewParent
);
112 itemUi
.modelBox
->addItem( "Generic" );
113 itemUi
.modelBox
->addItem( "Mail" );
114 itemUi
.modelBox
->addItem( "Contacts" );
115 itemUi
.modelBox
->addItem( "Calendar" );
116 connect( itemUi
.modelBox
, SIGNAL(activated(int)), SLOT(modelChanged()) );
117 QTimer::singleShot( 0, this, SLOT(modelChanged()) );
119 itemUi
.itemView
->setXmlGuiWindow( xmlGuiWindow
);
120 itemUi
.itemView
->setModel( mItemModel
);
121 itemUi
.itemView
->setSelectionMode( QAbstractItemView::ExtendedSelection
);
122 connect( itemUi
.itemView
, SIGNAL(activated(QModelIndex
)), SLOT(itemActivated(QModelIndex
)) );
123 connect( itemUi
.itemView
, SIGNAL(clicked(QModelIndex
)), SLOT(itemActivated(QModelIndex
)) );
124 splitter2
->addWidget( itemViewParent
);
125 itemViewParent
->layout()->setMargin( 0 );
127 QWidget
*contentViewParent
= new QWidget( this );
128 contentUi
.setupUi( contentViewParent
);
129 connect( contentUi
.saveButton
, SIGNAL(clicked()), SLOT(save()) );
130 splitter2
->addWidget( contentViewParent
);
132 connect( contentUi
.attrAddButton
, SIGNAL(clicked()), SLOT(addAttribute()) );
133 connect( contentUi
.attrDeleteButton
, SIGNAL(clicked()), SLOT(delAttribute()) );
135 CollectionPropertiesDialog::registerPage( new CollectionAclPageFactory() );
136 CollectionPropertiesDialog::registerPage( new CollectionAttributePageFactory() );
137 CollectionPropertiesDialog::registerPage( new CollectionInternalsPageFactory() );
139 Control::widgetNeedsAkonadi( this );
141 mStdActionManager
= new StandardActionManager( xmlGuiWindow
->actionCollection(), xmlGuiWindow
);
142 mStdActionManager
->setCollectionSelectionModel( mCollectionView
->selectionModel() );
143 mStdActionManager
->setItemSelectionModel( itemUi
.itemView
->selectionModel() );
144 mStdActionManager
->createAllActions();
146 #ifndef NEPOMUK_FOUND
147 contentUi
.mainTabWidget
->removeTab( contentUi
.mainTabWidget
->indexOf( contentUi
.nepomukTab
) );
149 Nepomuk::ResourceManager::instance()->init();
153 void BrowserWidget::collectionActivated(const QModelIndex
& index
)
155 mCurrentCollection
= mCollectionView
->model()->data( index
, CollectionModel::CollectionIdRole
).toLongLong();
156 if ( mCurrentCollection
<= 0 )
158 mItemModel
->setCollection( Collection( mCurrentCollection
) );
161 void BrowserWidget::itemActivated(const QModelIndex
& index
)
163 const Item item
= mItemModel
->itemForIndex( index
);
164 if ( !item
.isValid() )
167 ItemFetchJob
*job
= new ItemFetchJob( item
, this );
168 job
->fetchScope().fetchFullPayload();
169 job
->fetchScope().fetchAllAttributes();
170 connect( job
, SIGNAL(result(KJob
*)), SLOT(itemFetchDone(KJob
*)) );
173 void BrowserWidget::itemFetchDone(KJob
* job
)
175 ItemFetchJob
*fetch
= static_cast<ItemFetchJob
*>( job
);
176 if ( job
->error() ) {
177 kWarning( 5265 ) << "Item fetch failed: " << job
->errorString();
178 } else if ( fetch
->items().isEmpty() ) {
179 kWarning( 5265 ) << "No item found!";
181 const Item item
= fetch
->items().first();
186 void BrowserWidget::setItem( const Akonadi::Item
&item
)
189 if ( item
.hasPayload
<KABC::Addressee
>() ) {
190 const KABC::Addressee addr
= item
.payload
<KABC::Addressee
>();
192 contentUi
.addresseeView
->setAddressee( addr
);
193 contentUi
.stack
->setCurrentWidget( contentUi
.addresseeViewPage
);
194 } else if ( item
.hasPayload
<KCal::Incidence::Ptr
>() ) {
195 contentUi
.incidenceView
->setItem( item
);
196 contentUi
.stack
->setCurrentWidget( contentUi
.incidenceViewPage
);
198 contentUi
.stack
->setCurrentWidget( contentUi
.unsupportedTypePage
);
201 QByteArray data
= item
.payloadData();
202 contentUi
.dataView
->setPlainText( data
);
204 contentUi
.id
->setText( QString::number( item
.id() ) );
205 contentUi
.remoteId
->setText( item
.remoteId() );
206 contentUi
.mimeType
->setText( item
.mimeType() );
207 contentUi
.revision
->setText( QString::number( item
.revision() ) );
208 contentUi
.size
->setText( QString::number( item
.size() ) );
209 contentUi
.modificationtime
->setText( item
.modificationTime().toString() + ( " UTC" ) );
211 foreach ( const Item::Flag
&f
, item
.flags() )
212 flags
<< QString::fromUtf8( f
);
213 contentUi
.flags
->setItems( flags
);
215 Attribute::List list
= item
.attributes();
216 mAttrModel
= new QStandardItemModel( list
.count(), 2 );
218 labels
<< i18n( "Attribute" ) << i18n( "Value" );
219 mAttrModel
->setHorizontalHeaderLabels( labels
);
220 for ( int i
= 0; i
< list
.count(); ++i
) {
221 QModelIndex index
= mAttrModel
->index( i
, 0 );
222 Q_ASSERT( index
.isValid() );
223 mAttrModel
->setData( index
, QString::fromLatin1( list
[i
]->type() ) );
224 index
= mAttrModel
->index( i
, 1 );
225 Q_ASSERT( index
.isValid() );
226 mAttrModel
->setData( index
, QString::fromLatin1( list
[i
]->serialized() ) );
227 mAttrModel
->itemFromIndex( index
)->setFlags( Qt::ItemIsEditable
| mAttrModel
->flags( index
) );
229 contentUi
.attrView
->setModel( mAttrModel
);
232 if ( Settings::self()->nepomukEnabled() ) {
233 Nepomuk::Resource
res( item
.url() );
234 delete mNepomukModel
;
236 if ( res
.isValid() ) {
237 QHash
<QUrl
, Nepomuk::Variant
> props
= res
.properties();
238 mNepomukModel
= new QStandardItemModel( props
.count(), 2, this );
240 labels
<< i18n( "Property" ) << i18n( "Value" );
241 mNepomukModel
->setHorizontalHeaderLabels( labels
);
243 for ( QHash
<QUrl
, Nepomuk::Variant
>::ConstIterator it
= props
.constBegin(); it
!= props
.constEnd(); ++it
, ++row
) {
244 QModelIndex index
= mNepomukModel
->index( row
, 0 );
245 Q_ASSERT( index
.isValid() );
246 mNepomukModel
->setData( index
, it
.key().toString() );
247 index
= mNepomukModel
->index( row
, 1 );
248 Q_ASSERT( index
.isValid() );
249 mNepomukModel
->setData( index
, it
.value().toString() );
251 contentUi
.nepomukView
->setEnabled( true );
253 contentUi
.nepomukView
->setEnabled( false );
255 contentUi
.nepomukView
->setModel( mNepomukModel
);
256 contentUi
.nepomukTab
->setEnabled( true );
258 contentUi
.nepomukTab
->setEnabled( false );
263 mMonitor
->deleteLater(); // might be the one calling us
264 mMonitor
= new Monitor( this );
265 mMonitor
->setItemMonitored( item
);
266 mMonitor
->itemFetchScope().fetchFullPayload();
267 mMonitor
->itemFetchScope().fetchAllAttributes();
268 connect( mMonitor
, SIGNAL(itemChanged(Akonadi::Item
,QSet
<QByteArray
>)), SLOT(setItem(Akonadi::Item
)) );
271 void BrowserWidget::modelChanged()
274 switch ( itemUi
.modelBox
->currentIndex() ) {
276 mItemModel
= new MessageModel( this );
279 mItemModel
= new KABCModel( this );
282 mItemModel
= new KCalModel( this );
285 mItemModel
= new ItemModel( this );
287 itemUi
.itemView
->setModel( mItemModel
);
288 if ( mCurrentCollection
> 0 )
289 mItemModel
->setCollection( Collection( mCurrentCollection
) );
290 if ( mStdActionManager
)
291 mStdActionManager
->setItemSelectionModel( itemUi
.itemView
->selectionModel() );
294 void BrowserWidget::save()
296 Q_ASSERT( mAttrModel
);
298 const QByteArray data
= contentUi
.dataView
->toPlainText().toUtf8();
299 Item item
= mCurrentItem
;
300 item
.setRemoteId( contentUi
.remoteId
->text() );
301 foreach ( const Item::Flag
&f
, mCurrentItem
.flags() )
303 foreach ( const QString
&s
, contentUi
.flags
->items() )
304 item
.setFlag( s
.toUtf8() );
305 item
.setPayloadFromData( data
);
307 item
.clearAttributes();
308 for ( int i
= 0; i
< mAttrModel
->rowCount(); ++i
) {
309 const QModelIndex typeIndex
= mAttrModel
->index( i
, 0 );
310 Q_ASSERT( typeIndex
.isValid() );
311 const QModelIndex valueIndex
= mAttrModel
->index( i
, 1 );
312 Q_ASSERT( valueIndex
.isValid() );
313 Attribute
* attr
= AttributeFactory::createAttribute( mAttrModel
->data( typeIndex
).toString().toLatin1() );
315 attr
->deserialize( mAttrModel
->data( valueIndex
).toString().toLatin1() );
316 item
.addAttribute( attr
);
319 ItemModifyJob
*store
= new ItemModifyJob( item
, this );
320 connect( store
, SIGNAL(result(KJob
*)), SLOT(saveResult(KJob
*)) );
323 void BrowserWidget::saveResult(KJob
* job
)
325 if ( job
->error() ) {
326 KMessageBox::error( this, i18n( "Failed to save changes: %1", job
->errorString() ) );
330 void BrowserWidget::addAttribute()
332 if ( contentUi
.attrName
->text().isEmpty() )
334 const int row
= mAttrModel
->rowCount();
335 mAttrModel
->insertRow( row
);
336 QModelIndex index
= mAttrModel
->index( row
, 0 );
337 Q_ASSERT( index
.isValid() );
338 mAttrModel
->setData( index
, contentUi
.attrName
->text() );
339 contentUi
.attrName
->clear();
342 void BrowserWidget::delAttribute()
344 QModelIndexList selection
= contentUi
.attrView
->selectionModel()->selectedRows();
345 if ( selection
.count() != 1 )
347 mAttrModel
->removeRow( selection
.first().row() );
350 void BrowserWidget::dumpToXml()
352 const Collection root
= mCollectionView
->currentIndex().data( CollectionModel::CollectionRole
).value
<Collection
>();
353 if ( !root
.isValid() )
355 const QString fileName
= KFileDialog::getSaveFileName( KUrl(), "*.xml", this, i18n( "Select XML file" ) );
356 if ( fileName
.isEmpty() )
358 XmlWriteJob
*job
= new XmlWriteJob( root
, fileName
, this );
359 connect( job
, SIGNAL(result(KJob
*)), SLOT(dumpToXmlResult(KJob
*)) );
362 void BrowserWidget::dumpToXmlResult( KJob
* job
)
365 KMessageBox::error( this, job
->errorString() );
368 #include "browserwidget.moc"