20 #include "selftestdialog_p.h"
21 #include "agentmanager.h"
22 #include "dbusconnectionpool.h"
23 #include "session_p.h"
24 #include "servermanager_p.h"
26 #include <akonadi/private/xdgbasedirs_p.h>
30 #include <KFileDialog>
32 #include <KMessageBox>
34 #include <KStandardDirs>
37 #include <QtCore/QFileInfo>
38 #include <QtCore/QProcess>
39 #include <QtCore/QSettings>
40 #include <QtCore/QTextStream>
41 #include <QtDBus/QtDBus>
42 #include <QtGui/QApplication>
43 #include <QtGui/QClipboard>
44 #include <QtGui/QStandardItemModel>
45 #include <QtSql/QSqlDatabase>
46 #include <QtSql/QSqlError>
50 #define AKONADI_CONTROL_SERVICE QLatin1String( "org.freedesktop.Akonadi.Control" )
51 #define AKONADI_SERVER_SERVICE QLatin1String( "org.freedesktop.Akonadi" )
52 #define AKONADI_SEARCH_SERVICE QLatin1String( "org.kde.nepomuk.services.nepomukqueryservice" )
54 using namespace Akonadi;
56 static QString makeLink(
const QString &file )
58 return QString::fromLatin1(
"<a href=\"%1\">%2</a>" ).arg( file, file );
62 ResultTypeRole = Qt::UserRole,
70 SelfTestDialog::SelfTestDialog(QWidget * parent) :
73 setCaption( i18n(
"Akonadi Server Self-Test" ) );
74 setButtons( Close | User1 | User2 );
75 setButtonText( User1, i18n(
"Save Report..." ) );
76 setButtonIcon( User1, KIcon( QString::fromLatin1(
"document-save" ) ) );
77 setButtonText( User2, i18n(
"Copy Report to Clipboard" ) );
78 setButtonIcon( User2, KIcon( QString::fromLatin1(
"edit-copy" ) ) );
79 showButtonSeparator(
true );
80 ui.setupUi( mainWidget() );
82 mTestModel =
new QStandardItemModel(
this );
83 ui.testView->setModel( mTestModel );
84 connect( ui.testView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
85 SLOT(selectionChanged(QModelIndex)) );
86 connect( ui.detailsLabel, SIGNAL(linkActivated(QString)), SLOT(linkActivated(QString)) );
88 connect(
this, SIGNAL(user1Clicked()), SLOT(saveReport()) );
89 connect(
this, SIGNAL(user2Clicked()), SLOT(copyReport()) );
91 connect( ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)), SLOT(runTests()) );
95 void SelfTestDialog::hideIntroduction()
97 ui.introductionLabel->hide();
100 QStandardItem* SelfTestDialog::report( ResultType type,
const KLocalizedString & summary,
const KLocalizedString & details)
102 QStandardItem *item =
new QStandardItem( summary.toString() );
105 item->setIcon( KIcon( QString::fromLatin1(
"dialog-ok" ) ) );
108 item->setIcon( KIcon( QString::fromLatin1(
"dialog-ok-apply" ) ) );
111 item->setIcon( KIcon( QString::fromLatin1(
"dialog-warning" ) ) );
115 item->setIcon( KIcon( QString::fromLatin1(
"dialog-error" ) ) );
117 item->setEditable(
false );
118 item->setWhatsThis( details.toString() );
119 item->setData( type, ResultTypeRole );
120 item->setData( summary.toString( 0 ), SummaryRole );
121 item->setData( details.toString( 0 ), DetailsRole );
122 mTestModel->appendRow( item );
126 void SelfTestDialog::selectionChanged(
const QModelIndex &index )
128 if ( index.isValid() ) {
129 ui.detailsLabel->setText( index.data( Qt::WhatsThisRole ).toString() );
130 ui.detailsGroup->setEnabled(
true );
132 ui.detailsLabel->setText( QString() );
133 ui.detailsGroup->setEnabled(
false );
137 void SelfTestDialog::runTests()
141 const QString driver = serverSetting( QLatin1String(
"General" ),
"Driver", QLatin1String(
"QMYSQL" ) ).toString();
143 if (driver == QLatin1String(
"QPSQL" )) {
151 testMySQLServerLog();
152 testMySQLServerConfig();
157 testProtocolVersion();
163 QVariant SelfTestDialog::serverSetting(
const QString & group,
const char *key,
const QVariant &def )
const
165 const QString serverConfigFile = XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite );
166 QSettings settings( serverConfigFile, QSettings::IniFormat );
167 settings.beginGroup( group );
168 return settings.value( QString::fromLatin1(key), def );
171 bool SelfTestDialog::useStandaloneMysqlServer()
const
173 const QString driver = serverSetting( QLatin1String(
"General" ),
"Driver", QLatin1String(
"QMYSQL" ) ).toString();
174 if ( driver != QLatin1String(
"QMYSQL" ) )
176 const bool startServer = serverSetting( driver,
"StartServer",
true ).toBool();
182 bool SelfTestDialog::runProcess(
const QString & app,
const QStringList & args, QString & result)
const
185 proc.start( app, args );
186 const bool rv = proc.waitForFinished();
188 result += QString::fromLocal8Bit( proc.readAllStandardError() );
189 result += QString::fromLocal8Bit( proc.readAllStandardOutput() );
193 void SelfTestDialog::testSQLDriver()
195 const QString driver = serverSetting( QLatin1String(
"General" ),
"Driver", QLatin1String(
"QMYSQL" ) ).toString();
196 const QStringList availableDrivers = QSqlDatabase::drivers();
197 const KLocalizedString detailsOk = ki18n(
"The QtSQL driver '%1' is required by your current Akonadi server configuration and was found on your system." )
199 const KLocalizedString detailsFail = ki18n(
"The QtSQL driver '%1' is required by your current Akonadi server configuration.\n"
200 "The following drivers are installed: %2.\n"
201 "Make sure the required driver is installed." )
203 .subs( availableDrivers.join( QLatin1String(
", " ) ) );
204 QStandardItem *item = 0;
205 if ( availableDrivers.contains( driver ) )
206 item = report( Success, ki18n(
"Database driver found." ), detailsOk );
208 item = report( Error, ki18n(
"Database driver not found." ), detailsFail );
209 item->setData( XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite ), FileIncludeRole );
212 void SelfTestDialog::testMySQLServer()
214 if ( !useStandaloneMysqlServer() ) {
215 report( Skip, ki18n(
"MySQL server executable not tested." ),
216 ki18n(
"The current configuration does not require an internal MySQL server." ) );
220 const QString driver = serverSetting( QLatin1String(
"General" ),
"Driver", QLatin1String(
"QMYSQL" ) ).toString();
221 const QString serverPath = serverSetting( driver,
"ServerPath", QLatin1String(
"" ) ).toString();
223 const KLocalizedString details = ki18n(
"You have currently configured Akonadi to use the MySQL server '%1'.\n"
224 "Make sure you have the MySQL server installed, set the correct path and ensure you have the "
225 "necessary read and execution rights on the server executable. The server executable is typically "
226 "called 'mysqld'; its location varies depending on the distribution." ).subs( serverPath );
228 QFileInfo info( serverPath );
229 if ( !info.exists() )
230 report( Error, ki18n(
"MySQL server not found." ), details );
231 else if ( !info.isReadable() )
232 report( Error, ki18n(
"MySQL server not readable." ), details );
233 else if ( !info.isExecutable() )
234 report( Error, ki18n(
"MySQL server not executable." ), details );
235 else if ( !serverPath.contains( QLatin1String(
"mysqld" ) ) )
236 report( Warning, ki18n(
"MySQL found with unexpected name." ), details );
238 report( Success, ki18n(
"MySQL server found." ), details );
242 if ( runProcess( serverPath, QStringList() << QLatin1String(
"--version" ), result ) ) {
243 const KLocalizedString details = ki18n(
"MySQL server found: %1" ).subs( result );
244 report( Success, ki18n(
"MySQL server is executable." ), details );
246 const KLocalizedString details = ki18n(
"Executing the MySQL server '%1' failed with the following error message: '%2'" )
247 .subs( serverPath ).subs( result );
248 report( Error, ki18n(
"Executing the MySQL server failed." ), details );
252 void SelfTestDialog::testMySQLServerLog()
254 if ( !useStandaloneMysqlServer() ) {
255 report( Skip, ki18n(
"MySQL server error log not tested." ),
256 ki18n(
"The current configuration does not require an internal MySQL server." ) );
260 const QString logFileName = XdgBaseDirs::saveDir(
"data", QLatin1String(
"akonadi/db_data" ) )
261 + QDir::separator() + QString::fromLatin1(
"mysql.err" );
262 const QFileInfo logFileInfo( logFileName );
263 if ( !logFileInfo.exists() || logFileInfo.size() == 0 ) {
264 report( Success, ki18n(
"No current MySQL error log found." ),
265 ki18n(
"The MySQL server did not report any errors during this startup. The log can be found in '%1'." ).subs( logFileName ) );
268 QFile logFile( logFileName );
269 if ( !logFile.open( QFile::ReadOnly | QFile::Text ) ) {
270 report( Error, ki18n(
"MySQL error log not readable." ),
271 ki18n(
"A MySQL server error log file was found but is not readable: %1" ).subs( makeLink( logFileName ) ) );
274 bool warningsFound =
false;
275 QStandardItem *item = 0;
276 while ( !logFile.atEnd() ) {
277 const QString line = QString::fromUtf8( logFile.readLine() );
278 if ( line.contains( QLatin1String(
"error" ), Qt::CaseInsensitive ) ) {
279 item = report( Error, ki18n(
"MySQL server log contains errors." ),
280 ki18n(
"The MySQL server error log file '%1' contains errors." ).subs( makeLink( logFileName ) ) );
281 item->setData( logFileName, FileIncludeRole );
284 if ( !warningsFound && line.contains( QLatin1String(
"warn" ), Qt::CaseInsensitive ) ) {
285 warningsFound =
true;
288 if ( warningsFound ) {
289 item = report( Warning, ki18n(
"MySQL server log contains warnings." ),
290 ki18n(
"The MySQL server log file '%1' contains warnings." ).subs( makeLink( logFileName ) ) );
292 item = report( Success, ki18n(
"MySQL server log contains no errors." ),
293 ki18n(
"The MySQL server log file '%1' does not contain any errors or warnings." )
294 .subs( makeLink( logFileName ) ) );
296 item->setData( logFileName, FileIncludeRole );
301 void SelfTestDialog::testMySQLServerConfig()
303 if ( !useStandaloneMysqlServer() ) {
304 report( Skip, ki18n(
"MySQL server configuration not tested." ),
305 ki18n(
"The current configuration does not require an internal MySQL server." ) );
309 QStandardItem *item = 0;
310 const QString globalConfig = XdgBaseDirs::findResourceFile(
"config", QLatin1String(
"akonadi/mysql-global.conf" ) );
311 const QFileInfo globalConfigInfo( globalConfig );
312 if ( !globalConfig.isEmpty() && globalConfigInfo.exists() && globalConfigInfo.isReadable() ) {
313 item = report( Success, ki18n(
"MySQL server default configuration found." ),
314 ki18n(
"The default configuration for the MySQL server was found and is readable at %1." )
315 .subs( makeLink( globalConfig ) ) );
316 item->setData( globalConfig, FileIncludeRole );
318 report( Error, ki18n(
"MySQL server default configuration not found." ),
319 ki18n(
"The default configuration for the MySQL server was not found or was not readable. "
320 "Check your Akonadi installation is complete and you have all required access rights." ) );
323 const QString localConfig = XdgBaseDirs::findResourceFile(
"config", QLatin1String(
"akonadi/mysql-local.conf" ) );
324 const QFileInfo localConfigInfo( localConfig );
325 if ( localConfig.isEmpty() || !localConfigInfo.exists() ) {
326 report( Skip, ki18n(
"MySQL server custom configuration not available." ),
327 ki18n(
"The custom configuration for the MySQL server was not found but is optional." ) );
328 }
else if ( localConfigInfo.exists() && localConfigInfo.isReadable() ) {
329 item = report( Success, ki18n(
"MySQL server custom configuration found." ),
330 ki18n(
"The custom configuration for the MySQL server was found and is readable at %1" )
331 .subs( makeLink( localConfig ) ) );
332 item->setData( localConfig, FileIncludeRole );
334 report( Error, ki18n(
"MySQL server custom configuration not readable." ),
335 ki18n(
"The custom configuration for the MySQL server was found at %1 but is not readable. "
336 "Check your access rights." ).subs( makeLink( localConfig ) ) );
339 const QString actualConfig = XdgBaseDirs::saveDir(
"data", QLatin1String(
"akonadi" ) ) + QLatin1String(
"/mysql.conf" );
340 const QFileInfo actualConfigInfo( actualConfig );
341 if ( actualConfig.isEmpty() || !actualConfigInfo.exists() || !actualConfigInfo.isReadable() ) {
342 report( Error, ki18n(
"MySQL server configuration not found or not readable." ),
343 ki18n(
"The MySQL server configuration was not found or is not readable." ) );
345 item = report( Success, ki18n(
"MySQL server configuration is usable." ),
346 ki18n(
"The MySQL server configuration was found at %1 and is readable." ).subs( makeLink( actualConfig ) ) );
347 item->setData( actualConfig, FileIncludeRole );
351 void SelfTestDialog::testPSQLServer()
353 const QString dbname = serverSetting( QLatin1String(
"QPSQL" ),
"Name", QLatin1String(
"akonadi" )).toString();
354 const QString hostname = serverSetting( QLatin1String(
"QPSQL" ),
"Host", QLatin1String(
"localhost" )).toString();
355 const QString username = serverSetting( QLatin1String(
"QPSQL" ),
"User", QString() ).toString();
356 const QString password = serverSetting( QLatin1String(
"QPSQL" ),
"Password", QString() ).toString();
357 const int port = serverSetting( QLatin1String(
"QPSQL" ),
"Port", 5432).toInt();
359 QSqlDatabase db = QSqlDatabase::addDatabase( QLatin1String(
"QPSQL" ) );
360 db.setHostName( hostname );
361 db.setDatabaseName( dbname );
363 if ( !username.isEmpty() )
364 db.setUserName( username );
366 if ( !password.isEmpty() )
367 db.setPassword( password );
372 const KLocalizedString details = ki18n( db.lastError().text().toLatin1() );
373 report( Error, ki18n(
"Cannot connect to PostgreSQL server." ), details);
376 report( Success, ki18n(
"PostgreSQL server found." ),
377 ki18n(
"The PostgreSQL server was found and connection is working." ));
382 void SelfTestDialog::testAkonadiCtl()
384 const QString path = KStandardDirs::findExe( QLatin1String(
"akonadictl" ) );
385 if ( path.isEmpty() ) {
386 report( Error, ki18n(
"akonadictl not found" ),
387 ki18n(
"The program 'akonadictl' needs to be accessible in $PATH. "
388 "Make sure you have the Akonadi server installed." ) );
392 if ( runProcess( path, QStringList() << QLatin1String(
"--version" ), result ) ) {
393 report( Success, ki18n(
"akonadictl found and usable" ),
394 ki18n(
"The program '%1' to control the Akonadi server was found "
395 "and could be executed successfully.\nResult:\n%2" ).subs( path ).subs( result ) );
397 report( Error, ki18n(
"akonadictl found but not usable" ),
398 ki18n(
"The program '%1' to control the Akonadi server was found "
399 "but could not be executed successfully.\nResult:\n%2\n"
400 "Make sure the Akonadi server is installed correctly." ).subs( path ).subs( result ) );
404 void SelfTestDialog::testServerStatus()
406 if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE ) ) {
407 report( Success, ki18n(
"Akonadi control process registered at D-Bus." ),
408 ki18n(
"The Akonadi control process is registered at D-Bus which typically indicates it is operational." ) );
410 report( Error, ki18n(
"Akonadi control process not registered at D-Bus." ),
411 ki18n(
"The Akonadi control process is not registered at D-Bus which typically means it was not started "
412 "or encountered a fatal error during startup." ) );
415 if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_SERVER_SERVICE ) ) {
416 report( Success, ki18n(
"Akonadi server process registered at D-Bus." ),
417 ki18n(
"The Akonadi server process is registered at D-Bus which typically indicates it is operational." ) );
419 report( Error, ki18n(
"Akonadi server process not registered at D-Bus." ),
420 ki18n(
"The Akonadi server process is not registered at D-Bus which typically means it was not started "
421 "or encountered a fatal error during startup." ) );
425 void SelfTestDialog::testSearchStatus()
427 bool searchAvailable =
false;
428 if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_SEARCH_SERVICE ) ) {
429 searchAvailable =
true;
430 report( Success, ki18n(
"Nepomuk search service registered at D-Bus." ),
431 ki18n(
"The Nepomuk search service is registered at D-Bus which typically indicates it is operational." ) );
433 report( Error, ki18n(
"Nepomuk search service not registered at D-Bus." ),
434 ki18n(
"The Nepomuk search service is not registered at D-Bus which typically means it was not started "
435 "or encountered a fatal error during startup." ) );
438 if ( searchAvailable ) {
440 QDBusInterface interface( QLatin1String(
"org.kde.NepomukStorage" ), QLatin1String(
"/nepomukstorage" ) );
441 const QDBusReply<QString> reply = interface.call( QLatin1String(
"usedSopranoBackend" ) );
442 if ( reply.isValid() ) {
443 const QString name = reply.value();
446 if ( name.contains( QLatin1String(
"redland" ) ) ) {
447 report( Error, ki18n(
"Nepomuk search service uses inappropriate backend." ),
448 ki18n(
"The Nepomuk search service uses the '%1' backend, which is not "
449 "recommended for use with Akonadi." ).subs( name ) );
451 report( Success, ki18n(
"Nepomuk search service uses an appropriate backend. " ),
452 ki18n(
"The Nepomuk search service uses one of the recommended backends." ) );
458 void SelfTestDialog::testProtocolVersion()
460 if ( Internal::serverProtocolVersion() < 0 ) {
461 report( Skip, ki18n(
"Protocol version check not possible." ),
462 ki18n(
"Without a connection to the server it is not possible to check if the protocol version meets the requirements." ) );
465 if ( Internal::serverProtocolVersion() < SessionPrivate::minimumProtocolVersion() ) {
466 report( Error, ki18n(
"Server protocol version is too old." ),
467 ki18n(
"The server protocol version is %1, but at least version %2 is required. "
468 "Install a newer version of the Akonadi server." )
469 .subs( Internal::serverProtocolVersion() )
470 .subs( SessionPrivate::minimumProtocolVersion() ) );
472 report( Success, ki18n(
"Server protocol version is recent enough." ),
473 ki18n(
"The server Protocol version is %1, which equal or newer than the required version %2." )
474 .subs( Internal::serverProtocolVersion() )
475 .subs( SessionPrivate::minimumProtocolVersion() ) );
479 void SelfTestDialog::testResources()
482 bool resourceFound =
false;
483 foreach (
const AgentType &type, agentTypes ) {
484 if ( type.
capabilities().contains( QLatin1String(
"Resource" ) ) ) {
485 resourceFound =
true;
490 const QStringList pathList = XdgBaseDirs::findAllResourceDirs(
"data", QLatin1String(
"akonadi/agents" ) );
491 QStandardItem *item = 0;
492 if ( resourceFound ) {
493 item = report( Success, ki18n(
"Resource agents found." ), ki18n(
"At least one resource agent has been found." ) );
495 item = report( Error, ki18n(
"No resource agents found." ),
496 ki18n(
"No resource agents have been found, Akonadi is not usable without at least one. "
497 "This usually means that no resource agents are installed or that there is a setup problem. "
498 "The following paths have been searched: '%1'. "
499 "The XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes all paths "
500 "where Akonadi agents are installed." )
501 .subs( pathList.join( QLatin1String(
" " ) ) )
502 .subs( QString::fromLocal8Bit( qgetenv(
"XDG_DATA_DIRS" ) ) ) );
504 item->setData( pathList, ListDirectoryRole );
505 item->setData( QByteArray(
"XDG_DATA_DIRS" ), EnvVarRole );
508 void Akonadi::SelfTestDialog::testServerLog()
510 QString serverLog = XdgBaseDirs::saveDir(
"data", QLatin1String(
"akonadi" ) )
511 + QDir::separator() + QString::fromLatin1(
"akonadiserver.error" );
512 QFileInfo info( serverLog );
513 if ( !info.exists() || info.size() <= 0 ) {
514 report( Success, ki18n(
"No current Akonadi server error log found." ),
515 ki18n(
"The Akonadi server did not report any errors during its current startup." ) );
517 QStandardItem *item = report( Error, ki18n(
"Current Akonadi server error log found." ),
518 ki18n(
"The Akonadi server reported errors during its current startup. The log can be found in %1." ).subs( makeLink( serverLog ) ) );
519 item->setData( serverLog, FileIncludeRole );
522 serverLog += QLatin1String(
".old" );
523 info.setFile( serverLog );
524 if ( !info.exists() || info.size() <= 0 ) {
525 report( Success, ki18n(
"No previous Akonadi server error log found." ),
526 ki18n(
"The Akonadi server did not report any errors during its previous startup." ) );
528 QStandardItem *item = report( Error, ki18n(
"Previous Akonadi server error log found." ),
529 ki18n(
"The Akonadi server reported errors during its previous startup. The log can be found in %1." ).subs( makeLink( serverLog ) ) );
530 item->setData( serverLog, FileIncludeRole );
534 void SelfTestDialog::testControlLog()
536 QString controlLog = XdgBaseDirs::saveDir(
"data", QLatin1String(
"akonadi" ) )
537 + QDir::separator() + QString::fromLatin1(
"akonadi_control.error" );
538 QFileInfo info( controlLog );
539 if ( !info.exists() || info.size() <= 0 ) {
540 report( Success, ki18n(
"No current Akonadi control error log found." ),
541 ki18n(
"The Akonadi control process did not report any errors during its current startup." ) );
543 QStandardItem *item = report( Error, ki18n(
"Current Akonadi control error log found." ),
544 ki18n(
"The Akonadi control process reported errors during its current startup. The log can be found in %1." ).subs( makeLink( controlLog ) ) );
545 item->setData( controlLog, FileIncludeRole );
548 controlLog += QLatin1String(
".old" );
549 info.setFile( controlLog );
550 if ( !info.exists() || info.size() <= 0 ) {
551 report( Success, ki18n(
"No previous Akonadi control error log found." ),
552 ki18n(
"The Akonadi control process did not report any errors during its previous startup." ) );
554 QStandardItem *item = report( Error, ki18n(
"Previous Akonadi control error log found." ),
555 ki18n(
"The Akonadi control process reported errors during its previous startup. The log can be found in %1." ).subs( makeLink( controlLog ) ) );
556 item->setData( controlLog, FileIncludeRole );
561 void SelfTestDialog::testRootUser()
564 if ( user.isSuperUser() ) {
565 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." ) );
567 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." ) );
571 QString SelfTestDialog::createReport()
574 QTextStream s( &result );
575 s <<
"Akonadi Server Self-Test Report" << endl;
576 s <<
"===============================" << endl;
578 for (
int i = 0; i < mTestModel->rowCount(); ++i ) {
579 QStandardItem *item = mTestModel->item( i );
581 s <<
"Test " << (i + 1) <<
": ";
582 switch ( item->data( ResultTypeRole ).toInt() ) {
586 s <<
"SUCCESS";
break;
588 s <<
"WARNING";
break;
593 s << endl <<
"--------" << endl;
595 s << item->data( SummaryRole ).toString() << endl;
596 s <<
"Details: " << item->data( DetailsRole ).toString() << endl;
597 if ( item->data( FileIncludeRole ).isValid() ) {
599 const QString fileName = item->data( FileIncludeRole ).toString();
601 if ( f.open( QFile::ReadOnly ) ) {
602 s <<
"File content of '" << fileName <<
"':" << endl;
603 s << f.readAll() << endl;
605 s <<
"File '" << fileName <<
"' could not be opened" << endl;
608 if ( item->data( ListDirectoryRole ).isValid() ) {
610 const QStringList pathList = item->data( ListDirectoryRole ).toStringList();
611 if ( pathList.isEmpty() )
612 s <<
"Directory list is empty." << endl;
613 foreach (
const QString &path, pathList ) {
614 s <<
"Directory listing of '" << path <<
"':" << endl;
616 dir.setFilter( QDir::AllEntries | QDir::NoDotAndDotDot );
617 foreach (
const QString &entry, dir.entryList() )
621 if ( item->data( EnvVarRole ).isValid() ) {
623 const QByteArray envVarName = item->data( EnvVarRole ).toByteArray();
624 const QByteArray envVarValue = qgetenv( envVarName );
625 s <<
"Environment variable " << envVarName <<
" is set to '" << envVarValue <<
"'" << endl;
634 void SelfTestDialog::saveReport()
636 const QString defaultFileName = QLatin1String(
"akonadi-selftest-report-" )
637 + QDate::currentDate().toString( QLatin1String(
"yyyyMMdd" ) )
638 + QLatin1String(
".txt" );
639 const QString fileName = KFileDialog::getSaveFileName( defaultFileName, QString(),
this,
640 i18n(
"Save Test Report" ) );
641 if ( fileName.isEmpty() )
644 QFile file( fileName );
645 if ( !file.open( QFile::ReadWrite ) ) {
646 KMessageBox::error(
this, i18n(
"Could not open file '%1'", fileName ) );
650 file.write( createReport().toUtf8() );
654 void SelfTestDialog::copyReport()
656 #ifndef QT_NO_CLIPBOARD
657 QApplication::clipboard()->setText( createReport() );
661 void SelfTestDialog::linkActivated(
const QString & link)
663 KRun::runUrl( KUrl::fromPath( link ), QLatin1String(
"text/plain" ),
this );
668 #include "selftestdialog_p.moc"