20 #include "selftestdialog_p.h"
21 #include "agentmanager.h"
22 #include "dbusconnectionpool.h"
23 #include "session_p.h"
24 #include "servermanager.h"
25 #include "servermanager_p.h"
27 #include <akonadi/private/xdgbasedirs_p.h>
31 #include <KFileDialog>
32 #include <KLocalizedString>
33 #include <KMessageBox>
35 #include <KStandardDirs>
38 #include <QtCore/QFileInfo>
39 #include <QtCore/QProcess>
40 #include <QtCore/QSettings>
41 #include <QtCore/QTextStream>
42 #include <QtDBus/QtDBus>
43 #include <QApplication>
45 #include <QStandardItemModel>
46 #include <QtSql/QSqlDatabase>
47 #include <QtSql/QSqlError>
51 #define AKONADI_SEARCH_SERVICE QLatin1String( "org.kde.nepomuk.services.nepomukqueryservice" )
53 using namespace Akonadi;
55 static QString makeLink(
const QString &file )
57 return QString::fromLatin1(
"<a href=\"%1\">%2</a>" ).arg( file, file );
61 ResultTypeRole = Qt::UserRole,
72 setCaption( i18n(
"Akonadi Server Self-Test" ) );
73 setButtons( Close | User1 | User2 );
74 setButtonText( User1, i18n(
"Save Report..." ) );
75 setButtonIcon( User1, KIcon( QString::fromLatin1(
"document-save" ) ) );
76 setButtonText( User2, i18n(
"Copy Report to Clipboard" ) );
77 setButtonIcon( User2, KIcon( QString::fromLatin1(
"edit-copy" ) ) );
78 showButtonSeparator(
true );
79 ui.setupUi( mainWidget() );
81 mTestModel =
new QStandardItemModel(
this );
82 ui.testView->setModel( mTestModel );
83 connect( ui.testView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
84 SLOT(selectionChanged(QModelIndex)) );
85 connect( ui.detailsLabel, SIGNAL(linkActivated(QString)), SLOT(linkActivated(QString)) );
87 connect(
this, SIGNAL(user1Clicked()), SLOT(saveReport()) );
88 connect(
this, SIGNAL(user2Clicked()), SLOT(copyReport()) );
96 ui.introductionLabel->hide();
99 QStandardItem* SelfTestDialog::report( ResultType type,
const KLocalizedString & summary,
const KLocalizedString & details)
101 QStandardItem *item =
new QStandardItem( summary.toString() );
104 item->setIcon( KIcon( QString::fromLatin1(
"dialog-ok" ) ) );
107 item->setIcon( KIcon( QString::fromLatin1(
"dialog-ok-apply" ) ) );
110 item->setIcon( KIcon( QString::fromLatin1(
"dialog-warning" ) ) );
114 item->setIcon( KIcon( QString::fromLatin1(
"dialog-error" ) ) );
116 item->setEditable(
false );
117 item->setWhatsThis( details.toString() );
118 item->setData( type, ResultTypeRole );
119 item->setData( summary.toString( 0 ), SummaryRole );
120 item->setData( details.toString( 0 ), DetailsRole );
121 mTestModel->appendRow( item );
125 void SelfTestDialog::selectionChanged(
const QModelIndex &index )
127 if ( index.isValid() ) {
128 ui.detailsLabel->setText( index.data( Qt::WhatsThisRole ).toString() );
129 ui.detailsGroup->setEnabled(
true );
131 ui.detailsLabel->setText( QString() );
132 ui.detailsGroup->setEnabled(
false );
136 void SelfTestDialog::runTests()
140 const QString driver = serverSetting( QLatin1String(
"General" ),
"Driver", QLatin1String(
"QMYSQL" ) ).toString();
142 if (driver == QLatin1String(
"QPSQL" )) {
150 testMySQLServerLog();
151 testMySQLServerConfig();
156 testProtocolVersion();
162 QVariant SelfTestDialog::serverSetting(
const QString & group,
const char *key,
const QVariant &def )
const
164 const QString serverConfigFile = XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite );
165 QSettings settings( serverConfigFile, QSettings::IniFormat );
166 settings.beginGroup( group );
167 return settings.value( QString::fromLatin1(key), def );
170 bool SelfTestDialog::useStandaloneMysqlServer()
const
172 const QString driver = serverSetting( QLatin1String(
"General" ),
"Driver", QLatin1String(
"QMYSQL" ) ).toString();
173 if ( driver != QLatin1String(
"QMYSQL" ) )
175 const bool startServer = serverSetting( driver,
"StartServer",
true ).toBool();
181 bool SelfTestDialog::runProcess(
const QString & app,
const QStringList & args, QString & result)
const
184 proc.start( app, args );
185 const bool rv = proc.waitForFinished();
187 result += QString::fromLocal8Bit( proc.readAllStandardError() );
188 result += QString::fromLocal8Bit( proc.readAllStandardOutput() );
192 void SelfTestDialog::testSQLDriver()
194 const QString driver = serverSetting( QLatin1String(
"General" ),
"Driver", QLatin1String(
"QMYSQL" ) ).toString();
195 const QStringList availableDrivers = QSqlDatabase::drivers();
196 const KLocalizedString detailsOk = ki18n(
"The QtSQL driver '%1' is required by your current Akonadi server configuration and was found on your system." )
198 const KLocalizedString detailsFail = ki18n(
"The QtSQL driver '%1' is required by your current Akonadi server configuration.\n"
199 "The following drivers are installed: %2.\n"
200 "Make sure the required driver is installed." )
202 .subs( availableDrivers.join( QLatin1String(
", " ) ) );
203 QStandardItem *item = 0;
204 if ( availableDrivers.contains( driver ) )
205 item = report( Success, ki18n(
"Database driver found." ), detailsOk );
207 item = report( Error, ki18n(
"Database driver not found." ), detailsFail );
208 item->setData( XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite ), FileIncludeRole );
211 void SelfTestDialog::testMySQLServer()
213 if ( !useStandaloneMysqlServer() ) {
214 report( Skip, ki18n(
"MySQL server executable not tested." ),
215 ki18n(
"The current configuration does not require an internal MySQL server." ) );
219 const QString driver = serverSetting( QLatin1String(
"General" ),
"Driver", QLatin1String(
"QMYSQL" ) ).toString();
220 const QString serverPath = serverSetting( driver,
"ServerPath", QLatin1String(
"" ) ).toString();
222 const KLocalizedString details = ki18n(
"You have currently configured Akonadi to use the MySQL server '%1'.\n"
223 "Make sure you have the MySQL server installed, set the correct path and ensure you have the "
224 "necessary read and execution rights on the server executable. The server executable is typically "
225 "called 'mysqld'; its location varies depending on the distribution." ).subs( serverPath );
227 QFileInfo info( serverPath );
228 if ( !info.exists() )
229 report( Error, ki18n(
"MySQL server not found." ), details );
230 else if ( !info.isReadable() )
231 report( Error, ki18n(
"MySQL server not readable." ), details );
232 else if ( !info.isExecutable() )
233 report( Error, ki18n(
"MySQL server not executable." ), details );
234 else if ( !serverPath.contains( QLatin1String(
"mysqld" ) ) )
235 report( Warning, ki18n(
"MySQL found with unexpected name." ), details );
237 report( Success, ki18n(
"MySQL server found." ), details );
241 if ( runProcess( serverPath, QStringList() << QLatin1String(
"--version" ), result ) ) {
242 const KLocalizedString details = ki18n(
"MySQL server found: %1" ).subs( result );
243 report( Success, ki18n(
"MySQL server is executable." ), details );
245 const KLocalizedString details = ki18n(
"Executing the MySQL server '%1' failed with the following error message: '%2'" )
246 .subs( serverPath ).subs( result );
247 report( Error, ki18n(
"Executing the MySQL server failed." ), details );
251 void SelfTestDialog::testMySQLServerLog()
253 if ( !useStandaloneMysqlServer() ) {
254 report( Skip, ki18n(
"MySQL server error log not tested." ),
255 ki18n(
"The current configuration does not require an internal MySQL server." ) );
259 const QString logFileName = XdgBaseDirs::saveDir(
"data", QLatin1String(
"akonadi/db_data" ) )
260 + QDir::separator() + QString::fromLatin1(
"mysql.err" );
261 const QFileInfo logFileInfo( logFileName );
262 if ( !logFileInfo.exists() || logFileInfo.size() == 0 ) {
263 report( Success, ki18n(
"No current MySQL error log found." ),
264 ki18n(
"The MySQL server did not report any errors during this startup. The log can be found in '%1'." ).subs( logFileName ) );
267 QFile logFile( logFileName );
268 if ( !logFile.open( QFile::ReadOnly | QFile::Text ) ) {
269 report( Error, ki18n(
"MySQL error log not readable." ),
270 ki18n(
"A MySQL server error log file was found but is not readable: %1" ).subs( makeLink( logFileName ) ) );
273 bool warningsFound =
false;
274 QStandardItem *item = 0;
275 while ( !logFile.atEnd() ) {
276 const QString line = QString::fromUtf8( logFile.readLine() );
277 if ( line.contains( QLatin1String(
"error" ), Qt::CaseInsensitive ) ) {
278 item = report( Error, ki18n(
"MySQL server log contains errors." ),
279 ki18n(
"The MySQL server error log file '%1' contains errors." ).subs( makeLink( logFileName ) ) );
280 item->setData( logFileName, FileIncludeRole );
283 if ( !warningsFound && line.contains( QLatin1String(
"warn" ), Qt::CaseInsensitive ) ) {
284 warningsFound =
true;
287 if ( warningsFound ) {
288 item = report( Warning, ki18n(
"MySQL server log contains warnings." ),
289 ki18n(
"The MySQL server log file '%1' contains warnings." ).subs( makeLink( logFileName ) ) );
291 item = report( Success, ki18n(
"MySQL server log contains no errors." ),
292 ki18n(
"The MySQL server log file '%1' does not contain any errors or warnings." )
293 .subs( makeLink( logFileName ) ) );
295 item->setData( logFileName, FileIncludeRole );
300 void SelfTestDialog::testMySQLServerConfig()
302 if ( !useStandaloneMysqlServer() ) {
303 report( Skip, ki18n(
"MySQL server configuration not tested." ),
304 ki18n(
"The current configuration does not require an internal MySQL server." ) );
308 QStandardItem *item = 0;
309 const QString globalConfig = XdgBaseDirs::findResourceFile(
"config", QLatin1String(
"akonadi/mysql-global.conf" ) );
310 const QFileInfo globalConfigInfo( globalConfig );
311 if ( !globalConfig.isEmpty() && globalConfigInfo.exists() && globalConfigInfo.isReadable() ) {
312 item = report( Success, ki18n(
"MySQL server default configuration found." ),
313 ki18n(
"The default configuration for the MySQL server was found and is readable at %1." )
314 .subs( makeLink( globalConfig ) ) );
315 item->setData( globalConfig, FileIncludeRole );
317 report( Error, ki18n(
"MySQL server default configuration not found." ),
318 ki18n(
"The default configuration for the MySQL server was not found or was not readable. "
319 "Check your Akonadi installation is complete and you have all required access rights." ) );
322 const QString localConfig = XdgBaseDirs::findResourceFile(
"config", QLatin1String(
"akonadi/mysql-local.conf" ) );
323 const QFileInfo localConfigInfo( localConfig );
324 if ( localConfig.isEmpty() || !localConfigInfo.exists() ) {
325 report( Skip, ki18n(
"MySQL server custom configuration not available." ),
326 ki18n(
"The custom configuration for the MySQL server was not found but is optional." ) );
327 }
else if ( localConfigInfo.exists() && localConfigInfo.isReadable() ) {
328 item = report( Success, ki18n(
"MySQL server custom configuration found." ),
329 ki18n(
"The custom configuration for the MySQL server was found and is readable at %1" )
330 .subs( makeLink( localConfig ) ) );
331 item->setData( localConfig, FileIncludeRole );
333 report( Error, ki18n(
"MySQL server custom configuration not readable." ),
334 ki18n(
"The custom configuration for the MySQL server was found at %1 but is not readable. "
335 "Check your access rights." ).subs( makeLink( localConfig ) ) );
338 const QString actualConfig = XdgBaseDirs::saveDir(
"data", QLatin1String(
"akonadi" ) ) + QLatin1String(
"/mysql.conf" );
339 const QFileInfo actualConfigInfo( actualConfig );
340 if ( actualConfig.isEmpty() || !actualConfigInfo.exists() || !actualConfigInfo.isReadable() ) {
341 report( Error, ki18n(
"MySQL server configuration not found or not readable." ),
342 ki18n(
"The MySQL server configuration was not found or is not readable." ) );
344 item = report( Success, ki18n(
"MySQL server configuration is usable." ),
345 ki18n(
"The MySQL server configuration was found at %1 and is readable." ).subs( makeLink( actualConfig ) ) );
346 item->setData( actualConfig, FileIncludeRole );
350 void SelfTestDialog::testPSQLServer()
352 const QString dbname = serverSetting( QLatin1String(
"QPSQL" ),
"Name", QLatin1String(
"akonadi" )).toString();
353 const QString hostname = serverSetting( QLatin1String(
"QPSQL" ),
"Host", QLatin1String(
"localhost" )).toString();
354 const QString username = serverSetting( QLatin1String(
"QPSQL" ),
"User", QString() ).toString();
355 const QString password = serverSetting( QLatin1String(
"QPSQL" ),
"Password", QString() ).toString();
356 const int port = serverSetting( QLatin1String(
"QPSQL" ),
"Port", 5432).toInt();
358 QSqlDatabase db = QSqlDatabase::addDatabase( QLatin1String(
"QPSQL" ) );
359 db.setHostName( hostname );
360 db.setDatabaseName( dbname );
362 if ( !username.isEmpty() )
363 db.setUserName( username );
365 if ( !password.isEmpty() )
366 db.setPassword( password );
371 const KLocalizedString details = ki18n( db.lastError().text().toLatin1() );
372 report( Error, ki18n(
"Cannot connect to PostgreSQL server." ), details);
375 report( Success, ki18n(
"PostgreSQL server found." ),
376 ki18n(
"The PostgreSQL server was found and connection is working." ));
381 void SelfTestDialog::testAkonadiCtl()
383 const QString path = KStandardDirs::findExe( QLatin1String(
"akonadictl" ) );
384 if ( path.isEmpty() ) {
385 report( Error, ki18n(
"akonadictl not found" ),
386 ki18n(
"The program 'akonadictl' needs to be accessible in $PATH. "
387 "Make sure you have the Akonadi server installed." ) );
391 if ( runProcess( path, QStringList() << QLatin1String(
"--version" ), result ) ) {
392 report( Success, ki18n(
"akonadictl found and usable" ),
393 ki18n(
"The program '%1' to control the Akonadi server was found "
394 "and could be executed successfully.\nResult:\n%2" ).subs( path ).subs( result ) );
396 report( Error, ki18n(
"akonadictl found but not usable" ),
397 ki18n(
"The program '%1' to control the Akonadi server was found "
398 "but could not be executed successfully.\nResult:\n%2\n"
399 "Make sure the Akonadi server is installed correctly." ).subs( path ).subs( result ) );
403 void SelfTestDialog::testServerStatus()
405 if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered(
ServerManager::serviceName(ServerManager::Control) ) ) {
406 report( Success, ki18n(
"Akonadi control process registered at D-Bus." ),
407 ki18n(
"The Akonadi control process is registered at D-Bus which typically indicates it is operational." ) );
409 report( Error, ki18n(
"Akonadi control process not registered at D-Bus." ),
410 ki18n(
"The Akonadi control process is not registered at D-Bus which typically means it was not started "
411 "or encountered a fatal error during startup." ) );
414 if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered(
ServerManager::serviceName(ServerManager::Server) ) ) {
415 report( Success, ki18n(
"Akonadi server process registered at D-Bus." ),
416 ki18n(
"The Akonadi server process is registered at D-Bus which typically indicates it is operational." ) );
418 report( Error, ki18n(
"Akonadi server process not registered at D-Bus." ),
419 ki18n(
"The Akonadi server process is not registered at D-Bus which typically means it was not started "
420 "or encountered a fatal error during startup." ) );
424 void SelfTestDialog::testSearchStatus()
426 bool searchAvailable =
false;
427 if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_SEARCH_SERVICE ) ) {
428 searchAvailable =
true;
429 report( Success, ki18n(
"Nepomuk search service registered at D-Bus." ),
430 ki18n(
"The Nepomuk search service is registered at D-Bus which typically indicates it is operational." ) );
432 report( Error, ki18n(
"Nepomuk search service not registered at D-Bus." ),
433 ki18n(
"The Nepomuk search service is not registered at D-Bus which typically means it was not started "
434 "or encountered a fatal error during startup." ) );
437 if ( searchAvailable ) {
439 QDBusInterface interface( QLatin1String(
"org.kde.NepomukStorage" ), QLatin1String(
"/nepomukstorage" ) );
440 const QDBusReply<QString> reply = interface.call( QLatin1String(
"usedSopranoBackend" ) );
441 if ( reply.isValid() ) {
442 const QString name = reply.value();
445 if ( name.contains( QLatin1String(
"redland" ) ) ) {
446 report( Error, ki18n(
"Nepomuk search service uses inappropriate backend." ),
447 ki18n(
"The Nepomuk search service uses the '%1' backend, which is not "
448 "recommended for use with Akonadi." ).subs( name ) );
450 report( Success, ki18n(
"Nepomuk search service uses an appropriate backend. " ),
451 ki18n(
"The Nepomuk search service uses one of the recommended backends." ) );
457 void SelfTestDialog::testProtocolVersion()
459 if ( Internal::serverProtocolVersion() < 0 ) {
460 report( Skip, ki18n(
"Protocol version check not possible." ),
461 ki18n(
"Without a connection to the server it is not possible to check if the protocol version meets the requirements." ) );
464 if ( Internal::serverProtocolVersion() < SessionPrivate::minimumProtocolVersion() ) {
465 report( Error, ki18n(
"Server protocol version is too old." ),
466 ki18n(
"The server protocol version is %1, but at least version %2 is required. "
467 "Install a newer version of the Akonadi server." )
468 .subs( Internal::serverProtocolVersion() )
469 .subs( SessionPrivate::minimumProtocolVersion() ) );
471 report( Success, ki18n(
"Server protocol version is recent enough." ),
472 ki18n(
"The server Protocol version is %1, which equal or newer than the required version %2." )
473 .subs( Internal::serverProtocolVersion() )
474 .subs( SessionPrivate::minimumProtocolVersion() ) );
478 void SelfTestDialog::testResources()
481 bool resourceFound =
false;
482 foreach (
const AgentType &type, agentTypes ) {
483 if ( type.
capabilities().contains( QLatin1String(
"Resource" ) ) ) {
484 resourceFound =
true;
489 const QStringList pathList = XdgBaseDirs::findAllResourceDirs(
"data", QLatin1String(
"akonadi/agents" ) );
490 QStandardItem *item = 0;
491 if ( resourceFound ) {
492 item = report( Success, ki18n(
"Resource agents found." ), ki18n(
"At least one resource agent has been found." ) );
494 item = report( Error, ki18n(
"No resource agents found." ),
495 ki18n(
"No resource agents have been found, Akonadi is not usable without at least one. "
496 "This usually means that no resource agents are installed or that there is a setup problem. "
497 "The following paths have been searched: '%1'. "
498 "The XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes all paths "
499 "where Akonadi agents are installed." )
500 .subs( pathList.join( QLatin1String(
" " ) ) )
501 .subs( QString::fromLocal8Bit( qgetenv(
"XDG_DATA_DIRS" ) ) ) );
503 item->setData( pathList, ListDirectoryRole );
504 item->setData( QByteArray(
"XDG_DATA_DIRS" ), EnvVarRole );
507 void Akonadi::SelfTestDialog::testServerLog()
509 QString serverLog = XdgBaseDirs::saveDir(
"data", QLatin1String(
"akonadi" ) )
510 + QDir::separator() + QString::fromLatin1(
"akonadiserver.error" );
511 QFileInfo info( serverLog );
512 if ( !info.exists() || info.size() <= 0 ) {
513 report( Success, ki18n(
"No current Akonadi server error log found." ),
514 ki18n(
"The Akonadi server did not report any errors during its current startup." ) );
516 QStandardItem *item = report( Error, ki18n(
"Current Akonadi server error log found." ),
517 ki18n(
"The Akonadi server reported errors during its current startup. The log can be found in %1." ).subs( makeLink( serverLog ) ) );
518 item->setData( serverLog, FileIncludeRole );
521 serverLog += QLatin1String(
".old" );
522 info.setFile( serverLog );
523 if ( !info.exists() || info.size() <= 0 ) {
524 report( Success, ki18n(
"No previous Akonadi server error log found." ),
525 ki18n(
"The Akonadi server did not report any errors during its previous startup." ) );
527 QStandardItem *item = report( Error, ki18n(
"Previous Akonadi server error log found." ),
528 ki18n(
"The Akonadi server reported errors during its previous startup. The log can be found in %1." ).subs( makeLink( serverLog ) ) );
529 item->setData( serverLog, FileIncludeRole );
533 void SelfTestDialog::testControlLog()
535 QString controlLog = XdgBaseDirs::saveDir(
"data", QLatin1String(
"akonadi" ) )
536 + QDir::separator() + QString::fromLatin1(
"akonadi_control.error" );
537 QFileInfo info( controlLog );
538 if ( !info.exists() || info.size() <= 0 ) {
539 report( Success, ki18n(
"No current Akonadi control error log found." ),
540 ki18n(
"The Akonadi control process did not report any errors during its current startup." ) );
542 QStandardItem *item = report( Error, ki18n(
"Current Akonadi control error log found." ),
543 ki18n(
"The Akonadi control process reported errors during its current startup. The log can be found in %1." ).subs( makeLink( controlLog ) ) );
544 item->setData( controlLog, FileIncludeRole );
547 controlLog += QLatin1String(
".old" );
548 info.setFile( controlLog );
549 if ( !info.exists() || info.size() <= 0 ) {
550 report( Success, ki18n(
"No previous Akonadi control error log found." ),
551 ki18n(
"The Akonadi control process did not report any errors during its previous startup." ) );
553 QStandardItem *item = report( Error, ki18n(
"Previous Akonadi control error log found." ),
554 ki18n(
"The Akonadi control process reported errors during its previous startup. The log can be found in %1." ).subs( makeLink( controlLog ) ) );
555 item->setData( controlLog, FileIncludeRole );
559 void SelfTestDialog::testRootUser()
562 if ( user.isSuperUser() ) {
563 report( Error, ki18n(
"Akonadi was started as root" ), ki18n(
"Running Internet-facing applications as root/administrator exposes you to many security risks. MySQL, used by this Akonadi installation, will not allow itself to run as root, to protect you from these risks." ) );
565 report( Success, ki18n(
"Akonadi is not running as root" ), ki18n(
"Akonadi is not running as a root/administrator user, which is the recommended setup for a secure system." ) );
569 QString SelfTestDialog::createReport()
572 QTextStream s( &result );
573 s <<
"Akonadi Server Self-Test Report" << endl;
574 s <<
"===============================" << endl;
576 for (
int i = 0; i < mTestModel->rowCount(); ++i ) {
577 QStandardItem *item = mTestModel->item( i );
579 s <<
"Test " << (i + 1) <<
": ";
580 switch ( item->data( ResultTypeRole ).toInt() ) {
584 s <<
"SUCCESS";
break;
586 s <<
"WARNING";
break;
591 s << endl <<
"--------" << endl;
593 s << item->data( SummaryRole ).toString() << endl;
594 s <<
"Details: " << item->data( DetailsRole ).toString() << endl;
595 if ( item->data( FileIncludeRole ).isValid() ) {
597 const QString fileName = item->data( FileIncludeRole ).toString();
599 if ( f.open( QFile::ReadOnly ) ) {
600 s <<
"File content of '" << fileName <<
"':" << endl;
601 s << f.readAll() << endl;
603 s <<
"File '" << fileName <<
"' could not be opened" << endl;
606 if ( item->data( ListDirectoryRole ).isValid() ) {
608 const QStringList pathList = item->data( ListDirectoryRole ).toStringList();
609 if ( pathList.isEmpty() )
610 s <<
"Directory list is empty." << endl;
611 foreach (
const QString &path, pathList ) {
612 s <<
"Directory listing of '" << path <<
"':" << endl;
614 dir.setFilter( QDir::AllEntries | QDir::NoDotAndDotDot );
615 foreach (
const QString &entry, dir.entryList() )
619 if ( item->data( EnvVarRole ).isValid() ) {
621 const QByteArray envVarName = item->data( EnvVarRole ).toByteArray();
622 const QByteArray envVarValue = qgetenv( envVarName );
623 s <<
"Environment variable " << envVarName <<
" is set to '" << envVarValue <<
"'" << endl;
632 void SelfTestDialog::saveReport()
634 const QString defaultFileName = QLatin1String(
"akonadi-selftest-report-" )
635 + QDate::currentDate().toString( QLatin1String(
"yyyyMMdd" ) )
636 + QLatin1String(
".txt" );
637 const QString fileName = KFileDialog::getSaveFileName( QUrl(defaultFileName), QString(),
this,
638 i18n(
"Save Test Report" ) );
639 if ( fileName.isEmpty() )
642 QFile file( fileName );
643 if ( !file.open( QFile::ReadWrite ) ) {
644 KMessageBox::error(
this, i18n(
"Could not open file '%1'", fileName ) );
648 file.write( createReport().toUtf8() );
652 void SelfTestDialog::copyReport()
654 #ifndef QT_NO_CLIPBOARD
655 QApplication::clipboard()->setText( createReport() );
659 void SelfTestDialog::linkActivated(
const QString & link)
661 KRun::runUrl( KUrl::fromPath( link ), QLatin1String(
"text/plain" ),
this );
666 #include "moc_selftestdialog_p.cpp"
static ServerManager * self()
Returns the singleton instance of this class, for connecting to its signals.
void hideIntroduction()
Hides the label with the introduction message.
static QString serviceName(ServiceType serviceType)
Returns the namespaced D-Bus service name for serviceType.
A representation of an agent type.
QList< AgentType > List
Describes a list of agent types.
QStringList capabilities() const
Returns the list of supported capabilities of the agent type.
SelfTestDialog(QWidget *parent=0)
Creates a new self test dialog.
AgentType::List types() const
Returns the list of all available agent types.
static AgentManager * self()
Returns the global instance of the agent manager.
State
Enum for the various states the server can be in.