2 This file is part of Akonadi.
4 Copyright (c) 2006 Tobias Koenig <tokoe@kde.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22 #include "agentwidget.h"
24 #include <akonadi/agenttypedialog.h>
25 #include <akonadi/agentinstancewidget.h>
26 #include <akonadi/agentmanager.h>
27 #include <akonadi/agentinstancecreatejob.h>
28 #include <akonadi/control.h>
32 #include <KMessageBox>
33 #include <KStandardGuiItem>
35 #include <QtGui/QGridLayout>
36 #include <QtGui/QMenu>
37 #include <QtGui/QPushButton>
38 #include <QDBusInterface>
39 #include <QDBusMessage>
40 #include <QMetaObject>
41 #include <QMetaMethod>
42 #include <QResizeEvent>
44 using namespace Akonadi
;
46 AgentWidget::AgentWidget( QWidget
*parent
)
51 connect( ui
.instanceWidget
, SIGNAL(doubleClicked(Akonadi::AgentInstance
)), SLOT(configureAgent()) );
52 connect( ui
.instanceWidget
, SIGNAL(currentChanged(Akonadi::AgentInstance
,Akonadi::AgentInstance
)),
53 SLOT(currentChanged(Akonadi::AgentInstance
)) );
54 connect( ui
.instanceWidget
, SIGNAL(customContextMenuRequested(QPoint
)), SLOT(showContextMenu(QPoint
)) );
56 connect( ui
.instanceWidget
->view()->selectionModel(), SIGNAL(selectionChanged(QItemSelection
,QItemSelection
)), SLOT(selectionChanged(QItemSelection
,QItemSelection
)) );
58 currentChanged( ui
.instanceWidget
->currentAgentInstance() );
60 ui
.addButton
->setGuiItem( KStandardGuiItem::add() );
61 connect( ui
.addButton
, SIGNAL( clicked() ), this, SLOT( addAgent() ) );
63 ui
.removeButton
->setGuiItem( KStandardGuiItem::remove() );
64 connect( ui
.removeButton
, SIGNAL( clicked() ), this, SLOT( removeAgent() ) );
66 ui
.configButton
->setGuiItem( KStandardGuiItem::configure() );
67 connect( ui
.configButton
, SIGNAL( clicked() ), this, SLOT( configureAgent() ) );
69 mSyncMenu
= new QMenu( i18n("Synchronize"), this );
70 mSyncMenu
->addAction( i18n("Synchronize All"), this, SLOT(synchronizeAgent()) );
71 mSyncMenu
->addAction( i18n("Synchronize Collection Tree"), this, SLOT(synchronizeTree()) );
72 mSyncMenu
->setIcon( KIcon("view-refresh" ) );
73 ui
.syncButton
->setMenu( mSyncMenu
);
74 ui
.syncButton
->setIcon( KIcon( "view-refresh" ) );
75 connect( ui
.syncButton
, SIGNAL( clicked() ), this, SLOT( synchronizeAgent() ) );
77 ui
.abortButton
->setIcon( KIcon("dialog-cancel") );
78 connect( ui
.abortButton
, SIGNAL(clicked()), this, SLOT(abortAgent()) );
79 ui
.restartButton
->setIcon( KIcon( "system-reboot" ) ); //FIXME: Is using system-reboot icon here a good idea?
80 connect( ui
.restartButton
, SIGNAL(clicked()), SLOT(restartAgent()) );
82 Control::widgetNeedsAkonadi( this );
85 void AgentWidget::addAgent()
87 Akonadi::AgentTypeDialog
dlg( this );
89 const AgentType agentType
= dlg
.agentType();
91 if ( agentType
.isValid() ) {
92 AgentInstanceCreateJob
*job
= new AgentInstanceCreateJob( agentType
, this );
93 job
->configure( this );
94 job
->start(); // TODO: check result
99 void AgentWidget::selectionChanged(const QItemSelection
& selected
, const QItemSelection
& deselected
)
101 Q_UNUSED( selected
);
102 Q_UNUSED( deselected
);
104 const bool multiSelection
= ui
.instanceWidget
->view()->selectionModel()->selectedRows().size() > 1;
105 // Only agent removal, sync and restart is possible when multiple items are selected.
106 ui
.configButton
->setDisabled( multiSelection
);
110 void AgentWidget::removeAgent()
112 QList
<AgentInstance
> list
= ui
.instanceWidget
->selectedAgentInstances();
113 if ( !list
.isEmpty() )
115 if ( KMessageBox::questionYesNo( this,
116 i18np( "Do you really want to delete the selected agent instance?",
117 "Do you really want to delete these %1 agent instances?",
119 i18n( "Multiple Agent Deletion" ),
120 KStandardGuiItem::del(),
121 KStandardGuiItem::cancel(),
123 KMessageBox::Dangerous
)
124 == KMessageBox::Yes
)
126 foreach( const AgentInstance
&agent
, list
)
127 AgentManager::self()->removeInstance( agent
);
132 void AgentWidget::configureAgent()
134 AgentInstance agent
= ui
.instanceWidget
->currentAgentInstance();
135 if ( agent
.isValid() )
136 agent
.configure( this );
139 void AgentWidget::synchronizeAgent()
141 QList
<AgentInstance
> list
= ui
.instanceWidget
->selectedAgentInstances();
142 if ( !list
.isEmpty() )
143 foreach( AgentInstance agent
, list
)
147 void AgentWidget::toggleOnline()
149 AgentInstance agent
= ui
.instanceWidget
->currentAgentInstance();
150 if ( agent
.isValid() )
151 agent
.setIsOnline( !agent
.isOnline() );
154 void AgentWidget::synchronizeTree()
156 QList
<AgentInstance
> list
= ui
.instanceWidget
->selectedAgentInstances();
157 if ( !list
.isEmpty() )
158 foreach( AgentInstance agent
, list
)
159 agent
.synchronizeCollectionTree();
162 void AgentWidget::abortAgent()
164 QList
<AgentInstance
> list
= ui
.instanceWidget
->selectedAgentInstances();
165 if ( !list
.isEmpty() )
166 foreach( AgentInstance agent
, list
)
167 agent
.abortCurrentTask();
170 void AgentWidget::restartAgent()
172 AgentInstance agent
= ui
.instanceWidget
->currentAgentInstance();
173 if ( agent
.isValid() )
177 void AgentWidget::cloneAgent()
179 mCloneSource
= ui
.instanceWidget
->currentAgentInstance();
180 if ( !mCloneSource
.isValid() )
182 const AgentType agentType
= mCloneSource
.type();
183 if ( agentType
.isValid() ) {
184 AgentInstanceCreateJob
*job
= new AgentInstanceCreateJob( agentType
, this );
185 connect( job
, SIGNAL(result(KJob
*)), SLOT(cloneAgent(KJob
*)) );
188 kWarning() << "WTF?";
192 void AgentWidget::cloneAgent( KJob
* job
)
194 if ( job
->error() ) {
195 KMessageBox::error( this, i18n("Cloneing agent failed: %1.", job
->errorText() ) );
199 AgentInstance cloneTarget
= static_cast<AgentInstanceCreateJob
*>( job
)->instance();
200 Q_ASSERT( cloneTarget
.isValid() );
201 Q_ASSERT( mCloneSource
.isValid() );
203 QDBusInterface
sourceIface( QString::fromLatin1("org.freedesktop.Akonadi.Agent.%1").arg( mCloneSource
.identifier() ),
205 if ( !sourceIface
.isValid() ) {
206 kError() << "Unable to obtain KConfigXT D-Bus interface of source agent" << mCloneSource
.identifier();
210 QDBusInterface
targetIface( QString::fromLatin1("org.freedesktop.Akonadi.Agent.%1").arg( cloneTarget
.identifier() ),
212 if ( !targetIface
.isValid() ) {
213 kError() << "Unable to obtain KConfigXT D-Bus interface of target agent" << cloneTarget
.identifier();
217 cloneTarget
.setName( mCloneSource
.name() + " (Clone)" );
219 // iterate over all getter methods in the source interface and call the
220 // corresponding setter in the target interface
221 for ( int i
= 0; i
< sourceIface
.metaObject()->methodCount(); ++i
) {
222 const QMetaMethod method
= sourceIface
.metaObject()->method( i
);
223 if ( QByteArray( method
.typeName() ).isEmpty() ) // returns void
225 const QByteArray
signature( method
.signature() );
226 if ( signature
.isEmpty() )
228 if ( signature
.startsWith( "set" ) || !signature
.contains( "()" ) ) // setter or takes parameters // krazy:exclude=strings
230 if ( signature
.startsWith( "Introspect" ) ) // D-Bus stuff // krazy:exclude=strings
232 const QString methodName
= QString::fromLatin1( signature
.left( signature
.indexOf( '(' ) ) );
233 const QDBusMessage reply
= sourceIface
.call( methodName
);
234 if ( !reply
.arguments().count() == 1 ) {
235 kError() << "call to method" << signature
<< "failed: " << reply
.arguments() << reply
.errorMessage();
238 const QString setterName
= QLatin1String("set") + methodName
.at( 0 ).toUpper() + methodName
.mid( 1 );
239 targetIface
.call( setterName
, reply
.arguments().at( 0 ) );
242 cloneTarget
.reconfigure();
245 void AgentWidget::currentChanged(const Akonadi::AgentInstance
& instance
)
247 ui
.removeButton
->setEnabled( instance
.isValid() );
248 ui
.configButton
->setEnabled( instance
.isValid() );
249 ui
.syncButton
->setEnabled( instance
.isValid() );
250 ui
.restartButton
->setEnabled( instance
.isValid() );
252 if ( instance
.isValid() ) {
253 ui
.identifierLabel
->setText( instance
.identifier() );
254 ui
.typeLabel
->setText( instance
.type().name() );
255 QString onlineStatus
= ( instance
.isOnline() ? i18n( "Online" ) : i18n( "Offline" ) );
257 switch( instance
.status() ) {
258 case AgentInstance::Idle
: agentStatus
= i18n( "Idle" ); break;
259 case AgentInstance::Running
: agentStatus
= i18n( "Running (%1%)", instance
.progress() ); break;
260 case AgentInstance::Broken
: agentStatus
= i18n( "Broken" ); break;
262 ui
.statusLabel
->setText( i18nc( "Two statuses, for example \"Online, Running (66%)\" or \"Offline, Broken\"",
263 "%1, %2", onlineStatus
, agentStatus
) );
264 ui
.statusMessageLabel
->setText( instance
.statusMessage() );
265 ui
.capabilitiesLabel
->setText( instance
.type().capabilities().join( ", " ) );
266 ui
.mimeTypeLabel
->setText( instance
.type().mimeTypes().join( ", " ) );
268 ui
.identifierLabel
->setText( QString() );
269 ui
.typeLabel
->setText( QString() );
270 ui
.statusLabel
->setText( QString() );
271 ui
.capabilitiesLabel
->setText( QString() );
272 ui
.mimeTypeLabel
->setText( QString() );
276 void AgentWidget::showContextMenu(const QPoint
& pos
)
279 menu
.addAction( KIcon("list-add"), i18n("Add Agent..."), this, SLOT(addAgent()) );
280 menu
.addAction( KIcon("edit-copy"), i18n("Clone Agent"), this, SLOT(cloneAgent()) );
282 menu
.addMenu( mSyncMenu
);
283 menu
.addAction( KIcon("dialog-cancel"), i18n("Abort Activity"), this, SLOT(abortAgent()) );
284 menu
.addAction( KIcon("system-reboot"), i18n("Restart Agent"), this, SLOT(restartAgent()) ); //FIXME: Is using system-reboot icon here a good idea?
285 menu
.addAction( KIcon("network-disconnect"), i18n("Toggle Online/Offline"), this, SLOT(toggleOnline()) );
286 menu
.addAction( KIcon("configure"), i18n("Configure..."), this, SLOT(configureAgent()) );
287 menu
.addAction( KIcon("list-remove"), i18n("Remove Agent"), this, SLOT(removeAgent()) );
288 menu
.exec( mapToGlobal( pos
) );
291 void AgentWidget::resizeEvent( QResizeEvent
*event
)
293 ui
.detailsBox
->setVisible( event
->size().height() > 400 );
296 #include "agentwidget.moc"