typo found by Andrey Cherepanov
[kdepim.git] / akonadiconsole / browserwidget.cpp
blob8ac1899a9a99792f8fa9375efd4703be57a340c8
1 /*
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
17 02110-1301, USA.
20 #include "browserwidget.h"
22 #include "collectionattributespage.h"
23 #include "collectioninternalspage.h"
24 #include "collectionaclpage.h"
25 #include "settings.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>
50 #include <kdebug.h>
51 #include <kconfig.h>
52 #include <kfiledialog.h>
53 #include <kmessagebox.h>
54 #include <kxmlguiwindow.h>
56 #ifdef NEPOMUK_FOUND
57 #include <nepomuk/resource.h>
58 #include <nepomuk/resourcemanager.h>
59 #include <nepomuk/variant.h>
60 #endif
62 #include <QSplitter>
63 #include <QTextEdit>
64 #include <QVBoxLayout>
65 #include <QStackedWidget>
66 #include <QtGui/QSortFilterProxyModel>
67 #include <QStandardItemModel>
68 #include <QTimer>
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) :
77 QWidget( parent ),
78 mItemModel( 0 ),
79 mCurrentCollection( 0 ),
80 mAttrModel( 0 ),
81 #ifdef NEPOMUK_FOUND
82 mNepomukModel( 0 ),
83 #endif
84 mStdActionManager( 0 ),
85 mMonitor( 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 ) );
148 #else
149 Nepomuk::ResourceManager::instance()->init();
150 #endif
153 void BrowserWidget::collectionActivated(const QModelIndex & index)
155 mCurrentCollection = mCollectionView->model()->data( index, CollectionModel::CollectionIdRole ).toLongLong();
156 if ( mCurrentCollection <= 0 )
157 return;
158 mItemModel->setCollection( Collection( mCurrentCollection ) );
161 void BrowserWidget::itemActivated(const QModelIndex & index)
163 const Item item = mItemModel->itemForIndex( index );
164 if ( !item.isValid() )
165 return;
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!";
180 } else {
181 const Item item = fetch->items().first();
182 setItem( item );
186 void BrowserWidget::setItem( const Akonadi::Item &item )
188 mCurrentItem = 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 );
197 } else {
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" ) );
210 QStringList flags;
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 );
217 QStringList labels;
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 );
231 #ifdef NEPOMUK_FOUND
232 if ( Settings::self()->nepomukEnabled() ) {
233 Nepomuk::Resource res( item.url() );
234 delete mNepomukModel;
235 mNepomukModel = 0;
236 if ( res.isValid() ) {
237 QHash<QUrl, Nepomuk::Variant> props = res.properties();
238 mNepomukModel = new QStandardItemModel( props.count(), 2, this );
239 QStringList labels;
240 labels << i18n( "Property" ) << i18n( "Value" );
241 mNepomukModel->setHorizontalHeaderLabels( labels );
242 int row = 0;
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 );
252 } else {
253 contentUi.nepomukView->setEnabled( false );
255 contentUi.nepomukView->setModel( mNepomukModel );
256 contentUi.nepomukTab->setEnabled( true );
257 } else {
258 contentUi.nepomukTab->setEnabled( false );
260 #endif
262 if ( mMonitor )
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()
273 delete mItemModel;
274 switch ( itemUi.modelBox->currentIndex() ) {
275 case 1:
276 mItemModel = new MessageModel( this );
277 break;
278 case 2:
279 mItemModel = new KABCModel( this );
280 break;
281 case 3:
282 mItemModel = new KCalModel( this );
283 break;
284 default:
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() )
302 item.clearFlag( f );
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() );
314 Q_ASSERT( attr );
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() )
333 return;
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 )
346 return;
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() )
354 return;
355 const QString fileName = KFileDialog::getSaveFileName( KUrl(), "*.xml", this, i18n( "Select XML file" ) );
356 if ( fileName.isEmpty() )
357 return;
358 XmlWriteJob *job = new XmlWriteJob( root, fileName, this );
359 connect( job, SIGNAL(result(KJob*)), SLOT(dumpToXmlResult(KJob*)) );
362 void BrowserWidget::dumpToXmlResult( KJob* job )
364 if ( job->error() )
365 KMessageBox::error( this, job->errorString() );
368 #include "browserwidget.moc"