• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepimlibs API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • sources
  • kde-4.14
  • kdepimlibs
  • akonadi
selftestdialog.cpp
1 /*
2  Copyright (c) 2008 Volker Krause <vkrause@kde.org>
3 
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.
8 
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.
13 
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.
18 */
19 
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"
26 
27 #include <akonadi/private/xdgbasedirs_p.h>
28 
29 #include <KDebug>
30 #include <KUrl>
31 #include <KIcon>
32 #include <KFileDialog>
33 #include <KLocalizedString>
34 #include <KMessageBox>
35 #include <KRun>
36 #include <KStandardDirs>
37 #include <KUser>
38 
39 #include <QtCore/QFileInfo>
40 #include <QtCore/QProcess>
41 #include <QtCore/QSettings>
42 #include <QtCore/QTextStream>
43 #include <QtDBus/QtDBus>
44 #include <QApplication>
45 #include <QClipboard>
46 #include <QStandardItemModel>
47 #include <QtSql/QSqlDatabase>
48 #include <QtSql/QSqlError>
49 
50 // @cond PRIVATE
51 
52 using namespace Akonadi;
53 
54 static QString makeLink(const QString &file)
55 {
56  return QString::fromLatin1("<a href=\"%1\">%2</a>").arg(file, file);
57 }
58 
59 enum SelfTestRole {
60  ResultTypeRole = Qt::UserRole,
61  FileIncludeRole,
62  ListDirectoryRole,
63  EnvVarRole,
64  SummaryRole,
65  DetailsRole
66 };
67 
68 SelfTestDialog::SelfTestDialog(QWidget *parent)
69  : KDialog(parent)
70 {
71  setCaption(i18n("Akonadi Server Self-Test"));
72  setButtons(Close | User1 | User2);
73  setButtonText(User1, i18n("Save Report..."));
74  setButtonIcon(User1, KIcon(QString::fromLatin1("document-save")));
75  setButtonText(User2, i18n("Copy Report to Clipboard"));
76  setButtonIcon(User2, KIcon(QString::fromLatin1("edit-copy")));
77  showButtonSeparator(true);
78  ui.setupUi(mainWidget());
79 
80  mTestModel = new QStandardItemModel(this);
81  ui.testView->setModel(mTestModel);
82  connect(ui.testView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
83  SLOT(selectionChanged(QModelIndex)));
84  connect(ui.detailsLabel, SIGNAL(linkActivated(QString)), SLOT(linkActivated(QString)));
85 
86  connect(this, SIGNAL(user1Clicked()), SLOT(saveReport()));
87  connect(this, SIGNAL(user2Clicked()), SLOT(copyReport()));
88 
89  connect(ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)), SLOT(runTests()));
90  runTests();
91 }
92 
93 void SelfTestDialog::hideIntroduction()
94 {
95  ui.introductionLabel->hide();
96 }
97 
98 QStandardItem *SelfTestDialog::report(ResultType type, const KLocalizedString &summary, const KLocalizedString &details)
99 {
100  QStandardItem *item = new QStandardItem(summary.toString());
101  switch (type) {
102  case Skip:
103  item->setIcon(KIcon(QString::fromLatin1("dialog-ok")));
104  break;
105  case Success:
106  item->setIcon(KIcon(QString::fromLatin1("dialog-ok-apply")));
107  break;
108  case Warning:
109  item->setIcon(KIcon(QString::fromLatin1("dialog-warning")));
110  break;
111  case Error:
112  default:
113  item->setIcon(KIcon(QString::fromLatin1("dialog-error")));
114  }
115  item->setEditable(false);
116  item->setWhatsThis(details.toString());
117  item->setData(type, ResultTypeRole);
118  item->setData(summary.toString(0), SummaryRole);
119  item->setData(details.toString(0), DetailsRole);
120  mTestModel->appendRow(item);
121  return item;
122 }
123 
124 void SelfTestDialog::selectionChanged(const QModelIndex &index)
125 {
126  if (index.isValid()) {
127  ui.detailsLabel->setText(index.data(Qt::WhatsThisRole).toString());
128  ui.detailsGroup->setEnabled(true);
129  } else {
130  ui.detailsLabel->setText(QString());
131  ui.detailsGroup->setEnabled(false);
132  }
133 }
134 
135 void SelfTestDialog::runTests()
136 {
137  mTestModel->clear();
138 
139  const QString driver = serverSetting(QLatin1String("General"), "Driver", QLatin1String("QMYSQL")).toString();
140  testSQLDriver();
141  if (driver == QLatin1String("QPSQL")) {
142  testPSQLServer();
143  } else {
144 #ifndef Q_OS_WIN
145  testRootUser();
146 #endif
147  testMySQLServer();
148  testMySQLServerLog();
149  testMySQLServerConfig();
150  }
151  testAkonadiCtl();
152  testServerStatus();
153  testProtocolVersion();
154  testResources();
155  testServerLog();
156  testControlLog();
157 }
158 
159 QVariant SelfTestDialog::serverSetting(const QString &group, const char *key, const QVariant &def) const
160 {
161  const QString serverConfigFile = XdgBaseDirs::akonadiServerConfigFile(XdgBaseDirs::ReadWrite);
162  QSettings settings(serverConfigFile, QSettings::IniFormat);
163  settings.beginGroup(group);
164  return settings.value(QString::fromLatin1(key), def);
165 }
166 
167 bool SelfTestDialog::useStandaloneMysqlServer() const
168 {
169  const QString driver = serverSetting(QLatin1String("General"), "Driver", QLatin1String("QMYSQL")).toString();
170  if (driver != QLatin1String("QMYSQL")) {
171  return false;
172  }
173  const bool startServer = serverSetting(driver, "StartServer", true).toBool();
174  if (!startServer) {
175  return false;
176  }
177  return true;
178 }
179 
180 bool SelfTestDialog::runProcess(const QString &app, const QStringList &args, QString &result) const
181 {
182  QProcess proc;
183  proc.start(app, args);
184  const bool rv = proc.waitForFinished();
185  result.clear();
186  result += QString::fromLocal8Bit(proc.readAllStandardError());
187  result += QString::fromLocal8Bit(proc.readAllStandardOutput());
188  return rv;
189 }
190 
191 void SelfTestDialog::testSQLDriver()
192 {
193  const QString driver = serverSetting(QLatin1String("General"), "Driver", QLatin1String("QMYSQL")).toString();
194  const QStringList availableDrivers = QSqlDatabase::drivers();
195  const KLocalizedString detailsOk = ki18n("The QtSQL driver '%1' is required by your current Akonadi server configuration and was found on your system.")
196  .subs(driver);
197  const KLocalizedString detailsFail = ki18n("The QtSQL driver '%1' is required by your current Akonadi server configuration.\n"
198  "The following drivers are installed: %2.\n"
199  "Make sure the required driver is installed.")
200  .subs(driver)
201  .subs(availableDrivers.join(QLatin1String(", ")));
202  QStandardItem *item = 0;
203  if (availableDrivers.contains(driver)) {
204  item = report(Success, ki18n("Database driver found."), detailsOk);
205  } else {
206  item = report(Error, ki18n("Database driver not found."), detailsFail);
207  }
208  item->setData(XdgBaseDirs::akonadiServerConfigFile(XdgBaseDirs::ReadWrite), FileIncludeRole);
209 }
210 
211 void SelfTestDialog::testMySQLServer()
212 {
213  if (!useStandaloneMysqlServer()) {
214  report(Skip, ki18n("MySQL server executable not tested."),
215  ki18n("The current configuration does not require an internal MySQL server."));
216  return;
217  }
218 
219  const QString driver = serverSetting(QLatin1String("General"), "Driver", QLatin1String("QMYSQL")).toString();
220  const QString serverPath = serverSetting(driver, "ServerPath", QLatin1String("")).toString(); // ### default?
221 
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);
226 
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);
236  } else {
237  report(Success, ki18n("MySQL server found."), details);
238  }
239 
240  // be extra sure and get the server version while we are at it
241  QString result;
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);
245  } else {
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);
249  }
250 }
251 
252 void SelfTestDialog::testMySQLServerLog()
253 {
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."));
257  return;
258  }
259 
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));
266  return;
267  }
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)));
272  return;
273  }
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);
282  return;
283  }
284  if (!warningsFound && line.contains(QLatin1String("warn"), Qt::CaseInsensitive)) {
285  warningsFound = true;
286  }
287  }
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)));
291  } else {
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)));
295  }
296  item->setData(logFileName, FileIncludeRole);
297 
298  logFile.close();
299 }
300 
301 void SelfTestDialog::testMySQLServerConfig()
302 {
303  if (!useStandaloneMysqlServer()) {
304  report(Skip, ki18n("MySQL server configuration not tested."),
305  ki18n("The current configuration does not require an internal MySQL server."));
306  return;
307  }
308 
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);
317  } else {
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."));
321  }
322 
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);
333  } else {
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)));
337  }
338 
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."));
344  } else {
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);
348  }
349 }
350 
351 void SelfTestDialog::testPSQLServer()
352 {
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();
358 
359  QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QPSQL"));
360  db.setHostName(hostname);
361  db.setDatabaseName(dbname);
362 
363  if (!username.isEmpty()) {
364  db.setUserName(username);
365  }
366 
367  if (!password.isEmpty()) {
368  db.setPassword(password);
369  }
370 
371  db.setPort(port);
372 
373  if (!db.open()) {
374  const KLocalizedString details = ki18n(db.lastError().text().toLatin1());
375  report(Error, ki18n("Cannot connect to PostgreSQL server."), details);
376  } else {
377  report(Success, ki18n("PostgreSQL server found."),
378  ki18n("The PostgreSQL server was found and connection is working."));
379  }
380  db.close();
381 }
382 
383 void SelfTestDialog::testAkonadiCtl()
384 {
385  const QString path = KStandardDirs::findExe(QLatin1String("akonadictl"));
386  if (path.isEmpty()) {
387  report(Error, ki18n("akonadictl not found"),
388  ki18n("The program 'akonadictl' needs to be accessible in $PATH. "
389  "Make sure you have the Akonadi server installed."));
390  return;
391  }
392  QString result;
393  if (runProcess(path, QStringList() << QLatin1String("--version"), result)) {
394  report(Success, ki18n("akonadictl found and usable"),
395  ki18n("The program '%1' to control the Akonadi server was found "
396  "and could be executed successfully.\nResult:\n%2").subs(path).subs(result));
397  } else {
398  report(Error, ki18n("akonadictl found but not usable"),
399  ki18n("The program '%1' to control the Akonadi server was found "
400  "but could not be executed successfully.\nResult:\n%2\n"
401  "Make sure the Akonadi server is installed correctly.").subs(path).subs(result));
402  }
403 }
404 
405 void SelfTestDialog::testServerStatus()
406 {
407  if (DBusConnectionPool::threadConnection().interface()->isServiceRegistered(ServerManager::serviceName(ServerManager::Control))) {
408  report(Success, ki18n("Akonadi control process registered at D-Bus."),
409  ki18n("The Akonadi control process is registered at D-Bus which typically indicates it is operational."));
410  } else {
411  report(Error, ki18n("Akonadi control process not registered at D-Bus."),
412  ki18n("The Akonadi control process is not registered at D-Bus which typically means it was not started "
413  "or encountered a fatal error during startup."));
414  }
415 
416  if (DBusConnectionPool::threadConnection().interface()->isServiceRegistered(ServerManager::serviceName(ServerManager::Server))) {
417  report(Success, ki18n("Akonadi server process registered at D-Bus."),
418  ki18n("The Akonadi server process is registered at D-Bus which typically indicates it is operational."));
419  } else {
420  report(Error, ki18n("Akonadi server process not registered at D-Bus."),
421  ki18n("The Akonadi server process is not registered at D-Bus which typically means it was not started "
422  "or encountered a fatal error during startup."));
423  }
424 }
425 
426 void SelfTestDialog::testProtocolVersion()
427 {
428  if (Internal::serverProtocolVersion() < 0) {
429  report(Skip, ki18n("Protocol version check not possible."),
430  ki18n("Without a connection to the server it is not possible to check if the protocol version meets the requirements."));
431  return;
432  }
433  if (Internal::serverProtocolVersion() < SessionPrivate::minimumProtocolVersion()) {
434  report(Error, ki18n("Server protocol version is too old."),
435  ki18n("The server protocol version is %1, but at least version %2 is required. "
436  "Install a newer version of the Akonadi server.")
437  .subs(Internal::serverProtocolVersion())
438  .subs(SessionPrivate::minimumProtocolVersion()));
439  } else {
440  report(Success, ki18n("Server protocol version is recent enough."),
441  ki18n("The server Protocol version is %1, which equal or newer than the required version %2.")
442  .subs(Internal::serverProtocolVersion())
443  .subs(SessionPrivate::minimumProtocolVersion()));
444  }
445 }
446 
447 void SelfTestDialog::testResources()
448 {
449  AgentType::List agentTypes = AgentManager::self()->types();
450  bool resourceFound = false;
451  foreach (const AgentType &type, agentTypes) {
452  if (type.capabilities().contains(QLatin1String("Resource"))) {
453  resourceFound = true;
454  break;
455  }
456  }
457 
458  const QStringList pathList = XdgBaseDirs::findAllResourceDirs("data", QLatin1String("akonadi/agents"));
459  QStandardItem *item = 0;
460  if (resourceFound) {
461  item = report(Success, ki18n("Resource agents found."), ki18n("At least one resource agent has been found."));
462  } else {
463  item = report(Error, ki18n("No resource agents found."),
464  ki18n("No resource agents have been found, Akonadi is not usable without at least one. "
465  "This usually means that no resource agents are installed or that there is a setup problem. "
466  "The following paths have been searched: '%1'. "
467  "The XDG_DATA_DIRS environment variable is set to '%2'; make sure this includes all paths "
468  "where Akonadi agents are installed.")
469  .subs(pathList.join(QLatin1String(" ")))
470  .subs(QString::fromLocal8Bit(qgetenv("XDG_DATA_DIRS"))));
471  }
472  item->setData(pathList, ListDirectoryRole);
473  item->setData(QByteArray("XDG_DATA_DIRS"), EnvVarRole);
474 }
475 
476 void Akonadi::SelfTestDialog::testServerLog()
477 {
478  QString serverLog = XdgBaseDirs::saveDir("data", QLatin1String("akonadi"))
479  + QDir::separator() + QString::fromLatin1("akonadiserver.error");
480  QFileInfo info(serverLog);
481  if (!info.exists() || info.size() <= 0) {
482  report(Success, ki18n("No current Akonadi server error log found."),
483  ki18n("The Akonadi server did not report any errors during its current startup."));
484  } else {
485  QStandardItem *item = report(Error, ki18n("Current Akonadi server error log found."),
486  ki18n("The Akonadi server reported errors during its current startup. The log can be found in %1.").subs(makeLink(serverLog)));
487  item->setData(serverLog, FileIncludeRole);
488  }
489 
490  serverLog += QLatin1String(".old");
491  info.setFile(serverLog);
492  if (!info.exists() || info.size() <= 0) {
493  report(Success, ki18n("No previous Akonadi server error log found."),
494  ki18n("The Akonadi server did not report any errors during its previous startup."));
495  } else {
496  QStandardItem *item = report(Error, ki18n("Previous Akonadi server error log found."),
497  ki18n("The Akonadi server reported errors during its previous startup. The log can be found in %1.").subs(makeLink(serverLog)));
498  item->setData(serverLog, FileIncludeRole);
499  }
500 }
501 
502 void SelfTestDialog::testControlLog()
503 {
504  QString controlLog = XdgBaseDirs::saveDir("data", QLatin1String("akonadi"))
505  + QDir::separator() + QString::fromLatin1("akonadi_control.error");
506  QFileInfo info(controlLog);
507  if (!info.exists() || info.size() <= 0) {
508  report(Success, ki18n("No current Akonadi control error log found."),
509  ki18n("The Akonadi control process did not report any errors during its current startup."));
510  } else {
511  QStandardItem *item = report(Error, ki18n("Current Akonadi control error log found."),
512  ki18n("The Akonadi control process reported errors during its current startup. The log can be found in %1.").subs(makeLink(controlLog)));
513  item->setData(controlLog, FileIncludeRole);
514  }
515 
516  controlLog += QLatin1String(".old");
517  info.setFile(controlLog);
518  if (!info.exists() || info.size() <= 0) {
519  report(Success, ki18n("No previous Akonadi control error log found."),
520  ki18n("The Akonadi control process did not report any errors during its previous startup."));
521  } else {
522  QStandardItem *item = report(Error, ki18n("Previous Akonadi control error log found."),
523  ki18n("The Akonadi control process reported errors during its previous startup. The log can be found in %1.").subs(makeLink(controlLog)));
524  item->setData(controlLog, FileIncludeRole);
525  }
526 }
527 
528 void SelfTestDialog::testRootUser()
529 {
530  KUser user;
531  if (user.isSuperUser()) {
532  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."));
533  } else {
534  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."));
535  }
536 }
537 
538 QString SelfTestDialog::createReport()
539 {
540  QString result;
541  QTextStream s(&result);
542  s << "Akonadi Server Self-Test Report" << endl;
543  s << "===============================" << endl;
544 
545  for (int i = 0; i < mTestModel->rowCount(); ++i) {
546  QStandardItem *item = mTestModel->item(i);
547  s << endl;
548  s << "Test " << (i + 1) << ": ";
549  switch (item->data(ResultTypeRole).toInt()) {
550  case Skip:
551  s << "SKIP";
552  break;
553  case Success:
554  s << "SUCCESS";
555  break;
556  case Warning:
557  s << "WARNING";
558  break;
559  case Error:
560  default:
561  s << "ERROR";
562  break;
563  }
564  s << endl << "--------" << endl;
565  s << endl;
566  s << item->data(SummaryRole).toString() << endl;
567  s << "Details: " << item->data(DetailsRole).toString() << endl;
568  if (item->data(FileIncludeRole).isValid()) {
569  s << endl;
570  const QString fileName = item->data(FileIncludeRole).toString();
571  QFile f(fileName);
572  if (f.open(QFile::ReadOnly)) {
573  s << "File content of '" << fileName << "':" << endl;
574  s << f.readAll() << endl;
575  } else {
576  s << "File '" << fileName << "' could not be opened" << endl;
577  }
578  }
579  if (item->data(ListDirectoryRole).isValid()) {
580  s << endl;
581  const QStringList pathList = item->data(ListDirectoryRole).toStringList();
582  if (pathList.isEmpty()) {
583  s << "Directory list is empty." << endl;
584  }
585  foreach (const QString &path, pathList) {
586  s << "Directory listing of '" << path << "':" << endl;
587  QDir dir(path);
588  dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
589  foreach (const QString &entry, dir.entryList()) {
590  s << entry << endl;
591  }
592  }
593  }
594  if (item->data(EnvVarRole).isValid()) {
595  s << endl;
596  const QByteArray envVarName = item->data(EnvVarRole).toByteArray();
597  const QByteArray envVarValue = qgetenv(envVarName);
598  s << "Environment variable " << envVarName << " is set to '" << envVarValue << "'" << endl;
599  }
600  }
601 
602  s << endl;
603  s.flush();
604  return result;
605 }
606 
607 void SelfTestDialog::saveReport()
608 {
609  const QString defaultFileName = QLatin1String("akonadi-selftest-report-")
610  + QDate::currentDate().toString(QLatin1String("yyyyMMdd"))
611  + QLatin1String(".txt");
612  const QString fileName = KFileDialog::getSaveFileName(QUrl(defaultFileName), QString(), this,
613  i18n("Save Test Report"), KFileDialog::ConfirmOverwrite);
614  if (fileName.isEmpty()) {
615  return;
616  }
617 
618  QFile file(fileName);
619  if (!file.open(QFile::ReadWrite)) {
620  KMessageBox::error(this, i18n("Could not open file '%1'", fileName));
621  return;
622  }
623 
624  file.write(createReport().toUtf8());
625  file.close();
626 }
627 
628 void SelfTestDialog::copyReport()
629 {
630 #ifndef QT_NO_CLIPBOARD
631  QApplication::clipboard()->setText(createReport());
632 #endif
633 }
634 
635 void SelfTestDialog::linkActivated(const QString &link)
636 {
637  KRun::runUrl(KUrl::fromPath(link), QLatin1String("text/plain"), this);
638 }
639 
640 // @endcond
641 
642 #include "moc_selftestdialog_p.cpp"
QModelIndex
QVariant::toByteArray
QByteArray toByteArray() const
QStandardItemModel
QWidget
QSqlDatabase::lastError
QSqlError lastError() const
QStandardItem::setIcon
void setIcon(const QIcon &icon)
QSqlDatabase::setUserName
void setUserName(const QString &name)
QSqlDatabase::drivers
QStringList drivers()
QDate::toString
QString toString(Qt::DateFormat format) const
QByteArray
QStandardItemModel::clear
void clear()
QStringList::contains
bool contains(const QString &str, Qt::CaseSensitivity cs) const
Akonadi::ServerManager::self
static ServerManager * self()
Returns the singleton instance of this class, for connecting to its signals.
Definition: servermanager.cpp:161
QSqlDatabase::setPort
void setPort(int port)
QSqlDatabase::addDatabase
QSqlDatabase addDatabase(const QString &type, const QString &connectionName)
Akonadi::SelfTestDialog::hideIntroduction
void hideIntroduction()
Hides the label with the introduction message.
Akonadi::ServerManager::serviceName
static QString serviceName(ServiceType serviceType)
Returns the namespaced D-Bus service name for serviceType.
Definition: servermanager.cpp:307
QStringList::join
QString join(const QString &separator) const
QDir::separator
QChar separator()
QFile
QSqlDatabase
QTextStream
QStandardItem::setData
virtual void setData(const QVariant &value, int role)
QString::clear
void clear()
QModelIndex::isValid
bool isValid() const
QString::fromLocal8Bit
QString fromLocal8Bit(const char *str, int size)
Akonadi::AgentType
A representation of an agent type.
Definition: agenttype.h:58
QString::fromUtf8
QString fromUtf8(const char *str, int size)
QVariant::toInt
int toInt(bool *ok) const
QApplication::clipboard
QClipboard * clipboard()
QProcess
QList::isEmpty
bool isEmpty() const
QString::isEmpty
bool isEmpty() const
Akonadi::AgentType::capabilities
QStringList capabilities() const
Returns the list of supported capabilities of the agent type.
Definition: agenttype.cpp:76
QSqlDatabase::open
bool open()
QString
QList
QStringList
Akonadi::SelfTestDialog::SelfTestDialog
SelfTestDialog(QWidget *parent=0)
Creates a new self test dialog.
QFileInfo
QStandardItemModel::item
QStandardItem * item(int row, int column) const
QSettings
QString::contains
bool contains(QChar ch, Qt::CaseSensitivity cs) const
QUrl
QSqlDatabase::setHostName
void setHostName(const QString &host)
QDir
QString::toLatin1
QByteArray toLatin1() const
QVariant::toStringList
QStringList toStringList() const
QModelIndex::data
QVariant data(int role) const
QLatin1String
Akonadi::AgentManager::types
AgentType::List types() const
Returns the list of all available agent types.
Definition: agentmanager.cpp:386
QDate::currentDate
QDate currentDate()
QStandardItemModel::rowCount
virtual int rowCount(const QModelIndex &parent) const
QVariant::toBool
bool toBool() const
Akonadi::AgentManager::self
static AgentManager * self()
Returns the global instance of the agent manager.
Definition: agentmanager.cpp:377
QSqlDatabase::setPassword
void setPassword(const QString &password)
QString::fromLatin1
QString fromLatin1(const char *str, int size)
Akonadi::ServerManager::State
State
Enum for the various states the server can be in.
Definition: servermanager.h:50
QVariant::isValid
bool isValid() const
QClipboard::setText
void setText(const QString &text, Mode mode)
QSqlError::text
QString text() const
QSqlDatabase::setDatabaseName
void setDatabaseName(const QString &name)
QStandardItem
QStandardItem::setWhatsThis
void setWhatsThis(const QString &whatsThis)
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QVariant::toString
QString toString() const
QProcess::readAllStandardOutput
QByteArray readAllStandardOutput()
QStandardItemModel::appendRow
void appendRow(const QList< QStandardItem * > &items)
QStandardItem::data
virtual QVariant data(int role) const
QStandardItem::setEditable
void setEditable(bool editable)
QProcess::start
void start(const QString &program, const QStringList &arguments, QFlags< QIODevice::OpenModeFlag > mode)
QProcess::readAllStandardError
QByteArray readAllStandardError()
QSqlDatabase::close
void close()
QVariant
QProcess::waitForFinished
bool waitForFinished(int msecs)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:38:03 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs API Reference

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal