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

messagelist

  • sources
  • kde-4.12
  • kdepim
  • messagelist
  • utils
configurethemesdialog.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * Copyright 2008 Szymon Tomasz Stefanek <pragma@kvirc.net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  *******************************************************************************/
20 
21 #include "utils/configurethemesdialog.h"
22 #include "utils/configurethemesdialog_p.h"
23 
24 #include "utils/themeeditor.h"
25 #include "core/theme.h"
26 
27 #include "core/manager.h"
28 
29 #include <QGridLayout>
30 #include <QPushButton>
31 #include <QFrame>
32 #include <QHash>
33 
34 #include <KLocale>
35 #include <KIconLoader>
36 #include <KMessageBox>
37 #include <KFileDialog>
38 #include <KConfigGroup>
39 
40 namespace MessageList
41 {
42 
43 namespace Utils
44 {
45 
46 class ThemeListWidgetItem : public QListWidgetItem
47 {
48 public:
49  ThemeListWidgetItem( QListWidget * par, const Core::Theme &set )
50  : QListWidgetItem( set.name(), par )
51  {
52  mTheme = new Core::Theme( set );
53  }
54  ~ThemeListWidgetItem()
55  {
56  delete mTheme;
57  }
58 
59  Core::Theme * theme() const
60  {
61  return mTheme;
62  }
63  void forgetTheme()
64  {
65  mTheme = 0;
66  }
67 private:
68  Core::Theme * mTheme;
69 };
70 
71 class ThemeListWidget : public QListWidget
72 {
73 public:
74  ThemeListWidget( QWidget * parent )
75  : QListWidget( parent )
76  {}
77 public:
78  // need a larger but shorter QListWidget
79  QSize sizeHint() const
80  { return QSize( 450, 128 ); }
81 };
82 
83 } // namespace Utils
84 
85 } // namespace MessageList
86 
87 using namespace MessageList::Core;
88 using namespace MessageList::Utils;
89 
90 ConfigureThemesDialog::ConfigureThemesDialog( QWidget *parent )
91  : KDialog( parent ), d( new Private( this ) )
92 {
93  setAttribute( Qt::WA_DeleteOnClose );
94  setWindowModality( Qt::ApplicationModal ); // FIXME: Sure ?
95  setButtons( Ok | Cancel );
96  setWindowTitle( i18n( "Customize Themes" ) );
97 
98  QWidget * base = new QWidget( this );
99  setMainWidget( base );
100 
101  QGridLayout * g = new QGridLayout( base );
102  g->setContentsMargins( 0, 0, 0, 0 );
103 
104  d->mThemeList = new ThemeListWidget( base );
105  d->mThemeList->setSelectionMode(QAbstractItemView::ExtendedSelection);
106  d->mThemeList->setSortingEnabled( true );
107  g->addWidget( d->mThemeList, 0, 0, 7, 1 );
108 
109  connect( d->mThemeList, SIGNAL(itemClicked(QListWidgetItem*)),
110  SLOT(themeListItemClicked(QListWidgetItem*)) );
111 
112  d->mNewThemeButton = new QPushButton( i18n( "New Theme" ), base );
113  d->mNewThemeButton->setIcon( KIcon( QLatin1String( "document-new" ) ) );
114  d->mNewThemeButton->setIconSize( QSize( KIconLoader::SizeSmall, KIconLoader::SizeSmall ) );
115  g->addWidget( d->mNewThemeButton, 0, 1 );
116 
117  connect( d->mNewThemeButton, SIGNAL(clicked()),
118  SLOT(newThemeButtonClicked()) );
119 
120  d->mCloneThemeButton = new QPushButton( i18n( "Clone Theme" ), base );
121  d->mCloneThemeButton->setIcon( KIcon( QLatin1String( "edit-copy" ) ) );
122  d->mCloneThemeButton->setIconSize( QSize( KIconLoader::SizeSmall, KIconLoader::SizeSmall ) );
123  g->addWidget( d->mCloneThemeButton, 1, 1 );
124 
125  connect( d->mCloneThemeButton, SIGNAL(clicked()),
126  SLOT(cloneThemeButtonClicked()) );
127 
128  QFrame * f = new QFrame( base );
129  f->setFrameStyle( QFrame::Sunken | QFrame::HLine );
130  f->setMinimumHeight( 24 );
131  g->addWidget( f, 2, 1, Qt::AlignVCenter );
132 
133 
134  d->mExportThemeButton = new QPushButton( i18n( "Export Theme..." ), base );
135  g->addWidget( d->mExportThemeButton, 3, 1 );
136 
137  connect( d->mExportThemeButton, SIGNAL(clicked()),
138  SLOT(exportThemeButtonClicked()) );
139 
140  d->mImportThemeButton = new QPushButton( i18n( "Import Theme..." ), base );
141  g->addWidget( d->mImportThemeButton, 4, 1 );
142  connect( d->mImportThemeButton, SIGNAL(clicked()),
143  SLOT(importThemeButtonClicked()) );
144 
145  f = new QFrame( base );
146  f->setFrameStyle( QFrame::Sunken | QFrame::HLine );
147  f->setMinimumHeight( 24 );
148  g->addWidget( f, 5, 1, Qt::AlignVCenter );
149 
150 
151  d->mDeleteThemeButton = new QPushButton( i18n( "Delete Theme" ), base );
152  d->mDeleteThemeButton->setIcon( KIcon( QLatin1String( "edit-delete" ) ) );
153  d->mDeleteThemeButton->setIconSize( QSize( KIconLoader::SizeSmall, KIconLoader::SizeSmall ) );
154  g->addWidget( d->mDeleteThemeButton, 6, 1 );
155 
156  connect( d->mDeleteThemeButton, SIGNAL(clicked()),
157  SLOT(deleteThemeButtonClicked()) );
158 
159  d->mEditor = new ThemeEditor( base );
160  g->addWidget( d->mEditor, 8, 0, 1, 2 );
161 
162  connect( d->mEditor, SIGNAL(themeNameChanged()),
163  SLOT(editedThemeNameChanged()) );
164 
165  g->setColumnStretch( 0, 1 );
166  g->setRowStretch( 4, 1 );
167 
168  connect( this, SIGNAL(okClicked()),
169  SLOT(okButtonClicked()) );
170 
171  d->fillThemeList();
172 }
173 
174 ConfigureThemesDialog::~ConfigureThemesDialog()
175 {
176  delete d;
177 }
178 
179 void ConfigureThemesDialog::selectTheme( const QString &themeId )
180 {
181  ThemeListWidgetItem * item = d->findThemeItemById( themeId );
182  if ( item ) {
183  d->mThemeList->setCurrentItem( item );
184  d->themeListItemClicked(item);
185  }
186 }
187 
188 void ConfigureThemesDialog::Private::okButtonClicked()
189 {
190  commitEditor();
191 
192  Manager::instance()->removeAllThemes();
193 
194  const int c = mThemeList->count();
195  int i = 0;
196  while ( i < c )
197  {
198  ThemeListWidgetItem * item = dynamic_cast< ThemeListWidgetItem * >( mThemeList->item( i ) );
199  if ( item )
200  {
201  Manager::instance()->addTheme( item->theme() );
202  item->forgetTheme();
203  }
204  ++i;
205  }
206 
207  Manager::instance()->themesConfigurationCompleted();
208 
209  q->close(); // this will delete too
210 }
211 
212 void ConfigureThemesDialog::Private::commitEditor()
213 {
214  Theme * editedTheme = mEditor->editedTheme();
215  if ( !editedTheme )
216  return;
217 
218  mEditor->commit();
219 
220  ThemeListWidgetItem * editedItem = findThemeItemByTheme( editedTheme );
221  if ( !editedItem )
222  return;
223 
224  // We must reset the runtime column state as the columns might have
225  // totally changed in the editor
226  editedTheme->resetColumnState();
227 
228  QString goodName = uniqueNameForTheme( editedTheme->name(), editedTheme );
229  editedTheme->setName( goodName );
230  editedItem->setText( goodName );
231 }
232 
233 void ConfigureThemesDialog::Private::editedThemeNameChanged()
234 {
235  Theme * set = mEditor->editedTheme();
236  if ( !set )
237  return;
238 
239  ThemeListWidgetItem * it = findThemeItemByTheme( set );
240  if ( !it )
241  return;
242 
243  QString goodName = uniqueNameForTheme( set->name(), set );
244 
245  it->setText( goodName );
246 }
247 
248 void ConfigureThemesDialog::Private::fillThemeList()
249 {
250  const QHash< QString, Theme * >& sets = Manager::instance()->themes();
251 
252  QHash< QString, Theme * >::ConstIterator end( sets.constEnd() );
253  for( QHash< QString, Theme * >::ConstIterator it = sets.constBegin(); it != end; ++it )
254  (void)new ThemeListWidgetItem( mThemeList, *( *it ) );
255 }
256 
257 
258 void ConfigureThemesDialog::Private::themeListItemClicked(QListWidgetItem* cur)
259 {
260  commitEditor();
261 
262  const int numberOfSelectedItem(mThemeList->selectedItems().count());
263 
264  ThemeListWidgetItem * item = cur ? dynamic_cast< ThemeListWidgetItem * >( cur ) : 0;
265  mDeleteThemeButton->setEnabled( item && !item->theme()->readOnly() );
266  mCloneThemeButton->setEnabled( numberOfSelectedItem == 1 );
267  mEditor->editTheme( item ? item->theme() : 0 );
268  mExportThemeButton->setEnabled( numberOfSelectedItem > 0 );
269 
270  if ( item && !item->isSelected() )
271  item->setSelected( true ); // make sure it's true
272 }
273 
274 ThemeListWidgetItem * ConfigureThemesDialog::Private::findThemeItemById( const QString &themeId )
275 {
276  const int c = mThemeList->count();
277  int i = 0;
278  while ( i < c )
279  {
280  ThemeListWidgetItem * item = dynamic_cast< ThemeListWidgetItem * >( mThemeList->item( i ) );
281  if ( item )
282  {
283  if ( item->theme()->id() == themeId )
284  return item;
285  }
286  ++i;
287  }
288  return 0;
289 }
290 
291 
292 ThemeListWidgetItem * ConfigureThemesDialog::Private::findThemeItemByName( const QString &name, Theme * skipTheme )
293 {
294  const int c = mThemeList->count();
295  int i = 0;
296  while ( i < c )
297  {
298  ThemeListWidgetItem * item = dynamic_cast< ThemeListWidgetItem * >( mThemeList->item( i ) );
299  if ( item )
300  {
301  if ( item->theme() != skipTheme )
302  {
303  if ( item->theme()->name() == name )
304  return item;
305  }
306  }
307  ++i;
308  }
309  return 0;
310 }
311 
312 ThemeListWidgetItem * ConfigureThemesDialog::Private::findThemeItemByTheme( Theme * set )
313 {
314  const int c = mThemeList->count();
315  int i = 0;
316  while ( i < c )
317  {
318  ThemeListWidgetItem * item = dynamic_cast< ThemeListWidgetItem * >( mThemeList->item( i ) );
319  if ( item )
320  {
321  if ( item->theme() == set )
322  return item;
323  }
324  ++i;
325  }
326  return 0;
327 }
328 
329 
330 QString ConfigureThemesDialog::Private::uniqueNameForTheme( const QString& baseName, Theme * skipTheme )
331 {
332  QString ret = baseName;
333  if( ret.isEmpty() )
334  ret = i18n( "Unnamed Theme" );
335 
336  int idx = 1;
337 
338  ThemeListWidgetItem * item = findThemeItemByName( ret, skipTheme );
339  while ( item )
340  {
341  idx++;
342  ret = QString::fromLatin1( "%1 %2" ).arg( baseName ).arg( idx );
343  item = findThemeItemByName( ret, skipTheme );
344  }
345  return ret;
346 }
347 
348 void ConfigureThemesDialog::Private::newThemeButtonClicked()
349 {
350  const int numberOfSelectedItem(mThemeList->selectedItems().count());
351  Theme emptyTheme;
352  emptyTheme.setName( uniqueNameForTheme( i18n( "New Theme" ) ) );
353  Theme::Column * col = new Theme::Column();
354  col->setLabel( i18n( "New Column" ) );
355  col->setVisibleByDefault( true );
356  col->addMessageRow( new Theme::Row() );
357  col->addGroupHeaderRow( new Theme::Row() );
358  emptyTheme.addColumn( col );
359  ThemeListWidgetItem * item = new ThemeListWidgetItem( mThemeList, emptyTheme );
360 
361  mThemeList->setCurrentItem( item );
362  mEditor->editTheme( item->theme() );
363 
364  mDeleteThemeButton->setEnabled( !item->theme()->readOnly() );
365  mExportThemeButton->setEnabled( item );
366  mCloneThemeButton->setEnabled(numberOfSelectedItem == 1);
367 }
368 
369 void ConfigureThemesDialog::Private::cloneThemeButtonClicked()
370 {
371  ThemeListWidgetItem * item = dynamic_cast< ThemeListWidgetItem * >( mThemeList->currentItem() );
372  if ( !item )
373  return;
374  commitEditor();
375  item->setSelected(false);
376  Theme copyTheme( *( item->theme() ) );
377  copyTheme.setReadOnly( false );
378  copyTheme.detach(); // detach shared data
379  copyTheme.generateUniqueId(); // regenerate id so it becomes different
380  copyTheme.setName( uniqueNameForTheme( item->theme()->name() ) );
381  item = new ThemeListWidgetItem( mThemeList, copyTheme );
382 
383  mThemeList->setCurrentItem( item );
384  mEditor->editTheme( item->theme() );
385 
386  const int numberOfSelectedItem(mThemeList->selectedItems().count());
387  mDeleteThemeButton->setEnabled( !item->theme()->readOnly() );
388  mExportThemeButton->setEnabled( true );
389  mCloneThemeButton->setEnabled(numberOfSelectedItem == 1);
390 }
391 
392 void ConfigureThemesDialog::Private::deleteThemeButtonClicked()
393 {
394  QList<QListWidgetItem *> list = mThemeList->selectedItems();
395  if(list.isEmpty()) {
396  return;
397  }
398 
399  mEditor->editTheme( 0 ); // forget it
400  Q_FOREACH(QListWidgetItem * it, list) {
401  ThemeListWidgetItem * item = dynamic_cast< ThemeListWidgetItem * >( it );
402  if ( !item )
403  return;
404  if(!item->theme()->readOnly()) {
405  delete item;// this will trigger themeListCurrentItemChanged()
406  }
407  if ( mThemeList->count() < 2 )
408  break; // no way: desperately try to keep at least one option set alive :)
409  }
410 
411  ThemeListWidgetItem *newItem = dynamic_cast< ThemeListWidgetItem * >(mThemeList->currentItem());
412  mDeleteThemeButton->setEnabled( newItem && !newItem->theme()->readOnly() );
413  mExportThemeButton->setEnabled( newItem );
414  const int numberOfSelectedItem(mThemeList->selectedItems().count());
415  mCloneThemeButton->setEnabled(numberOfSelectedItem == 1);
416 }
417 
418 void ConfigureThemesDialog::Private::importThemeButtonClicked()
419 {
420  const QString filename = KFileDialog::getOpenFileName(QString(),QString::fromLatin1("*"),q,i18n("Import Theme"));
421  if(!filename.isEmpty()) {
422  KConfig config(filename);
423 
424  if(config.hasGroup(QLatin1String("MessageListView::Themes"))) {
425  KConfigGroup grp( &config, QLatin1String("MessageListView::Themes") );
426  const int cnt = grp.readEntry( "Count", 0 );
427  int idx = 0;
428  while ( idx < cnt ) {
429  const QString data = grp.readEntry( QString::fromLatin1( "Set%1" ).arg( idx ), QString() );
430  if ( !data.isEmpty() )
431  {
432  Theme * set = new Theme();
433  if ( set->loadFromString( data ) ) {
434  set->setReadOnly( false );
435  set->detach(); // detach shared data
436  set->generateUniqueId(); // regenerate id so it becomes different
437  set->setName( uniqueNameForTheme( set->name() ) );
438  (void)new ThemeListWidgetItem( mThemeList, *set );
439  } else {
440  delete set;
441  }
442  }
443  ++idx;
444  }
445  }
446  }
447 }
448 
449 void ConfigureThemesDialog::Private::exportThemeButtonClicked()
450 {
451  QList<QListWidgetItem *> list = mThemeList->selectedItems();
452  if(list.isEmpty()) {
453  return;
454  }
455  const QString filename = KFileDialog::getSaveFileName(QString(),QString::fromLatin1("*"),q,i18n("Export Theme"));
456  if(!filename.isEmpty()) {
457  KConfig config(filename);
458 
459  KConfigGroup grp( &config, QLatin1String("MessageListView::Themes") );
460  grp.writeEntry( "Count", list.count() );
461 
462  int idx = 0;
463  Q_FOREACH(QListWidgetItem *item, list) {
464  ThemeListWidgetItem * themeItem = static_cast< ThemeListWidgetItem * >( item );
465  grp.writeEntry( QString::fromLatin1( "Set%1" ).arg( idx ), themeItem->theme()->saveToString() );
466  ++idx;
467  }
468  }
469 }
470 
471 
472 #include "configurethemesdialog.moc"
MessageList::Utils::ConfigureThemesDialog::Private::newThemeButtonClicked
void newThemeButtonClicked()
Definition: configurethemesdialog.cpp:348
MessageList::Core::Theme::Column::addMessageRow
void addMessageRow(Row *row)
Appends a message row to this theme column.
Definition: theme.h:785
MessageList::Utils::ConfigureThemesDialog::~ConfigureThemesDialog
~ConfigureThemesDialog()
Definition: configurethemesdialog.cpp:174
QWidget
MessageList::Core::Theme::Row
The Row class defines a row of items inside a Column.
Definition: theme.h:466
MessageList::Utils::ConfigureThemesDialog::Private::uniqueNameForTheme
QString uniqueNameForTheme(const QString &baseName, Core::Theme *skipTheme=0)
Definition: configurethemesdialog.cpp:330
theme.h
KDialog
MessageList::Core::OptionSet::setReadOnly
void setReadOnly(bool b)
Definition: optionset.h:119
MessageList::Core::Theme::Column::setVisibleByDefault
void setVisibleByDefault(bool vbd)
Sets the "visible by default" tag for this column.
Definition: theme.h:718
MessageList::Core::Theme::Column
The Column class defines a view column available inside this theme.
Definition: theme.h:564
MessageList::Core::OptionSet::name
const QString & name() const
Returns the name of this OptionSet.
Definition: optionset.h:72
MessageList::Core::Theme::Column::setLabel
void setLabel(const QString &label)
Sets the label for this column.
Definition: theme.h:680
MessageList::Utils::ConfigureThemesDialog::Private
Definition: configurethemesdialog_p.h:43
configurethemesdialog.h
MessageList::Utils::ConfigureThemesDialog::Private::okButtonClicked
void okButtonClicked()
Definition: configurethemesdialog.cpp:188
MessageList::Utils::ConfigureThemesDialog::Private::mExportThemeButton
QPushButton * mExportThemeButton
Definition: configurethemesdialog_p.h:73
MessageList::Core::OptionSet::generateUniqueId
void generateUniqueId()
(Re)generates a (hopefully) unique identifier for this option set.
Definition: optionset.cpp:57
MessageList::Core::Theme::resetColumnState
void resetColumnState()
Resets the column state (visibility and width) to their default values (the "visible by default" ones...
Definition: theme.cpp:725
MessageList::Utils::ConfigureThemesDialog::Private::editedThemeNameChanged
void editedThemeNameChanged()
Definition: configurethemesdialog.cpp:233
MessageList::Core::OptionSet::loadFromString
bool loadFromString(const QString &data)
Attempts to unpack this configuration object from a string (that is likely to come out from a config ...
Definition: optionset.cpp:86
manager.h
MessageList::Utils::ConfigureThemesDialog::Private::mThemeList
ThemeListWidget * mThemeList
Definition: configurethemesdialog_p.h:68
MessageList::Utils::ConfigureThemesDialog::Private::commitEditor
void commitEditor()
Definition: configurethemesdialog.cpp:212
MessageList::Utils::ConfigureThemesDialog::Private::cloneThemeButtonClicked
void cloneThemeButtonClicked()
Definition: configurethemesdialog.cpp:369
MessageList::Utils::ConfigureThemesDialog::Private::mNewThemeButton
QPushButton * mNewThemeButton
Definition: configurethemesdialog_p.h:70
MessageList::Core::OptionSet::setName
void setName(const QString &name)
Sets the name of this OptionSet.
Definition: optionset.h:80
MessageList::Utils::ConfigureThemesDialog::Private::fillThemeList
void fillThemeList()
Definition: configurethemesdialog.cpp:248
MessageList::Utils::ConfigureThemesDialog::Private::findThemeItemByTheme
ThemeListWidgetItem * findThemeItemByTheme(Core::Theme *set)
Definition: configurethemesdialog.cpp:312
MessageList::Utils::ConfigureThemesDialog::Private::findThemeItemByName
ThemeListWidgetItem * findThemeItemByName(const QString &name, Core::Theme *skipTheme=0)
Definition: configurethemesdialog.cpp:292
MessageList::Utils::ConfigureThemesDialog::Private::importThemeButtonClicked
void importThemeButtonClicked()
Definition: configurethemesdialog.cpp:418
MessageList::Utils::ConfigureThemesDialog::Private::exportThemeButtonClicked
void exportThemeButtonClicked()
Definition: configurethemesdialog.cpp:449
MessageList::Utils::ConfigureThemesDialog::Private::mEditor
ThemeEditor * mEditor
Definition: configurethemesdialog_p.h:69
MessageList::Utils::ConfigureThemesDialog::Private::mCloneThemeButton
QPushButton * mCloneThemeButton
Definition: configurethemesdialog_p.h:71
configurethemesdialog_p.h
themeeditor.h
MessageList::Utils::ConfigureThemesDialog::Private::mDeleteThemeButton
QPushButton * mDeleteThemeButton
Definition: configurethemesdialog_p.h:72
MessageList::Utils::ConfigureThemesDialog::Private::deleteThemeButtonClicked
void deleteThemeButtonClicked()
Definition: configurethemesdialog.cpp:392
MessageList::Core::Theme::detach
void detach()
Detaches this object from the shared runtime data for columns.
Definition: theme.cpp:718
MessageList::Core::Theme
The Theme class defines the visual appearance of the MessageList.
Definition: theme.h:65
MessageList::Utils::ConfigureThemesDialog::Private::q
ConfigureThemesDialog *const q
Definition: configurethemesdialog_p.h:66
MessageList::Utils::ConfigureThemesDialog::selectTheme
void selectTheme(const QString &themeId)
Definition: configurethemesdialog.cpp:179
MessageList::Core::Theme::Column::addGroupHeaderRow
void addGroupHeaderRow(Row *row)
Appends a group header row to this theme.
Definition: theme.h:815
MessageList::Utils::ThemeEditor
Definition: themeeditor.h:202
MessageList::Utils::ConfigureThemesDialog::Private::findThemeItemById
ThemeListWidgetItem * findThemeItemById(const QString &themeId)
Definition: configurethemesdialog.cpp:274
MessageList::Utils::ConfigureThemesDialog::Private::themeListItemClicked
void themeListItemClicked(QListWidgetItem *)
Definition: configurethemesdialog.cpp:258
MessageList::Utils::ConfigureThemesDialog::Private::mImportThemeButton
QPushButton * mImportThemeButton
Definition: configurethemesdialog_p.h:74
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:55:32 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

messagelist

Skip menu "messagelist"
  • 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

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