• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDE3Support

  • kde3support
  • kdeui
k3listviewsearchline.cpp
Go to the documentation of this file.
1/* This file is part of the KDE libraries
2 Copyright (c) 2003 Scott Wheeler <wheeler@kde.org>
3 Copyright (c) 2005 Rafal Rzepecki <divide@users.sourceforge.net>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License version 2 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public 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
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18*/
19
20#include "k3listviewsearchline.h"
21
22#include <k3listview.h>
23#include <kiconloader.h>
24#include <ktoolbar.h>
25#include <kdebug.h>
26#include <klocale.h>
27
28#include <QApplication>
29#include <QTimer>
30#include <QMenu>
31#include <QLabel>
32#include <QContextMenuEvent>
33#include <QList>
34#include <Q3Header>
35#include <QToolButton>
36
37class K3ListViewSearchLine::K3ListViewSearchLinePrivate
38{
39public:
40 K3ListViewSearchLinePrivate() :
41 caseSensitive(Qt::CaseInsensitive),
42 activeSearch(false),
43 keepParentsVisible(true),
44 canChooseColumns(true),
45 queuedSearches(0),
46 allVisibleColumnsAction(0)
47 {}
48
49 QList<K3ListView *> listViews;
50 Qt::CaseSensitivity caseSensitive;
51 bool activeSearch;
52 bool keepParentsVisible;
53 bool canChooseColumns;
54 QString search;
55 int queuedSearches;
56 QList<int> searchColumns;
57 QAction *allVisibleColumnsAction;
58};
59
61// public methods
63
64K3ListViewSearchLine::K3ListViewSearchLine(QWidget *parent, K3ListView *listView) :
65 KLineEdit(parent)
66{
67 d = new K3ListViewSearchLinePrivate;
68 setClearButtonShown( true );
69
70 connect(this, SIGNAL(textChanged(QString)),
71 this, SLOT(queueSearch(QString)));
72
73 setListView( listView );
74 if( !listView)
75 setEnabled(false);
76}
77
78K3ListViewSearchLine::K3ListViewSearchLine(QWidget *parent,
79 const QList<K3ListView *> &listViews) :
80 KLineEdit(parent)
81{
82 d = new K3ListViewSearchLinePrivate;
83 setClearButtonShown( true );
84
85 connect(this, SIGNAL(textChanged(QString)),
86 this, SLOT(queueSearch(QString)));
87
88 setListViews( listViews );
89}
90
91
92K3ListViewSearchLine::~K3ListViewSearchLine()
93{
94 delete d;
95}
96
97bool K3ListViewSearchLine::caseSensitive() const
98{
99 return (d->caseSensitive ==Qt::CaseSensitive);
100}
101
102QList<int> K3ListViewSearchLine::searchColumns() const
103{
104 if (d->canChooseColumns)
105 return d->searchColumns;
106 else
107 return QList<int>();
108}
109
110bool K3ListViewSearchLine::keepParentsVisible() const
111{
112 return d->keepParentsVisible;
113}
114
115K3ListView *K3ListViewSearchLine::listView() const
116{
117 if ( d->listViews.count() == 1 )
118 return d->listViews.first();
119 else
120 return 0;
121}
122
123const QList<K3ListView *> &K3ListViewSearchLine::listViews() const
124{
125 return d->listViews;
126}
127
128
130// public slots
132
133void K3ListViewSearchLine::addListView(K3ListView *lv)
134{
135 if (lv) {
136 connectListView(lv);
137
138 d->listViews.append(lv);
139 setEnabled(!d->listViews.isEmpty());
140
141 checkColumns();
142 }
143}
144
145void K3ListViewSearchLine::removeListView(K3ListView *lv)
146{
147 if (lv) {
148 int idx = d->listViews.indexOf(lv);
149
150 if ( idx != -1 ) {
151 d->listViews.removeAt( idx );
152 checkColumns();
153
154 disconnectListView(lv);
155
156 setEnabled(!d->listViews.isEmpty());
157 }
158 }
159}
160
161void K3ListViewSearchLine::updateSearch(const QString &s)
162{
163 d->search = s.isNull() ? text() : s;
164
165 for (QList<K3ListView *>::Iterator it = d->listViews.begin();
166 it != d->listViews.end(); ++it)
167 updateSearch( *it );
168}
169
170void K3ListViewSearchLine::updateSearch(K3ListView *listView)
171{
172 if(!listView)
173 return;
174
175
176 // If there's a selected item that is visible, make sure that it's visible
177 // when the search changes too (assuming that it still matches).
178
179 Q3ListViewItem *currentItem = 0;
180
181 switch(listView->selectionMode())
182 {
183 case K3ListView::NoSelection:
184 break;
185 case K3ListView::Single:
186 currentItem = listView->selectedItem();
187 break;
188 default:
189 {
190 int flags = Q3ListViewItemIterator::Selected | Q3ListViewItemIterator::Visible;
191 for(Q3ListViewItemIterator it(listView, flags);
192 it.current() && !currentItem;
193 ++it)
194 {
195 if(listView->itemRect(it.current()).isValid())
196 currentItem = it.current();
197 }
198 }
199 }
200
201 if(d->keepParentsVisible)
202 checkItemParentsVisible(listView->firstChild());
203 else
204 checkItemParentsNotVisible(listView);
205
206 if(currentItem)
207 listView->ensureItemVisible(currentItem);
208}
209
210void K3ListViewSearchLine::setCaseSensitive(bool cs)
211{
212 d->caseSensitive = cs?Qt::CaseSensitive:Qt::CaseInsensitive;
213}
214
215void K3ListViewSearchLine::setKeepParentsVisible(bool v)
216{
217 d->keepParentsVisible = v;
218}
219
220void K3ListViewSearchLine::setSearchColumns(const QList<int> &columns)
221{
222 if (d->canChooseColumns)
223 d->searchColumns = columns;
224}
225
226void K3ListViewSearchLine::setListView(K3ListView *lv)
227{
228 setListViews(QList<K3ListView *>());
229 addListView(lv);
230}
231
232void K3ListViewSearchLine::setListViews(const QList<K3ListView *> &lv)
233{
234 for (QList<K3ListView *>::Iterator it = d->listViews.begin();
235 it != d->listViews.end(); ++it)
236 disconnectListView(*it);
237
238 d->listViews = lv;
239
240 for (QList<K3ListView *>::Iterator it = d->listViews.begin();
241 it != d->listViews.end(); ++it)
242 connectListView(*it);
243
244 checkColumns();
245 setEnabled(!d->listViews.isEmpty());
246}
247
249// protected members
251
252bool K3ListViewSearchLine::itemMatches(const Q3ListViewItem *item, const QString &s) const
253{
254 if(s.isEmpty())
255 return true;
256
257 // If the search column list is populated, search just the columns
258 // specifified. If it is empty default to searching all of the columns.
259
260 if(!d->searchColumns.isEmpty()) {
261 QList<int>::ConstIterator it = d->searchColumns.constBegin();
262 for(; it != d->searchColumns.constEnd(); ++it) {
263 if(*it < item->listView()->columns() &&
264 item->text(*it).indexOf(s, 0, d->caseSensitive) >= 0)
265 return true;
266 }
267 }
268 else {
269 for(int i = 0; i < item->listView()->columns(); i++) {
270 if(item->listView()->columnWidth(i) > 0 &&
271 item->text(i).indexOf(s, 0, d->caseSensitive) >= 0)
272 {
273 return true;
274 }
275 }
276 }
277
278 return false;
279}
280
281void K3ListViewSearchLine::contextMenuEvent( QContextMenuEvent*e )
282{
283 QMenu *popup = KLineEdit::createStandardContextMenu();
284
285 if (d->canChooseColumns) {
286 popup->addSeparator();
287 QMenu *subMenu = popup->addMenu(i18n("Search Columns"));
288 connect(subMenu, SIGNAL(triggered(QAction*)), this, SLOT(searchColumnsMenuActivated(QAction*)));
289
290 d->allVisibleColumnsAction = subMenu->addAction(i18n("All Visible Columns"));
291 d->allVisibleColumnsAction->setCheckable( true );
292 subMenu->addSeparator();
293
294 bool allColumnsAreSearchColumns = true;
295 // TODO Make the entry order match the actual column order
296 Q3Header* const header = d->listViews.first()->header();
297 int visibleColumns = 0;
298 for(int i = 0; i < d->listViews.first()->columns(); i++) {
299 if(d->listViews.first()->columnWidth(i)>0) {
300 QString columnText = d->listViews.first()->columnText(i);
301 if(columnText.isEmpty()) {
302 int visiblePosition=1;
303 for(int j = 0; j < header->mapToIndex(i); j++)
304 if(d->listViews.first()->columnWidth(header->mapToSection(j))>0)
305 visiblePosition++;
306
307 columnText = i18nc("Column number %1","Column No. %1", visiblePosition);
308 }
309 QAction *action = subMenu->addAction(columnText);
310 action->setData( visibleColumns );
311 action->setCheckable( true );
312
313 if(d->searchColumns.isEmpty() || d->searchColumns.indexOf(i) != -1)
314 action->setChecked(true);
315 else
316 allColumnsAreSearchColumns = false;
317
318 visibleColumns++;
319 }
320 }
321 d->allVisibleColumnsAction->setChecked( allColumnsAreSearchColumns );
322
323 // searchColumnsMenuActivated() relies on one possible "all" representation
324 if(allColumnsAreSearchColumns && !d->searchColumns.isEmpty())
325 d->searchColumns.clear();
326 }
327
328 popup->exec( e->globalPos() );
329
330 delete popup;
331}
332
333void K3ListViewSearchLine::connectListView(K3ListView *lv)
334{
335 connect(lv, SIGNAL(destroyed(QObject*)),
336 this, SLOT(listViewDeleted(QObject*)));
337 connect(lv, SIGNAL(itemAdded(Q3ListViewItem*)),
338 this, SLOT(itemAdded(Q3ListViewItem*)));
339}
340
341void K3ListViewSearchLine::disconnectListView(K3ListView *lv)
342{
343 disconnect(lv, SIGNAL(destroyed(QObject*)),
344 this, SLOT(listViewDeleted(QObject*)));
345 disconnect(lv, SIGNAL(itemAdded(Q3ListViewItem*)),
346 this, SLOT(itemAdded(Q3ListViewItem*)));
347}
348
349bool K3ListViewSearchLine::canChooseColumnsCheck()
350{
351 // This is true if either of the following is true:
352
353 // there are no listviews connected
354 if (d->listViews.isEmpty())
355 return false;
356
357 const K3ListView *first = d->listViews.first();
358
359 const unsigned int numcols = first->columns();
360 // the listviews have only one column,
361 if (numcols < 2)
362 return false;
363
364 QStringList headers;
365 for (unsigned int i = 0; i < numcols; ++i)
366 headers.append(first->columnText(i));
367
368 QList<K3ListView *>::ConstIterator it = d->listViews.constBegin();
369 for (++it /* skip the first one */; it !=d->listViews.constEnd(); ++it) {
370 // the listviews have different numbers of columns,
371 if ((unsigned int) (*it)->columns() != numcols)
372 return false;
373
374 // the listviews differ in column labels.
375 QStringList::ConstIterator jt;
376 unsigned int i;
377 for (i = 0, jt = headers.constBegin(); i < numcols; ++i, ++jt) {
378 Q_ASSERT(jt != headers.constEnd());
379 if ((*it)->columnText(i) != *jt)
380 return false;
381 }
382 }
383
384 return true;
385}
386
388// protected slots
390
391void K3ListViewSearchLine::queueSearch(const QString &search)
392{
393 d->queuedSearches++;
394 d->search = search;
395 QTimer::singleShot(200, this, SLOT(activateSearch()));
396}
397
398void K3ListViewSearchLine::activateSearch()
399{
400 --(d->queuedSearches);
401
402 if(d->queuedSearches == 0)
403 updateSearch(d->search);
404}
405
407// private slots
409
410void K3ListViewSearchLine::itemAdded(Q3ListViewItem *item) const
411{
412 item->setVisible(itemMatches(item, text()));
413}
414
415void K3ListViewSearchLine::listViewDeleted(QObject *o)
416{
417 d->listViews.removeAll(static_cast<K3ListView *>(o));
418 setEnabled(d->listViews.isEmpty());
419}
420
421void K3ListViewSearchLine::searchColumnsMenuActivated(QAction *action)
422{
423 int id = action->data().toInt();
424
425 if(action == d->allVisibleColumnsAction) {
426 if(d->searchColumns.isEmpty())
427 d->searchColumns.append(0);
428 else
429 d->searchColumns.clear();
430 }
431 else {
432 if(d->searchColumns.indexOf(id) != -1)
433 d->searchColumns.removeAll(id);
434 else {
435 if(d->searchColumns.isEmpty()) {
436 for(int i = 0; i < d->listViews.first()->columns(); i++) {
437 if(i != id)
438 d->searchColumns.append(i);
439 }
440 }
441 else
442 d->searchColumns.append(id);
443 }
444 }
445 updateSearch();
446}
447
449// private methods
451
452void K3ListViewSearchLine::checkColumns()
453{
454 d->canChooseColumns = canChooseColumnsCheck();
455}
456
457void K3ListViewSearchLine::checkItemParentsNotVisible(K3ListView *listView)
458{
459 Q3ListViewItemIterator it(listView);
460 for(; it.current(); ++it)
461 {
462 Q3ListViewItem *item = it.current();
463 if(itemMatches(item, d->search))
464 item->setVisible(true);
465 else
466 item->setVisible(false);
467 }
468}
469
470#include <kvbox.h>
471
481bool K3ListViewSearchLine::checkItemParentsVisible(Q3ListViewItem *item, Q3ListViewItem *highestHiddenParent)
482{
483 bool visible = false;
484 Q3ListViewItem * first = item;
485 for(; item; item = item->nextSibling())
486 {
487 //What we pass to our children as highestHiddenParent:
488 Q3ListViewItem * hhp = highestHiddenParent ? highestHiddenParent : item->isVisible() ? 0L : item;
489 bool childMatch = false;
490 if(item->firstChild() && checkItemParentsVisible(item->firstChild(), hhp))
491 childMatch = true;
492 // Should this item be shown? It should if any children should be, or if it matches.
493 if(childMatch || itemMatches(item, d->search))
494 {
495 visible = true;
496 if (highestHiddenParent)
497 {
498 highestHiddenParent->setVisible(true);
499 // Calling setVisible on our ancestor will unhide all its descendents. Hide the ones
500 // before us that should not be shown.
501 for(Q3ListViewItem *hide = first; hide != item; hide = hide->nextSibling())
502 hide->setVisible(false);
503 highestHiddenParent = 0;
504 // If we matched, than none of our children matched, yet the setVisible() call on our
505 // ancestor unhid them, undo the damage:
506 if(!childMatch)
507 for(Q3ListViewItem *hide = item->firstChild(); hide; hide = hide->nextSibling())
508 hide->setVisible(false);
509 }
510 else
511 item->setVisible(true);
512 }
513 else
514 item->setVisible(false);
515 }
516 return visible;
517}
518
520// K3ListViewSearchLineWidget
522
523class K3ListViewSearchLineWidget::K3ListViewSearchLineWidgetPrivate
524{
525public:
526 K3ListViewSearchLineWidgetPrivate() : listView(0), searchLine(0) {}
527 K3ListView *listView;
528 K3ListViewSearchLine *searchLine;
529};
530
531K3ListViewSearchLineWidget::K3ListViewSearchLineWidget(K3ListView *listView,
532 QWidget *parent) :
533 KHBox(parent)
534{
535 d = new K3ListViewSearchLineWidgetPrivate;
536 d->listView = listView;
537
538 setSpacing(5);
539
540 QTimer::singleShot(0, this, SLOT(createWidgets()));
541}
542
543K3ListViewSearchLineWidget::~K3ListViewSearchLineWidget()
544{
545 delete d;
546}
547
548K3ListViewSearchLine *K3ListViewSearchLineWidget::createSearchLine(K3ListView *listView)
549{
550 if(!d->searchLine)
551 d->searchLine = new K3ListViewSearchLine(this, listView);
552 return d->searchLine;
553}
554
555void K3ListViewSearchLineWidget::createWidgets()
556{
557 QLabel *label = new QLabel(i18n("S&earch:"), this);
558 label->setObjectName(QLatin1String("kde toolbar widget"));
559
560 d->searchLine = createSearchLine(d->listView);
561 d->searchLine->show();
562
563 label->setBuddy(d->searchLine);
564 label->show();
565}
566
567K3ListViewSearchLine *K3ListViewSearchLineWidget::searchLine() const
568{
569 return d->searchLine;
570}
571
572#include "k3listviewsearchline.moc"
K3ListViewSearchLineWidget::searchLine
K3ListViewSearchLine * searchLine() const
Returns a pointer to the search line.
Definition: k3listviewsearchline.cpp:567
K3ListViewSearchLineWidget::~K3ListViewSearchLineWidget
~K3ListViewSearchLineWidget()
Destroys the K3ListViewSearchLineWidget.
Definition: k3listviewsearchline.cpp:543
K3ListViewSearchLineWidget::createWidgets
virtual void createWidgets()
Creates the widgets inside of the widget.
Definition: k3listviewsearchline.cpp:555
K3ListViewSearchLineWidget::K3ListViewSearchLineWidget
K3ListViewSearchLineWidget(K3ListView *listView=0, QWidget *parent=0)
Creates a K3ListViewSearchLineWidget for listView with parent as the parent with and name.
Definition: k3listviewsearchline.cpp:531
K3ListViewSearchLineWidget::createSearchLine
virtual K3ListViewSearchLine * createSearchLine(K3ListView *listView)
Creates the search line.
Definition: k3listviewsearchline.cpp:548
K3ListViewSearchLine
This class makes it easy to add a search line for filtering the items in listviews based on a simple ...
Definition: k3listviewsearchline.h:39
K3ListViewSearchLine::updateSearch
virtual void updateSearch(const QString &s=QString())
Updates search to only make visible the items that match s.
Definition: k3listviewsearchline.cpp:161
K3ListViewSearchLine::setListViews
void setListViews(const QList< K3ListView * > &lv)
Sets K3ListViews that are filtered by this search line, replacing any previously filtered listviews.
Definition: k3listviewsearchline.cpp:232
K3ListViewSearchLine::setSearchColumns
void setSearchColumns(const QList< int > &columns)
Sets the list of columns to be searched.
Definition: k3listviewsearchline.cpp:220
K3ListViewSearchLine::itemMatches
virtual bool itemMatches(const Q3ListViewItem *item, const QString &s) const
Returns true if item matches the search s.
Definition: k3listviewsearchline.cpp:252
K3ListViewSearchLine::activateSearch
void activateSearch()
When the timer started with queueSearch() expires this slot is called.
Definition: k3listviewsearchline.cpp:398
K3ListViewSearchLine::removeListView
void removeListView(K3ListView *lv)
Removes a K3ListView from the list of listviews filtered by this search line.
Definition: k3listviewsearchline.cpp:145
K3ListViewSearchLine::contextMenuEvent
virtual void contextMenuEvent(QContextMenuEvent *e)
Re-implemented for internal reasons.
Definition: k3listviewsearchline.cpp:281
K3ListViewSearchLine::K3ListViewSearchLine
K3ListViewSearchLine(QWidget *parent=0, K3ListView *listView=0)
Constructs a K3ListViewSearchLine with listView being the K3ListView to be filtered.
Definition: k3listviewsearchline.cpp:64
K3ListViewSearchLine::setListView
void setListView(K3ListView *lv)
Sets the K3ListView that is filtered by this search line, replacing any previously filtered listviews...
Definition: k3listviewsearchline.cpp:226
K3ListViewSearchLine::keepParentsVisible
bool keepParentsVisible() const
If this is true (the default) then the parents of matched items will also be shown.
Definition: k3listviewsearchline.cpp:110
K3ListViewSearchLine::searchColumns
QList< int > searchColumns() const
Returns the current list of columns that will be searched.
Definition: k3listviewsearchline.cpp:102
K3ListViewSearchLine::addListView
void addListView(K3ListView *lv)
Adds a K3ListView to the list of listviews filtered by this search line.
Definition: k3listviewsearchline.cpp:133
K3ListViewSearchLine::~K3ListViewSearchLine
virtual ~K3ListViewSearchLine()
Destroys the K3ListViewSearchLine.
Definition: k3listviewsearchline.cpp:92
K3ListViewSearchLine::canChooseColumnsCheck
virtual bool canChooseColumnsCheck()
Checks columns in all listviews and decides whether choosing columns to filter on makes any sense.
Definition: k3listviewsearchline.cpp:349
K3ListViewSearchLine::queueSearch
void queueSearch(const QString &search)
When keys are pressed a new search string is created and a timer is activated.
Definition: k3listviewsearchline.cpp:391
K3ListViewSearchLine::setCaseSensitive
void setCaseSensitive(bool cs)
Make the search case sensitive or case insensitive.
Definition: k3listviewsearchline.cpp:210
K3ListViewSearchLine::listViews
const QList< K3ListView * > & listViews() const
Returns the list of pointers to listviews that are currently filtered by the search.
Definition: k3listviewsearchline.cpp:123
K3ListViewSearchLine::setKeepParentsVisible
void setKeepParentsVisible(bool v)
When a search is active on a list that's organized into a tree view if a parent or ancesestor of an i...
Definition: k3listviewsearchline.cpp:215
K3ListViewSearchLine::listView
K3ListView * listView() const
Returns the listview that is currently filtered by the search.
Definition: k3listviewsearchline.cpp:115
K3ListViewSearchLine::connectListView
virtual void connectListView(K3ListView *)
Connects signals of this listview to the appropriate slots of the search line.
Definition: k3listviewsearchline.cpp:333
K3ListViewSearchLine::caseSensitive
bool caseSensitive() const
Returns true if the search is case sensitive.
Definition: k3listviewsearchline.cpp:97
K3ListViewSearchLine::disconnectListView
virtual void disconnectListView(K3ListView *)
Disconnects signals of a listviews from the search line.
Definition: k3listviewsearchline.cpp:341
K3ListView
This Widget extends the functionality of Q3ListView to honor the system wide settings for Single Clic...
Definition: k3listview.h:58
K3ListView::Single
@ Single
Definition: k3listview.h:109
K3ListView::NoSelection
@ NoSelection
Definition: k3listview.h:112
KHBox
KHBox::setSpacing
void setSpacing(int space)
KLineEdit
KLineEdit::createStandardContextMenu
QMenu * createStandardContextMenu()
KLineEdit::setClearButtonShown
void setClearButtonShown(bool show)
Q3ListViewItem
QAction
QLabel
QList
QMenu
QObject
QWidget
header
const char header[]
k3listview.h
k3listviewsearchline.h
kdebug.h
kiconloader.h
klocale.h
i18n
QString i18n(const char *text)
i18nc
QString i18nc(const char *ctxt, const char *text)
ktoolbar.h
kvbox.h
label
QString label(StandardShortcut id)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDE3Support

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

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
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