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

rocs/RocsCore

  • sources
  • kde-4.12
  • kdeedu
  • rocs
  • RocsCore
Data.cpp
Go to the documentation of this file.
1 /*
2  This file is part of Rocs.
3  Copyright 2004-2011 Tomaz Canabrava <tomaz.canabrava@gmail.com>
4  Copyright 2012 Andreas Cord-Landwehr <cola@uni-paderborn.de>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Lesser General Public
8  License as published by the Free Software Foundation; either
9  version 2.1 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public
17  License along with this library. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "Data.h"
21 #include "DataType.h"
22 #include "Pointer.h"
23 #include "DataStructure.h"
24 #include "QtScriptBackend.h"
25 
26 #include <KDebug>
27 #include <KLocale>
28 #include <KGlobal>
29 #include <QColor>
30 #include <QMap>
31 #include <boost/weak_ptr.hpp>
32 
33 
34 class DataPrivate
35 {
36 public:
37  DataPrivate(DataStructurePtr parent, int uniqueIdentifier, int dataType);
38 
42  boost::weak_ptr<Data> q;
43 
44  PointerList _inPointers;
45  PointerList _outPointers;
46 
47  qreal _x;
48  qreal _y;
49  qreal _width;
50  bool _visible;
51 
52  DataStructurePtr _dataStructure;
53  int _uniqueIdentifier;
54  DataTypePtr _dataType;
55  QColor _color;
56 
57  QScriptValue _scriptvalue;
58  QScriptEngine *_engine;
59 
66  QScriptValue createScriptArray(PointerList list);
67 };
68 
69 DataPrivate::DataPrivate(DataStructurePtr parent, int uniqueIdentifier, int dataType)
70  : _x(0)
71  , _y(0)
72  , _width(0.3)
73  , _visible(parent->document()->dataType(dataType)->isVisible())
74  , _dataStructure(parent)
75  , _uniqueIdentifier(uniqueIdentifier)
76  , _dataType(_dataStructure->document()->dataType(dataType))
77  , _color(parent->document()->dataType(dataType)->defaultColor())
78 {
79  _inPointers = PointerList();
80  _outPointers = PointerList();
81 }
82 
83 QScriptValue DataPrivate::createScriptArray(PointerList list)
84 {
85  QScriptValue array = _engine->newArray();
86  foreach(PointerPtr e, list) {
87  array.property("push").call(array, QScriptValueList() << e->scriptValue());
88  }
89  return array;
90 }
91 
92 DataPtr Data::create(DataStructurePtr dataStructure, int uniqueIdentifier, int dataType)
93 {
94  return create<Data>(dataStructure, uniqueIdentifier, dataType);
95 }
96 
97 void Data::setQpointer(DataPtr q)
98 {
99  d->q = q;
100 }
101 
102 void Data::initialize()
103 {
104  installEventFilter(this);
105  QStringList properties = d->_dataType->properties();
106  foreach(const QString &property, properties) {
107  addDynamicProperty(property, d->_dataType->propertyDefaultValue(property));
108  }
109 
110  connect(d->_dataType.get(), SIGNAL(propertyAdded(QString,QVariant)),
111  this, SLOT(addDynamicProperty(QString,QVariant)));
112  connect(d->_dataType.get(), SIGNAL(propertyRemoved(QString)),
113  this, SLOT(removeDynamicProperty(QString)));
114  connect(d->_dataType.get(), SIGNAL(propertyRenamed(QString,QString)),
115  this, SLOT(renameDynamicProperty(QString,QString)));
116  connect(d->_dataType.get(), SIGNAL(propertyDefaultValueChanged(QString)),
117  this, SLOT(updateDynamicProperty(QString)));
118  connect(d->_dataType.get(), SIGNAL(propertyVisibilityChanged(QString)),
119  this, SLOT(updateDynamicProperty(QString)));
120  connect(d->_dataType.get(), SIGNAL(visibilityChanged(bool)),
121  this, SLOT(setVisible(bool)));
122  connect(d->_dataType.get(), SIGNAL(removed()), this, SLOT(remove()));
123 }
124 
125 DataPtr Data::getData() const
126 {
127  DataPtr px(d->q);
128  return px;
129 }
130 
131 // Do NOT set a parent, since shared pointer will take care for deletion!
132 Data::Data(DataStructurePtr dataStructure, int uniqueIdentifier, int dataType)
133  : QObject(0),
134  d(new DataPrivate(dataStructure, uniqueIdentifier, dataType))
135 {
136 }
137 
138 Data::~Data()
139 {
140 }
141 
142 bool Data::eventFilter(QObject *obj, QEvent *event){
143  if (event->type() == QEvent::DynamicPropertyChange) {
144  QString property = QString::fromLatin1(static_cast<QDynamicPropertyChangeEvent*>(event)->propertyName());
145  emit(propertyChanged(property));
146  }
147  return QObject::eventFilter(obj, event);
148 }
149 
150 DataStructurePtr Data::dataStructure() const
151 {
152  return d->_dataStructure;
153 }
154 
155 bool Data::isVisible() const
156 {
157  return d->_visible;
158 }
159 
160 void Data::setVisible(bool visible)
161 {
162  d->_visible = visible;
163  emit visibilityChanged(visible);
164 }
165 
166 void Data::setDataType(int dataType)
167 {
168  Q_ASSERT(d->_dataStructure->document()->dataTypeList().contains(dataType));
169 
170  // disconnect from old data type
171  if (d->_dataType) {
172  d->_dataType.get()->disconnect(this);
173  }
174 
175  // make changes
176  d->_dataType = d->_dataStructure->document()->dataType(dataType);
177  d->_dataStructure->updateData(getData());
178  foreach(const QString& property, d->_dataType->properties()) {
179  if (this->property(property.toLatin1()) == QVariant::Invalid) {
180  addDynamicProperty(property, d->_dataType->propertyDefaultValue(property));
181  }
182  }
183  emit dataTypeChanged(dataType);
184 
185  // connect to new type
186  connect(d->_dataType.get(), SIGNAL(propertyAdded(QString,QVariant)),
187  this, SLOT(addDynamicProperty(QString,QVariant)));
188  connect(d->_dataType.get(), SIGNAL(propertyDefaultValueChanged(QString)),
189  this, SLOT(updateDynamicProperty(QString)));
190  connect(d->_dataType.get(), SIGNAL(propertyVisibilityChanged(QString)),
191  this, SLOT(updateDynamicProperty(QString)));
192  connect(d->_dataType.get(), SIGNAL(propertyRenamed(QString,QString)),
193  this, SLOT(renameDynamicProperty(QString,QString)));
194  connect(d->_dataType.get(), SIGNAL(removed()), this, SLOT(remove()));
195 }
196 
197 DataList Data::adjacentDataList() const
198 {
199  // use QMap as the DataPtr elements are not hashable
200  // and we can speed up process by using the uniqe IDs
201  QMap<int, DataPtr> adjacent;
202  foreach(PointerPtr e, d->_outPointers) {
203  if (e->to() != e->from() && e->to() == getData()) {
204  continue;
205  }
206  adjacent[e->to()->identifier()] = e->to();
207  }
208 
209  foreach(PointerPtr e, d->_inPointers) {
210  if (e->to() != e->from() && e->from() == getData()) {
211  continue;
212  }
213  adjacent[e->from()->identifier()] = e->from();
214  }
215  return adjacent.values();
216 }
217 
218 PointerList Data::pointerList() const
219 {
220  PointerList adjacent;
221  foreach (const PointerPtr& p, d->_outPointers) {
222  adjacent.append(p);
223  }
224  foreach (const PointerPtr& p, d->_inPointers) {
225  adjacent.append(p);
226  }
227 
228  return adjacent;
229 }
230 
231 void Data::addPointer(PointerPtr pointer)
232 {
233  // state variable
234  bool changed = false;
235  // in-pointer
236  if (pointer->to()->identifier() == identifier() || pointer->direction() == PointerType::Bidirectional) {
237  if (!d->_inPointers.contains(pointer)) {
238  d->_inPointers.append(pointer);
239  changed = true;
240  }
241  }
242  // out-pointer
243  if (pointer->from()->identifier() == identifier() || pointer->direction() == PointerType::Bidirectional) {
244  if (!d->_outPointers.contains(pointer)) {
245  d->_outPointers.append(pointer);
246  changed = true;
247  }
248  }
249  // both must be check to guarantee that pointer is register only once: otherwise after a change of direction
250  // a single check could not suffice
251  if (changed) {
252  connect(pointer.get(), SIGNAL(directionChanged(PointerType::Direction)), this, SLOT(updatePointerList()), Qt::UniqueConnection);
253  emit pointerListChanged();
254  }
255 }
256 
257 PointerPtr Data::createPointer(DataPtr to)
258 {
259  return d->_dataStructure->createPointer(this->getData(), to, 0);
260 }
261 
262 void Data::remove(PointerPtr e)
263 {
264  // removes pointer from any list that could contain it
265  if (d->_inPointers.removeOne(e)) {
266  emit pointerListChanged();
267  d->_dataStructure->remove(e);
268  // not necessary to call e->remove() here, since data structure already calls that
269  }
270  if (d->_outPointers.removeOne(e)) {
271  emit pointerListChanged();
272  d->_dataStructure->remove(e);
273  // not necessary to call e->remove() here, since data structure already calls that
274  }
275 }
276 
277 void Data::updatePointerList()
278 {
279  bool changed = false;
280  PointerList tmpList = pointerList();
281  foreach(PointerPtr pointer, tmpList) {
282  if (pointer->direction() == PointerType::Bidirectional) {
283  if (!d->_inPointers.contains(pointer)) {
284  d->_inPointers.append(pointer);
285  changed = true;
286  }
287  if (!d->_outPointers.contains(pointer)) {
288  d->_outPointers.append(pointer);
289  changed = true;
290  }
291  }
292  if (pointer->direction() == PointerType::Unidirectional) {
293  if (getData() == pointer->from() && d->_inPointers.contains(pointer)) {
294  d->_inPointers.removeOne(pointer);
295  changed = true;
296  }
297  if (getData() == pointer->to() && d->_outPointers.contains(pointer)) {
298  d->_outPointers.removeOne(pointer);
299  changed = true;
300  }
301  }
302  }
303  if (changed) {
304  emit pointerListChanged();
305  }
306 }
307 
308 PointerList Data::pointerList(DataPtr to) const
309 {
310  PointerList list;
311  foreach(PointerPtr tmp, d->_outPointers) {
312  if (tmp->to() == to) {
313  list.append(tmp);
314  }
315  }
316  return list;
317 }
318 
319 void Data::remove()
320 {
321  emit removed();
322  // disconnect from DataType signals
323  disconnect(d->_dataType.get(), 0, this, 0);
324 
325  while (!d->_inPointers.isEmpty()) {
326  remove(d->_inPointers.first());
327  }
328  while (!d->_outPointers.isEmpty()) {
329  remove(d->_outPointers.first());
330  }
331 
332  d->_dataStructure->remove(getData());
333 }
334 
335 
336 void Data::self_remove()
337 {
338  kWarning() << "self_remove() is a deprecated function, please use remove()";
339  remove();
340 }
341 
342 QVariant Data::color() const
343 {
344  return d->_color;
345 }
346 
347 qreal Data::x() const
348 {
349  return d->_x;
350 }
351 
352 qreal Data::y() const
353 {
354  return d->_y;
355 }
356 
357 qreal Data::width() const
358 {
359  return d->_width;
360 }
361 
362 QString Data::icon() const
363 {
364  return d->_dataType->iconName();
365 }
366 
367 QList< QString > Data::properties() const
368 {
369  return d->_dataType->properties();
370 }
371 
372 PointerList& Data::inPointerList() const
373 {
374  return d->_inPointers;
375 }
376 
377 PointerList& Data::outPointerList() const
378 {
379  return d->_outPointers;
380 }
381 
382 int Data::identifier() const
383 {
384  return d->_uniqueIdentifier;
385 }
386 
387 int Data::dataType() const
388 {
389  return d->_dataType->identifier();
390 }
391 
392 void Data::setX(int x)
393 {
394  if (d->_x != x) {
395  d->_x = x;
396  emit posChanged(QPointF(d->_x, d->_y));
397  }
398 }
399 
400 void Data::setY(int y)
401 {
402  if (d->_y != y) {
403  d->_y = y;
404  emit posChanged(QPointF(d->_x, d->_y));
405  }
406 }
407 
408 void Data::setWidth(double w)
409 {
410  if (d->_width != w) {
411  d->_width = (qreal)w;
412  emit widthChanged(w);
413  }
414 }
415 
416 void Data::setPos(qreal x, qreal y)
417 {
418  if (d->_x != x || d->_y != y) {
419  d->_x = x;
420  d->_y = y;
421  emit posChanged(QPointF(d->_x, d->_y));
422  }
423 }
424 
425 void Data::setColor(const QVariant& s)
426 {
427  QColor c = s.value<QColor>();
428  if (d->_color != c) {
429  d->_color = c;
430  emit colorChanged(c);
431  }
432 }
433 
434 void Data::addDynamicProperty(const QString& property, const QVariant& value)
435 {
436  if (!Document::isValidIdentifier(property)) {
437  kWarning() << "Property identifier \"" << property << "\" is not valid: aborting";
438  return;
439  }
440  setProperty(property.toLatin1(), value);
441  emit propertyAdded(property);
442 }
443 
444 void Data::removeDynamicProperty(const QString& property)
445 {
446  // setting property to invalid is equals to deleting it
447  setProperty(property.toLatin1(), QVariant::Invalid);
448  emit propertyRemoved(property);
449 }
450 
451 void Data::updateDynamicProperty(const QString& property)
452 {
453  if (this->property(property.toLatin1()) == QVariant::Invalid
454  || this->property(property.toLatin1()).toString().isEmpty()
455  ) {
456  this->setProperty(property.toLatin1(), d->_dataType->propertyDefaultValue(property));
457  }
458  emit propertyChanged(property);
459 }
460 
461 void Data::renameDynamicProperty(const QString& oldName, const QString& newName)
462 {
463  if (!Document::isValidIdentifier(newName)) {
464  kWarning() << "Property identifier \"" << newName << "\" is not valid: aborting";
465  return;
466  }
467  setProperty(newName.toLatin1(), property(oldName.toLatin1()));
468  setProperty(oldName.toLatin1(), QVariant::Invalid);
469 }
470 
471 QScriptValue Data::scriptValue() const
472 {
473  return d->_scriptvalue;
474 }
475 
476 void Data::setEngine(QScriptEngine *engine)
477 {
478  d->_engine = engine;
479  d->_scriptvalue = engine->newQObject(getData().get());
480 }
481 
482 QScriptEngine * Data::engine() const
483 {
484  return d->_engine;
485 }
486 
487 QScriptValue Data::set_type(int dataType)
488 {
489  if (!d->_dataStructure->document()->dataTypeList().contains(dataType)) {
490  dataStructure()->document()->engineBackend()->debug(
491  i18n("Could not set data type for node %1: data type does not exist.", identifier()));
492  return d->_dataStructure->engine()->newVariant(false);
493  }
494  setDataType(dataType);
495  return d->_dataStructure->engine()->newVariant(true);
496 }
497 
498 QScriptValue Data::type()
499 {
500  return d->_dataStructure->engine()->newVariant(d->_dataType->identifier());
501 }
502 
503 void Data::add_property(const QString& name, const QString& value)
504 {
505  addDynamicProperty(name, value);
506 }
507 
508 void Data::remove_property (const QString& name)
509 {
510  removeDynamicProperty(name);
511 }
512 
513 QScriptValue Data::adj_data()
514 {
515  QList< DataPtr > list = adjacentDataList();
516  QScriptValue array = d->_engine->newArray();
517  foreach(DataPtr n, list) {
518  array.property("push").call(array, QScriptValueList() << n->scriptValue());
519  }
520  return array;
521 }
522 
523 QScriptValue Data::adj_pointers()
524 {
525  PointerList list = pointerList();
526  return d->createScriptArray(list);
527 }
528 
529 QScriptValue Data::adj_pointers(int pointerType)
530 {
531  PointerList list;
532  foreach(PointerPtr n, pointerList()) {
533  if (n->pointerType() != pointerType) {
534  continue;
535  }
536  list.append(n);
537  }
538  return d->createScriptArray(list);
539 }
540 
541 QScriptValue Data::input_pointers()
542 {
543  PointerList list = inPointerList();
544  return d->createScriptArray(list);
545 }
546 
547 QScriptValue Data::input_pointers(int pointerType)
548 {
549  PointerList list;
550  foreach(PointerPtr n, inPointerList()) {
551  if (n->pointerType() != pointerType) {
552  continue;
553  }
554  list.append(n);
555  }
556  return d->createScriptArray(list);
557 }
558 
559 QScriptValue Data::output_pointers()
560 {
561  PointerList list = outPointerList();
562  return d->createScriptArray(list);
563 }
564 
565 QScriptValue Data::output_pointers(int pointerType)
566 {
567  PointerList list;
568  foreach(PointerPtr n, outPointerList()) {
569  if (n->pointerType() != pointerType) {
570  continue;
571  }
572  list.append(n);
573  }
574  return d->createScriptArray(list);
575 }
576 
577 QScriptValue Data::connected_pointers(Data *n)
578 {
579  if (n == 0) {
580  return QScriptValue();
581  }
582  PointerList list = pointerList(n->getData());
583  return d->createScriptArray(list);
584 }
DataType.h
Data::icon
QString icon() const
Definition: Data.cpp:362
Data::setColor
void setColor(const QVariant &s)
Definition: Data.cpp:425
Data::remove_property
void remove_property(const QString &name)
Definition: Data.cpp:508
Data::removeDynamicProperty
void removeDynamicProperty(const QString &property)
Remove dynamic property with identifier property from data element.
Definition: Data.cpp:444
Data::adj_data
QScriptValue adj_data()
Definition: Data.cpp:513
PointerType::Bidirectional
Definition: PointerType.h:48
Data::pointerListChanged
void pointerListChanged()
Data::setEngine
virtual void setEngine(QScriptEngine *_engine)
Set script engine.
Definition: Data.cpp:476
Data::dataStructure
DataStructurePtr dataStructure() const
Definition: Data.cpp:150
DataStructurePtr
boost::shared_ptr< DataStructure > DataStructurePtr
Definition: CoreTypes.h:38
GmlParser::document
Document * document
Definition: GmlGrammar.cpp:40
Data::Data
Data(DataStructurePtr dataStructure, int uniqueIdentifer, int dataType)
Protected constructor.
Definition: Data.cpp:132
Data::addPointer
void addPointer(PointerPtr pointer)
Register an created pointer to this data element.
Definition: Data.cpp:231
Data::renameDynamicProperty
void renameDynamicProperty(const QString &oldName, const QString &newName)
Definition: Data.cpp:461
Data::propertyRemoved
void propertyRemoved(const QString &name)
Data::eventFilter
bool eventFilter(QObject *obj, QEvent *event)
Definition: Data.cpp:142
DataList
QList< boost::shared_ptr< Data > > DataList
Definition: CoreTypes.h:30
Data::dataType
int dataType() const
Definition: Data.cpp:387
QtScriptBackend.h
Data::dataTypeChanged
void dataTypeChanged(int dataType)
QObject
Data::y
qreal y() const
Data::scriptValue
QScriptValue scriptValue() const
Definition: Data.cpp:471
Data.h
Data::colorChanged
void colorChanged(const QColor &c)
Data::width
qreal width() const
Data::setY
void setY(int y)
Definition: Data.cpp:400
Data::updatePointerList
void updatePointerList()
FIXME proof of concept implementation: since each Pointer emits a changed direction signal...
Definition: Data.cpp:277
Data::visibilityChanged
void visibilityChanged(bool visible)
PointerType::Unidirectional
Definition: PointerType.h:47
Data::connected_pointers
QScriptValue connected_pointers(Data *n)
Definition: Data.cpp:577
PointerPtr
boost::shared_ptr< Pointer > PointerPtr
Definition: CoreTypes.h:35
Data::propertyAdded
void propertyAdded(const QString &name)
Data::createPointer
PointerPtr createPointer(DataPtr to)
Create new pointer to to.
Definition: Data.cpp:257
DataStructure.h
Data::updateDynamicProperty
void updateDynamicProperty(const QString &property)
Definition: Data.cpp:451
Data::setVisible
void setVisible(bool visible)
Definition: Data.cpp:160
Data::posChanged
void posChanged(const QPointF &p)
Data::widthChanged
void widthChanged(double w)
Data::adj_pointers
QScriptValue adj_pointers()
Definition: Data.cpp:523
Data::remove
void remove()
Definition: Data.cpp:319
Data::inPointerList
PointerList & inPointerList() const
Definition: Data.cpp:372
Data::~Data
virtual ~Data()
Default destructor.
Definition: Data.cpp:138
Data::add_property
void add_property(const QString &name, const QString &value)
Definition: Data.cpp:503
Data::engine
QScriptEngine * engine() const
Definition: Data.cpp:482
Data::color
QVariant color() const
Data::properties
QList< QString > properties() const
Definition: Data.cpp:367
Data::propertyChanged
void propertyChanged(const QString &name)
Data::self_remove
void self_remove()
Definition: Data.cpp:336
Data::set_type
QScriptValue set_type(int type)
Definition: Data.cpp:487
Data::removed
void removed()
Data::getData
virtual DataPtr getData() const
Definition: Data.cpp:125
Data::outPointerList
PointerList & outPointerList() const
Definition: Data.cpp:377
Data::setPos
void setPos(qreal x, qreal y)
Definition: Data.cpp:416
Data::input_pointers
QScriptValue input_pointers()
Definition: Data.cpp:541
PointerType::Direction
Direction
Definition: PointerType.h:46
Data::addDynamicProperty
void addDynamicProperty(const QString &property, const QVariant &value)
Add new dynamic property with identifier property to this data element and sets it to value...
Definition: Data.cpp:434
Pointer.h
DataPtr
boost::shared_ptr< Data > DataPtr
Definition: CoreTypes.h:34
Data::setDataType
void setDataType(int dataType)
Definition: Data.cpp:166
DataTypePtr
boost::shared_ptr< DataType > DataTypePtr
Definition: CoreTypes.h:36
Data::identifier
int identifier() const
Definition: Data.cpp:382
Data
Definition: Data.h:40
Data::setWidth
void setWidth(double w)
Definition: Data.cpp:408
Data::setX
void setX(int x)
Definition: Data.cpp:392
Data::x
qreal x() const
Document::isValidIdentifier
static bool isValidIdentifier(const QString &identifier)
Evaluates given string and returns true if identifier is valid, otherwise returns false...
Definition: Document.cpp:232
Data::type
QScriptValue type()
Definition: Data.cpp:498
Data::adjacentDataList
DataList adjacentDataList() const
Definition: Data.cpp:197
Data::pointerList
PointerList pointerList() const
Definition: Data.cpp:218
Data::create
static DataPtr create(DataStructurePtr dataStructure, int uniqueIdentifier, int dataType)
Create data element objects.
Definition: Data.cpp:92
Data::output_pointers
QScriptValue output_pointers()
Definition: Data.cpp:559
PointerList
QList< boost::shared_ptr< Pointer > > PointerList
Definition: CoreTypes.h:33
Data::isVisible
bool isVisible() const
Definition: Data.cpp:155
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:42:25 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

rocs/RocsCore

Skip menu "rocs/RocsCore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

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