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

kleopatra

  • sources
  • kde-4.14
  • kdepim
  • kleopatra
  • models
modeltest.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2007 Trolltech ASA. All rights reserved.
4 **
5 ** This file is part of the Qt Concurrent project on Trolltech Labs.
6 **
7 ** This file may be used under the terms of the GNU General Public
8 ** License version 2.0 as published by the Free Software Foundation
9 ** and appearing in the file LICENSE.GPL included in the packaging of
10 ** this file. Please review the following information to ensure GNU
11 ** General Public Licensing requirements will be met:
12 ** http://www.trolltech.com/products/qt/opensource.html
13 **
14 ** If you are unsure which license is appropriate for your use, please
15 ** review the following information:
16 ** http://www.trolltech.com/products/qt/licensing.html or contact the
17 ** sales department at sales@trolltech.com.
18 **
19 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 **
22 ****************************************************************************/
23 
24 #include "modeltest.h"
25 
26 #include <config-kleopatra.h>
27 
28 
29 Q_DECLARE_METATYPE(QModelIndex)
30 
31 
34 ModelTest::ModelTest(QAbstractItemModel *_model, QObject *parent) : QObject(parent), model(_model), fetchingMore(false)
35 {
36  Q_ASSERT(model);
37 
38  connect(model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
39  this, SLOT(runAllTests()));
40  connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
41  this, SLOT(runAllTests()));
42  connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
43  this, SLOT(runAllTests()));
44  connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
45  this, SLOT(runAllTests()));
46  connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
47  this, SLOT(runAllTests()));
48  connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
49  this, SLOT(runAllTests()));
50  connect(model, SIGNAL(layoutAboutToBeChanged()), this, SLOT(runAllTests()));
51  connect(model, SIGNAL(layoutChanged()), this, SLOT(runAllTests()));
52  connect(model, SIGNAL(modelReset()), this, SLOT(runAllTests()));
53  connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
54  this, SLOT(runAllTests()));
55  connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
56  this, SLOT(runAllTests()));
57  connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
58  this, SLOT(runAllTests()));
59  connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
60  this, SLOT(runAllTests()));
61 
62  // Special checks for inserting/removing
63  connect(model, SIGNAL(layoutAboutToBeChanged()),
64  this, SLOT(layoutAboutToBeChanged()));
65  connect(model, SIGNAL(layoutChanged()),
66  this, SLOT(layoutChanged()));
67 
68  connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
69  this, SLOT(rowsAboutToBeInserted(QModelIndex,int,int)));
70  connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
71  this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
72  connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
73  this, SLOT(rowsInserted(QModelIndex,int,int)));
74  connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
75  this, SLOT(rowsRemoved(QModelIndex,int,int)));
76 
77  runAllTests();
78 }
79 
80 void ModelTest::runAllTests()
81 {
82  if (fetchingMore)
83  return;
84  nonDestructiveBasicTest();
85  rowCount();
86  columnCount();
87  hasIndex();
88  index();
89  parent();
90  data();
91 }
92 
97 void ModelTest::nonDestructiveBasicTest()
98 {
99  Q_ASSERT(model->buddy(QModelIndex()) == QModelIndex());
100  model->canFetchMore(QModelIndex());
101  Q_ASSERT(model->columnCount(QModelIndex()) >= 0);
102  Q_ASSERT(model->data(QModelIndex()) == QVariant());
103  fetchingMore = true;
104  model->fetchMore(QModelIndex());
105  fetchingMore = false;
106  Qt::ItemFlags flags = model->flags(QModelIndex());
107  Q_ASSERT(flags == Qt::ItemIsDropEnabled || flags == 0);
108  model->hasChildren(QModelIndex());
109  model->hasIndex(0, 0);
110  model->headerData(0, Qt::Horizontal);
111  model->index(0, 0);
112  model->itemData(QModelIndex());
113  QVariant cache;
114  model->match(QModelIndex(), -1, cache);
115  model->mimeTypes();
116  Q_ASSERT(model->parent(QModelIndex()) == QModelIndex());
117  Q_ASSERT(model->rowCount() >= 0);
118  QVariant variant;
119  model->setData(QModelIndex(), variant, -1);
120  model->setHeaderData(-1, Qt::Horizontal, QVariant());
121  model->setHeaderData(0, Qt::Horizontal, QVariant());
122  model->setHeaderData(999999, Qt::Horizontal, QVariant());
123  QMap<int, QVariant> roles;
124  model->sibling(0, 0, QModelIndex());
125  model->span(QModelIndex());
126  model->supportedDropActions();
127 }
128 
134 void ModelTest::rowCount()
135 {
136  // check top row
137  QModelIndex topIndex = model->index(0, 0, QModelIndex());
138  int rows = model->rowCount(topIndex);
139  Q_ASSERT(rows >= 0);
140  if (rows > 0)
141  Q_ASSERT(model->hasChildren(topIndex) == true);
142 
143  QModelIndex secondLevelIndex = model->index(0, 0, topIndex);
144  if (secondLevelIndex.isValid()) { // not the top level
145  // check a row count where parent is valid
146  rows = model->rowCount(secondLevelIndex);
147  Q_ASSERT(rows >= 0);
148  if (rows > 0)
149  Q_ASSERT(model->hasChildren(secondLevelIndex) == true);
150  }
151 
152  // The models rowCount() is tested more extensively in checkChildren(),
153  // but this catches the big mistakes
154 }
155 
159 void ModelTest::columnCount()
160 {
161  // check top row
162  QModelIndex topIndex = model->index(0, 0, QModelIndex());
163  Q_ASSERT(model->columnCount(topIndex) >= 0);
164 
165  // check a column count where parent is valid
166  QModelIndex childIndex = model->index(0, 0, topIndex);
167  if (childIndex.isValid())
168  Q_ASSERT(model->columnCount(childIndex) >= 0);
169 
170  // columnCount() is tested more extensively in checkChildren(),
171  // but this catches the big mistakes
172 }
173 
177 void ModelTest::hasIndex()
178 {
179  // Make sure that invalid values returns an invalid index
180  Q_ASSERT(model->hasIndex(-2, -2) == false);
181  Q_ASSERT(model->hasIndex(-2, 0) == false);
182  Q_ASSERT(model->hasIndex(0, -2) == false);
183 
184  int rows = model->rowCount();
185  int columns = model->columnCount();
186 
187  // check out of bounds
188  Q_ASSERT(model->hasIndex(rows, columns) == false);
189  Q_ASSERT(model->hasIndex(rows + 1, columns + 1) == false);
190 
191  if (rows > 0)
192  Q_ASSERT(model->hasIndex(0, 0) == true);
193 
194  // hasIndex() is tested more extensively in checkChildren(),
195  // but this catches the big mistakes
196 }
197 
201 void ModelTest::index()
202 {
203  // Make sure that invalid values returns an invalid index
204  Q_ASSERT(model->index(-2, -2) == QModelIndex());
205  Q_ASSERT(model->index(-2, 0) == QModelIndex());
206  Q_ASSERT(model->index(0, -2) == QModelIndex());
207 
208  int rows = model->rowCount();
209  int columns = model->columnCount();
210 
211  if (rows == 0)
212  return;
213 
214  // Catch off by one errors
215  Q_ASSERT(model->index(rows, columns) == QModelIndex());
216  Q_ASSERT(model->index(0, 0).isValid() == true);
217 
218  // Make sure that the same index is *always* returned
219  QModelIndex a = model->index(0, 0);
220  QModelIndex b = model->index(0, 0);
221  Q_ASSERT(a == b);
222 
223  // index() is tested more extensively in checkChildren(),
224  // but this catches the big mistakes
225 }
226 
230 void ModelTest::parent()
231 {
232  // Make sure the model wont crash and will return an invalid QModelIndex
233  // when asked for the parent of an invalid index.
234  Q_ASSERT(model->parent(QModelIndex()) == QModelIndex());
235 
236  if (model->rowCount() == 0)
237  return;
238 
239  // Column 0 | Column 1 |
240  // QModelIndex() | |
241  // \- topIndex | topIndex1 |
242  // \- childIndex | childIndex1 |
243 
244  // Common error test #1, make sure that a top level index has a parent
245  // that is a invalid QModelIndex.
246  QModelIndex topIndex = model->index(0, 0, QModelIndex());
247  Q_ASSERT(model->parent(topIndex) == QModelIndex());
248 
249  // Common error test #2, make sure that a second level index has a parent
250  // that is the first level index.
251  if (model->rowCount(topIndex) > 0) {
252  QModelIndex childIndex = model->index(0, 0, topIndex);
253  Q_ASSERT(model->parent(childIndex) == topIndex);
254  }
255 
256  // Common error test #3, the second column should NOT have the same children
257  // as the first column in a row.
258  // Usually the second column shouldn't have children.
259  QModelIndex topIndex1 = model->index(0, 1, QModelIndex());
260  if (model->rowCount(topIndex1) > 0) {
261  QModelIndex childIndex = model->index(0, 0, topIndex);
262  QModelIndex childIndex1 = model->index(0, 0, topIndex1);
263  Q_ASSERT(childIndex != childIndex1);
264  }
265 
266  // Full test, walk n levels deep through the model making sure that all
267  // parent's children correctly specify their parent.
268  checkChildren(QModelIndex());
269 }
270 
285 void ModelTest::checkChildren(const QModelIndex &parent, int currentDepth)
286 {
287  // First just try walking back up the tree.
288  QModelIndex p = parent;
289  while (p.isValid())
290  p = p.parent();
291 
292  // For models that are dynamically populated
293  if (model->canFetchMore(parent)) {
294  fetchingMore = true;
295  model->fetchMore(parent);
296  fetchingMore = false;
297  }
298 
299  int rows = model->rowCount(parent);
300  int columns = model->columnCount(parent);
301 
302  if (rows > 0)
303  Q_ASSERT(model->hasChildren(parent));
304 
305  // Some further testing against rows(), columns(), and hasChildren()
306  Q_ASSERT(rows >= 0);
307  Q_ASSERT(columns >= 0);
308  if (rows > 0)
309  Q_ASSERT(model->hasChildren(parent) == true);
310 
311  //qDebug() << "parent:" << model->data(parent).toString() << "rows:" << rows
312  // << "columns:" << columns << "parent column:" << parent.column();
313 
314  Q_ASSERT(model->hasIndex(rows + 1, 0, parent) == false);
315  for (int r = 0; r < rows; ++r) {
316  if (model->canFetchMore(parent)) {
317  fetchingMore = true;
318  model->fetchMore(parent);
319  fetchingMore = false;
320  }
321  Q_ASSERT(model->hasIndex(r, columns + 1, parent) == false);
322  for (int c = 0; c < columns; ++c) {
323  Q_ASSERT(model->hasIndex(r, c, parent) == true);
324  QModelIndex index = model->index(r, c, parent);
325  // rowCount() and columnCount() said that it existed...
326  Q_ASSERT(index.isValid() == true);
327 
328  // index() should always return the same index when called twice in a row
329  QModelIndex modifiedIndex = model->index(r, c, parent);
330  Q_ASSERT(index == modifiedIndex);
331 
332  // Make sure we get the same index if we request it twice in a row
333  QModelIndex a = model->index(r, c, parent);
334  QModelIndex b = model->index(r, c, parent);
335  Q_ASSERT(a == b);
336 
337  // Some basic checking on the index that is returned
338  Q_ASSERT(index.model() == model);
339  Q_ASSERT(index.row() == r);
340  Q_ASSERT(index.column() == c);
341  // While you can technically return a QVariant usually this is a sign
342  // of an bug in data() Disable if this really is ok in your model.
343  Q_ASSERT(model->data(index, Qt::DisplayRole).isValid() == true);
344 
345  // If the next test fails here is some somewhat useful debug you play with.
346  /*
347  if (model->parent(index) != parent) {
348  qDebug() << r << c << currentDepth << model->data(index).toString()
349  << model->data(parent).toString();
350  qDebug() << index << parent << model->parent(index);
351  // And a view that you can even use to show the model.
352  //QTreeView view;
353  //view.setModel(model);
354  //view.show();
355  }*/
356 
357  // Check that we can get back our real parent.
358  Q_ASSERT(model->parent(index) == parent);
359 
360  // recursively go down the children
361  if (model->hasChildren(index) && currentDepth < 10 ) {
362  //qDebug() << r << c << "has children" << model->rowCount(index);
363  checkChildren(index, ++currentDepth);
364  }/* else { if (currentDepth >= 10) qDebug() << "checked 10 deep"; };*/
365 
366  // make sure that after testing the children that the index doesn't change.
367  QModelIndex newerIndex = model->index(r, c, parent);
368  Q_ASSERT(index == newerIndex);
369  }
370  }
371 }
372 
376 void ModelTest::data()
377 {
378  // Invalid index should return an invalid qvariant
379  Q_ASSERT(!model->data(QModelIndex()).isValid());
380 
381  if (model->rowCount() == 0)
382  return;
383 
384  // A valid index should have a valid QVariant data
385  Q_ASSERT(model->index(0, 0).isValid());
386 
387  // shouldn't be able to set data on an invalid index
388  Q_ASSERT(model->setData(QModelIndex(), QLatin1String("foo"), Qt::DisplayRole) == false);
389 
390  // General Purpose roles that should return a QString
391  QVariant variant = model->data(model->index(0, 0), Qt::ToolTipRole);
392  if (variant.isValid()) {
393  Q_ASSERT(qVariantCanConvert<QString>(variant));
394  }
395  variant = model->data(model->index(0, 0), Qt::StatusTipRole);
396  if (variant.isValid()) {
397  Q_ASSERT(qVariantCanConvert<QString>(variant));
398  }
399  variant = model->data(model->index(0, 0), Qt::WhatsThisRole);
400  if (variant.isValid()) {
401  Q_ASSERT(qVariantCanConvert<QString>(variant));
402  }
403 
404  // General Purpose roles that should return a QSize
405  variant = model->data(model->index(0, 0), Qt::SizeHintRole);
406  if (variant.isValid()) {
407  Q_ASSERT(qVariantCanConvert<QSize>(variant));
408  }
409 
410  // General Purpose roles that should return a QFont
411  QVariant fontVariant = model->data(model->index(0, 0), Qt::FontRole);
412  if (fontVariant.isValid()) {
413  Q_ASSERT(qVariantCanConvert<QFont>(fontVariant));
414  }
415 
416  // Check that the alignment is one we know about
417  QVariant textAlignmentVariant = model->data(model->index(0, 0), Qt::TextAlignmentRole);
418  if (textAlignmentVariant.isValid()) {
419  int alignment = textAlignmentVariant.toInt();
420  Q_ASSERT(alignment == Qt::AlignLeft ||
421  alignment == Qt::AlignRight ||
422  alignment == Qt::AlignHCenter ||
423  alignment == Qt::AlignJustify ||
424  alignment == Qt::AlignTop ||
425  alignment == Qt::AlignBottom ||
426  alignment == Qt::AlignVCenter ||
427  alignment == Qt::AlignCenter ||
428  alignment == Qt::AlignAbsolute ||
429  alignment == Qt::AlignLeading ||
430  alignment == Qt::AlignTrailing);
431  }
432 
433  // General Purpose roles that should return a QColor
434  QVariant colorVariant = model->data(model->index(0, 0), Qt::BackgroundColorRole);
435  if (colorVariant.isValid()) {
436  Q_ASSERT(qVariantCanConvert<QColor>(colorVariant));
437  }
438 
439  colorVariant = model->data(model->index(0, 0), Qt::TextColorRole);
440  if (colorVariant.isValid()) {
441  Q_ASSERT(qVariantCanConvert<QColor>(colorVariant));
442  }
443 
444  // Check that the "check state" is one we know about.
445  QVariant checkStateVariant = model->data(model->index(0, 0), Qt::CheckStateRole);
446  if (checkStateVariant.isValid()) {
447  int state = checkStateVariant.toInt();
448  Q_ASSERT(state == Qt::Unchecked ||
449  state == Qt::PartiallyChecked ||
450  state == Qt::Checked);
451  }
452 }
453 
459 void ModelTest::rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
460 {
461  Q_UNUSED(end);
462  Changing c;
463  c.parent = parent;
464  c.oldSize = model->rowCount(parent);
465  c.last = model->data(model->index(start - 1, 0, parent));
466  c.next = model->data(model->index(start, 0, parent));
467  insert.push(c);
468 }
469 
475 void ModelTest::rowsInserted(const QModelIndex & parent, int start, int end)
476 {
477  Changing c = insert.pop();
478  Q_ASSERT(c.parent == parent);
479  Q_ASSERT(c.oldSize + (end - start + 1) == model->rowCount(parent));
480  Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent)));
481  /*
482  if (c.next != model->data(model->index(end + 1, 0, c.parent))) {
483  qDebug() << start << end;
484  for (int i=0; i < model->rowCount(); ++i)
485  qDebug() << model->index(i, 0).data().toString();
486  qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent));
487  }
488  */
489  Q_ASSERT(c.next == model->data(model->index(end + 1, 0, c.parent)));
490 }
491 
492 void ModelTest::layoutAboutToBeChanged()
493 {
494  for (int i = 0; i < qBound(0, model->rowCount(), 100); ++i)
495  changing.append(QPersistentModelIndex(model->index(i, 0)));
496 }
497 
498 void ModelTest::layoutChanged()
499 {
500  for (int i = 0; i < changing.count(); ++i) {
501  QPersistentModelIndex p = changing[i];
502  Q_ASSERT(p == model->index(p.row(), p.column(), p.parent()));
503  }
504  changing.clear();
505 }
506 
512 void ModelTest::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
513 {
514  Changing c;
515  c.parent = parent;
516  c.oldSize = model->rowCount(parent);
517  c.last = model->data(model->index(start - 1, 0, parent));
518  c.next = model->data(model->index(end + 1, 0, parent));
519  remove.push(c);
520 }
521 
527 void ModelTest::rowsRemoved(const QModelIndex & parent, int start, int end)
528 {
529  Changing c = remove.pop();
530  Q_ASSERT(c.parent == parent);
531  Q_ASSERT(c.oldSize - (end - start + 1) == model->rowCount(parent));
532  Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent)));
533  Q_ASSERT(c.next == model->data(model->index(start, 0, c.parent)));
534 }
535 
QAbstractItemModel::hasIndex
bool hasIndex(int row, int column, const QModelIndex &parent) const
flags
static const char * flags[]
Definition: readerstatus.cpp:114
QList::clear
void clear()
QModelIndex
QAbstractItemModel::rowCount
virtual int rowCount(const QModelIndex &parent) const =0
QAbstractItemModel::index
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const =0
QStack::pop
T pop()
QAbstractItemModel::buddy
virtual QModelIndex buddy(const QModelIndex &index) const
QAbstractItemModel::canFetchMore
virtual bool canFetchMore(const QModelIndex &parent) const
QAbstractItemModel::span
virtual QSize span(const QModelIndex &index) const
ModelTest::runAllTests
void runAllTests()
Definition: modeltest.cpp:80
QAbstractItemModel::itemData
virtual QMap< int, QVariant > itemData(const QModelIndex &index) const
QPersistentModelIndex::column
int column() const
QStack::push
void push(const T &t)
QMap
Definition: signingcertificateselectiondialog.h:41
ModelTest::rowsInserted
void rowsInserted(const QModelIndex &parent, int start, int end)
Definition: modeltest.cpp:475
ModelTest::rowsAboutToBeRemoved
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
Definition: modeltest.cpp:512
QAbstractItemModel::mimeTypes
virtual QStringList mimeTypes() const
QAbstractItemModel::match
virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits, QFlags< Qt::MatchFlag > flags) const
QModelIndex::isValid
bool isValid() const
QList::count
int count(const T &value) const
QList::append
void append(const T &value)
ModelTest::rowsAboutToBeInserted
void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
Definition: modeltest.cpp:459
QVariant::toInt
int toInt(bool *ok) const
QAbstractItemModel::setHeaderData
virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
QObject
modeltest.h
QAbstractItemModel::sibling
QModelIndex sibling(int row, int column, const QModelIndex &index) const
QAbstractItemModel::supportedDropActions
virtual Qt::DropActions supportedDropActions() const
QAbstractItemModel::data
virtual QVariant data(const QModelIndex &index, int role) const =0
QModelIndex::parent
QModelIndex parent() const
QAbstractItemModel::headerData
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const
QAbstractItemModel::parent
virtual QModelIndex parent(const QModelIndex &index) const =0
ModelTest::rowsRemoved
void rowsRemoved(const QModelIndex &parent, int start, int end)
Definition: modeltest.cpp:527
ModelTest::layoutChanged
void layoutChanged()
Definition: modeltest.cpp:498
QPersistentModelIndex
QLatin1String
ModelTest
Definition: modeltest.h:31
QAbstractItemModel::hasChildren
virtual bool hasChildren(const QModelIndex &parent) const
ModelTest::layoutAboutToBeChanged
void layoutAboutToBeChanged()
Definition: modeltest.cpp:492
QAbstractItemModel::columnCount
virtual int columnCount(const QModelIndex &parent) const =0
QAbstractItemModel::fetchMore
virtual void fetchMore(const QModelIndex &parent)
QAbstractItemModel
QAbstractItemModel::setData
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
QVariant::isValid
bool isValid() const
QAbstractItemModel::flags
virtual Qt::ItemFlags flags(const QModelIndex &index) const
QPersistentModelIndex::parent
QModelIndex parent() const
QPersistentModelIndex::row
int row() const
QVariant
Qt::ItemFlags
typedef ItemFlags
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:33:11 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kleopatra

Skip menu "kleopatra"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer
  • pimprint

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