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

KPIMTextedit Library

  • sources
  • kde-4.12
  • kdepimlibs
  • kpimtextedit
tableactionmenu.cpp
1 /*
2  Copyright (c) 2012 Montel Laurent <montel@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 
21 #include "tableactionmenu.h"
22 #include "textedit.h"
23 #include "inserttabledialog.h"
24 #include "tableformatdialog.h"
25 #include "tablecellformatdialog.h"
26 
27 #include <KActionCollection>
28 #include <KAction>
29 #include <KIcon>
30 #include <KLocalizedString>
31 
32 #include <QTextTable>
33 #include <QPointer>
34 #include <QDebug>
35 
36 namespace KPIMTextEdit {
37 
38 class TableActionMenuPrivate
39 {
40  public:
41  TableActionMenuPrivate( KActionCollection *ac, TextEdit *edit, TableActionMenu *qq )
42  : actionCollection( ac ), textEdit( edit ), q( qq )
43  {
44  }
45 
46  void _k_slotInsertRowBelow();
47  void _k_slotInsertRowAbove();
48  void _k_slotInsertColumnBefore();
49  void _k_slotInsertColumnAfter();
50 
51  void _k_slotInsertTable();
52 
53  void _k_slotRemoveRowBelow();
54  void _k_slotRemoveRowAbove();
55  void _k_slotRemoveColumnBefore();
56  void _k_slotRemoveColumnAfter();
57  void _k_slotRemoveCellContents();
58 
59  void _k_slotMergeCell();
60  void _k_slotMergeSelectedCells();
61  void _k_slotTableFormat();
62  void _k_slotTableCellFormat();
63  void _k_slotSplitCell();
64  void _k_updateActions( bool forceUpdate = false );
65 
66  KAction *actionInsertTable;
67 
68  KAction *actionInsertRowBelow;
69  KAction *actionInsertRowAbove;
70 
71  KAction *actionInsertColumnBefore;
72  KAction *actionInsertColumnAfter;
73 
74  KAction *actionRemoveRowBelow;
75  KAction *actionRemoveRowAbove;
76 
77  KAction *actionRemoveColumnBefore;
78  KAction *actionRemoveColumnAfter;
79 
80  KAction *actionMergeCell;
81  KAction *actionMergeSelectedCells;
82  KAction *actionSplitCell;
83 
84  KAction *actionTableFormat;
85  KAction *actionTableCellFormat;
86 
87  KAction *actionRemoveCellContents;
88 
89  KActionCollection *actionCollection;
90  TextEdit *textEdit;
91  TableActionMenu *q;
92 };
93 
94 void TableActionMenuPrivate::_k_slotRemoveCellContents()
95 {
96  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
97  QTextTable *table = textEdit->textCursor().currentTable();
98  const QTextTableCell cell = table->cellAt( textEdit->textCursor() );
99  if ( cell.isValid() ) {
100  const QTextCursor firstCursor = cell.firstCursorPosition();
101  const QTextCursor endCursor = cell.lastCursorPosition();
102  QTextCursor cursor = textEdit->textCursor();
103  cursor.beginEditBlock();
104  cursor.setPosition( firstCursor.position() );
105  cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor,
106  endCursor.position() - firstCursor.position() );
107  cursor.removeSelectedText();
108  cursor.endEditBlock();
109  }
110  }
111 }
112 
113 void TableActionMenuPrivate::_k_slotRemoveRowBelow()
114 {
115  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
116  QTextTable *table = textEdit->textCursor().currentTable();
117  if ( table ) {
118  const QTextTableCell cell = table->cellAt( textEdit->textCursor() );
119  if ( cell.row()<table->rows() - 1 ) {
120  table->removeRows( cell.row(), 1 );
121  }
122  }
123  }
124 }
125 
126 void TableActionMenuPrivate::_k_slotRemoveRowAbove()
127 {
128  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
129  QTextTable *table = textEdit->textCursor().currentTable();
130  if ( table ) {
131  const QTextTableCell cell = table->cellAt( textEdit->textCursor() );
132  if ( cell.row() >= 1 ) {
133  table->removeRows( cell.row() - 1, 1 );
134  }
135  }
136  }
137 }
138 
139 void TableActionMenuPrivate::_k_slotRemoveColumnBefore()
140 {
141  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
142  QTextTable *table = textEdit->textCursor().currentTable();
143  if ( table ) {
144  const QTextTableCell cell = table->cellAt( textEdit->textCursor() );
145  if ( cell.column() > 0 ) {
146  table->removeColumns( cell.column() - 1, 1 );
147  }
148  }
149  }
150 }
151 
152 void TableActionMenuPrivate::_k_slotRemoveColumnAfter()
153 {
154  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
155  QTextTable *table = textEdit->textCursor().currentTable();
156  if ( table ) {
157  const QTextTableCell cell = table->cellAt( textEdit->textCursor() );
158  if ( cell.column()<table->columns() - 1 ) {
159  table->removeColumns( cell.column(), 1 );
160  }
161  }
162  }
163 }
164 
165 void TableActionMenuPrivate::_k_slotInsertRowBelow()
166 {
167  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
168  QTextTable *table = textEdit->textCursor().currentTable();
169  if ( table ) {
170  const QTextTableCell cell = table->cellAt( textEdit->textCursor() );
171  if ( cell.row()<table->rows() ) {
172  table->insertRows( cell.row() + 1, 1 );
173  } else {
174  table->appendRows( 1 );
175  }
176  }
177  }
178 }
179 
180 void TableActionMenuPrivate::_k_slotInsertRowAbove()
181 {
182  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
183  QTextTable *table = textEdit->textCursor().currentTable();
184  if ( table ) {
185  const QTextTableCell cell = table->cellAt( textEdit->textCursor() );
186  table->insertRows( cell.row(), 1 );
187  }
188  }
189 }
190 
191 void TableActionMenuPrivate::_k_slotInsertColumnBefore()
192 {
193  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
194  QTextTable *table = textEdit->textCursor().currentTable();
195  if ( table ) {
196  const QTextTableCell cell = table->cellAt( textEdit->textCursor() );
197  table->insertColumns( cell.column(), 1 );
198  }
199  }
200 }
201 
202 void TableActionMenuPrivate::_k_slotInsertColumnAfter()
203 {
204  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
205  QTextTable *table = textEdit->textCursor().currentTable();
206  if ( table ) {
207  const QTextTableCell cell = table->cellAt( textEdit->textCursor() );
208  if ( cell.column()<table->columns() ) {
209  table->insertColumns( cell.column() + 1, 1 );
210  } else {
211  table->appendColumns( 1 );
212  }
213  }
214  }
215 }
216 
217 void TableActionMenuPrivate::_k_slotInsertTable()
218 {
219  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
220  QPointer<InsertTableDialog> dialog = new InsertTableDialog( textEdit );
221  if ( dialog->exec() ) {
222  QTextCursor cursor = textEdit->textCursor();
223  QTextTableFormat tableFormat;
224  tableFormat.setBorder( dialog->border() );
225  const int numberOfColumns( dialog->columns() );
226  QVector<QTextLength> contrains;
227  const QTextLength::Type type = dialog->typeOfLength();
228  const int length = dialog->length();
229 
230  const QTextLength textlength( type, length / numberOfColumns );
231  for ( int i = 0; i < numberOfColumns; ++i ) {
232  contrains.append( textlength );
233  }
234  tableFormat.setColumnWidthConstraints( contrains );
235  tableFormat.setAlignment(Qt::AlignLeft);
236  QTextTable *table = cursor.insertTable( dialog->rows(), numberOfColumns );
237  table->setFormat( tableFormat );
238  }
239  delete dialog;
240  }
241 }
242 
243 void TableActionMenuPrivate::_k_slotMergeCell()
244 {
245  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
246  QTextTable *table = textEdit->textCursor().currentTable();
247  if ( table ) {
248  const QTextTableCell cell = table->cellAt( textEdit->textCursor() );
249  table->mergeCells( cell.row(), cell.column(), 1, cell.columnSpan() + 1 );
250  }
251  }
252 }
253 
254 void TableActionMenuPrivate::_k_slotMergeSelectedCells()
255 {
256  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
257  QTextTable *table = textEdit->textCursor().currentTable();
258  if ( table ) {
259  table->mergeCells( textEdit->textCursor() );
260  }
261  }
262 }
263 
264 void TableActionMenuPrivate::_k_slotTableFormat()
265 {
266  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
267  QTextTable *table = textEdit->textCursor().currentTable();
268  if ( table ) {
269  QPointer<TableFormatDialog> dialog = new TableFormatDialog( textEdit );
270  const int numberOfColumn( table->columns() );
271  const int numberOfRow( table->rows() );
272  dialog->setColumns( numberOfColumn );
273  dialog->setRows( numberOfRow );
274  QTextTableFormat tableFormat = table->format();
275  dialog->setBorder( tableFormat.border() );
276  dialog->setSpacing( tableFormat.cellSpacing() );
277  dialog->setPadding( tableFormat.cellPadding() );
278  dialog->setAlignment( tableFormat.alignment() );
279  if ( tableFormat.hasProperty( QTextFormat::BackgroundBrush ) ) {
280  dialog->setTableBackgroundColor( tableFormat.background().color() );
281  }
282  QVector<QTextLength> contrains = tableFormat.columnWidthConstraints();
283  if ( !contrains.isEmpty() ) {
284  dialog->setTypeOfLength( contrains.at( 0 ).type() );
285  dialog->setLength( contrains.at( 0 ).rawValue() * numberOfColumn );
286  }
287 
288  if ( dialog->exec() ) {
289  const int newNumberOfColumns( dialog->columns() );
290  if ( ( newNumberOfColumns != numberOfColumn ) ||
291  ( dialog->rows() != numberOfRow ) ) {
292  table->resize( dialog->rows(), newNumberOfColumns );
293  }
294  tableFormat.setBorder( dialog->border() );
295  tableFormat.setCellPadding( dialog->padding() );
296  tableFormat.setCellSpacing( dialog->spacing() );
297  tableFormat.setAlignment( dialog->alignment() );
298 
299  QVector<QTextLength> contrains;
300  const QTextLength::Type type = dialog->typeOfLength();
301  const int length = dialog->length();
302 
303  const QTextLength textlength( type, length / newNumberOfColumns );
304  for ( int i = 0; i < newNumberOfColumns; ++i ) {
305  contrains.append( textlength );
306  }
307  tableFormat.setColumnWidthConstraints( contrains );
308  const QColor tableBackgroundColor = dialog->tableBackgroundColor();
309  if ( dialog->useBackgroundColor() ) {
310  if ( tableBackgroundColor.isValid() ) {
311  tableFormat.setBackground( tableBackgroundColor );
312  }
313  } else {
314  tableFormat.clearBackground();
315  }
316  table->setFormat( tableFormat );
317  }
318  delete dialog;
319  }
320  }
321 }
322 
323 void TableActionMenuPrivate::_k_slotTableCellFormat()
324 {
325  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
326  QTextTable *table = textEdit->textCursor().currentTable();
327  if ( table ) {
328  QTextTableCell cell = table->cellAt( textEdit->textCursor() );
329  QPointer<TableCellFormatDialog> dialog = new TableCellFormatDialog( textEdit );
330  QTextTableCellFormat format = cell.format().toTableCellFormat();
331  if ( format.hasProperty( QTextFormat::BackgroundBrush ) ) {
332  dialog->setTableCellBackgroundColor( format.background().color() );
333  }
334  dialog->setVerticalAlignment( format.verticalAlignment() );
335  if ( dialog->exec() ) {
336  if ( dialog->useBackgroundColor() ) {
337  const QColor tableCellColor = dialog->tableCellBackgroundColor();
338  if ( tableCellColor.isValid() ) {
339  format.setBackground( tableCellColor );
340  }
341  } else {
342  format.clearBackground();
343  }
344  format.setVerticalAlignment( dialog->verticalAlignment() );
345  cell.setFormat( format );
346  }
347  delete dialog;
348  }
349  }
350 }
351 
352 void TableActionMenuPrivate::_k_slotSplitCell()
353 {
354  if ( textEdit->textMode() == KRichTextEdit::Rich ) {
355  QTextTable *table = textEdit->textCursor().currentTable();
356  if ( table ) {
357  const QTextTableCell cell = table->cellAt( textEdit->textCursor() );
358  if ( cell.columnSpan() > 1 || cell.rowSpan() > 1 ) {
359  table->splitCell( cell.row(), cell.column(),
360  qMax( 1, cell.rowSpan() - 1 ),
361  qMax( 1, cell.columnSpan() - 1 ) );
362  _k_updateActions();
363  }
364  }
365  }
366 }
367 
368 void TableActionMenuPrivate::_k_updateActions( bool forceUpdate )
369 {
370  if ( ( textEdit->textMode() == KRichTextEdit::Rich ) || forceUpdate ) {
371  QTextTable *table = textEdit->textCursor().currentTable();
372  const bool isTable = ( table != 0 );
373  actionInsertRowBelow->setEnabled( isTable );
374  actionInsertRowAbove->setEnabled( isTable );
375 
376  actionInsertColumnBefore->setEnabled( isTable );
377  actionInsertColumnAfter->setEnabled( isTable );
378 
379  actionRemoveRowBelow->setEnabled( isTable );
380  actionRemoveRowAbove->setEnabled( isTable );
381 
382  actionRemoveColumnBefore->setEnabled( isTable );
383  actionRemoveColumnAfter->setEnabled( isTable );
384 
385  if ( table ) {
386  const QTextTableCell cell = table->cellAt( textEdit->textCursor() );
387 
388  int firstRow = -1;
389  int numRows = -1;
390  int firstColumn = -1;
391  int numColumns = -1;
392  textEdit->textCursor().selectedTableCells ( &firstRow, &numRows, &firstColumn, &numColumns );
393  const bool hasSelectedTableCell =
394  ( firstRow != -1 ) && ( numRows != -1 ) &&
395  ( firstColumn != -1 ) && ( numColumns != -1 );
396  if ( cell.column()>table->columns() - 2 ) {
397  actionMergeCell->setEnabled( false );
398  } else {
399  actionMergeCell->setEnabled( true );
400  }
401  if ( cell.columnSpan() > 1 || cell.rowSpan() > 1 ) {
402  actionSplitCell->setEnabled( true );
403  } else {
404  actionSplitCell->setEnabled( false );
405  }
406  actionTableCellFormat->setEnabled( true );
407  actionMergeSelectedCells->setEnabled( hasSelectedTableCell );
408  } else {
409  actionSplitCell->setEnabled( false );
410  actionMergeCell->setEnabled( false );
411  actionMergeSelectedCells->setEnabled( false );
412  }
413  actionTableFormat->setEnabled( isTable );
414  actionTableCellFormat->setEnabled( isTable );
415  actionRemoveCellContents->setEnabled( isTable );
416  }
417 }
418 
419 TableActionMenu::TableActionMenu( KActionCollection *ac, TextEdit *textEdit )
420  : KActionMenu( textEdit ), d( new TableActionMenuPrivate( ac, textEdit, this ) )
421 {
422  KActionMenu *insertMenu = new KActionMenu( i18n( "Insert" ), this );
423  addAction( insertMenu );
424 
425  d->actionInsertTable = new KAction( KIcon( QLatin1String( "insert-table" ) ), i18n( "Table..." ), this );
426  insertMenu->addAction( d->actionInsertTable );
427  ac->addAction( QLatin1String( "insert_new_table" ), d->actionInsertTable );
428  connect( d->actionInsertTable, SIGNAL(triggered(bool)),
429  SLOT(_k_slotInsertTable()) );
430 
431  insertMenu->addSeparator();
432  d->actionInsertRowBelow =
433  new KAction( KIcon( QLatin1String( "edit-table-insert-row-below" ) ),
434  i18n( "Row Below" ), this );
435  insertMenu->addAction( d->actionInsertRowBelow );
436  ac->addAction( QLatin1String( "insert_row_below" ), d->actionInsertRowBelow );
437  connect( d->actionInsertRowBelow, SIGNAL(triggered(bool)),
438  SLOT(_k_slotInsertRowBelow()) );
439 
440  d->actionInsertRowAbove =
441  new KAction( KIcon( QLatin1String( "edit-table-insert-row-above" ) ),
442  i18n( "Row Above" ), this );
443  insertMenu->addAction( d->actionInsertRowAbove );
444  ac->addAction( QLatin1String( "insert_row_above" ), d->actionInsertRowAbove );
445  connect( d->actionInsertRowAbove, SIGNAL(triggered(bool)),
446  SLOT(_k_slotInsertRowAbove()) );
447 
448  insertMenu->addSeparator();
449  d->actionInsertColumnBefore =
450  new KAction( KIcon( QLatin1String( "edit-table-insert-column-left" ) ),
451  i18n( "Column Before" ), this );
452  insertMenu->addAction( d->actionInsertColumnBefore );
453  ac->addAction( QLatin1String( "insert_column_before" ), d->actionInsertColumnBefore );
454 
455  connect( d->actionInsertColumnBefore, SIGNAL(triggered(bool)),
456  SLOT(_k_slotInsertColumnBefore()) );
457 
458  d->actionInsertColumnAfter =
459  new KAction( KIcon( QLatin1String( "edit-table-insert-column-right" ) ),
460  i18n( "Column After" ), this );
461  insertMenu->addAction( d->actionInsertColumnAfter );
462  ac->addAction( QLatin1String( "insert_column_after" ), d->actionInsertColumnAfter );
463  connect( d->actionInsertColumnAfter, SIGNAL(triggered(bool)),
464  SLOT(_k_slotInsertColumnAfter()) );
465 
466  KActionMenu *removeMenu = new KActionMenu( i18n( "Delete" ), this );
467  addAction( removeMenu );
468 
469  d->actionRemoveRowBelow = new KAction( i18n( "Row Below" ), this );
470  removeMenu->addAction( d->actionRemoveRowBelow );
471  ac->addAction( QLatin1String( "remove_row_below" ), d->actionRemoveRowBelow );
472  connect( d->actionRemoveRowBelow, SIGNAL(triggered(bool)),
473  SLOT(_k_slotRemoveRowBelow()) );
474 
475  d->actionRemoveRowAbove = new KAction( i18n( "Row Above" ), this );
476  removeMenu->addAction( d->actionRemoveRowAbove );
477  ac->addAction( QLatin1String( "remove_row_above" ), d->actionRemoveRowAbove );
478  connect( d->actionRemoveRowAbove, SIGNAL(triggered(bool)),
479  SLOT(_k_slotRemoveRowAbove()) );
480 
481  removeMenu->addSeparator();
482  d->actionRemoveColumnBefore = new KAction( i18n( "Column Before" ), this );
483  removeMenu->addAction( d->actionRemoveColumnBefore );
484  ac->addAction( QLatin1String( "remove_column_before" ), d->actionRemoveColumnBefore );
485 
486  connect( d->actionRemoveColumnBefore, SIGNAL(triggered(bool)),
487  SLOT(_k_slotRemoveColumnBefore()) );
488 
489  d->actionRemoveColumnAfter = new KAction( i18n( "Column After" ), this );
490  removeMenu->addAction( d->actionRemoveColumnAfter );
491  ac->addAction( QLatin1String( "remove_column_after" ), d->actionRemoveColumnAfter );
492  connect( d->actionRemoveColumnAfter, SIGNAL(triggered(bool)),
493  SLOT(_k_slotRemoveColumnAfter()) );
494 
495  removeMenu->addSeparator();
496  d->actionRemoveCellContents = new KAction( i18n( "Cell Contents" ), this );
497  removeMenu->addAction( d->actionRemoveCellContents );
498  ac->addAction( QLatin1String( "remove_cell_contents" ), d->actionRemoveCellContents );
499  connect( d->actionRemoveCellContents, SIGNAL(triggered(bool)),
500  SLOT(_k_slotRemoveCellContents()) );
501 
502  addSeparator();
503 
504  d->actionMergeCell =
505  new KAction( KIcon( QLatin1String( "edit-table-cell-merge" ) ),
506  i18n( "Join With Cell to the Right" ), this );
507  ac->addAction( QLatin1String( "join_cell_to_the_right" ), d->actionMergeCell );
508  connect( d->actionMergeCell, SIGNAL(triggered(bool)),
509  SLOT(_k_slotMergeCell()) );
510  addAction( d->actionMergeCell );
511 
512  d->actionMergeSelectedCells = new KAction( i18n( "Join Selected Cells" ), this );
513  ac->addAction( QLatin1String( "join_cell_selected_cells" ), d->actionMergeSelectedCells );
514  connect( d->actionMergeSelectedCells, SIGNAL(triggered(bool)),
515  SLOT(_k_slotMergeSelectedCells()) );
516  addAction( d->actionMergeSelectedCells );
517 
518  d->actionSplitCell =
519  new KAction( KIcon( QLatin1String( "edit-table-cell-split" ) ),
520  i18n( "Split cells" ), this );
521  ac->addAction( QLatin1String( "split_cells" ), d->actionSplitCell );
522  connect( d->actionSplitCell, SIGNAL(triggered(bool)),
523  SLOT(_k_slotSplitCell()) );
524  addAction( d->actionSplitCell );
525 
526  addSeparator();
527 
528  d->actionTableFormat = new KAction( i18n( "Table Format..." ), this );
529  ac->addAction( QLatin1String( "table_format" ), d->actionTableFormat );
530  connect( d->actionTableFormat, SIGNAL(triggered(bool)),
531  SLOT(_k_slotTableFormat()) );
532  addAction( d->actionTableFormat );
533 
534  d->actionTableCellFormat = new KAction( i18n( "Table Cell Format..." ), this );
535  ac->addAction( QLatin1String( "table_cell_format" ), d->actionTableCellFormat );
536  connect( d->actionTableCellFormat, SIGNAL(triggered(bool)),
537  SLOT(_k_slotTableCellFormat()) );
538  addAction( d->actionTableCellFormat );
539 
540  connect( textEdit, SIGNAL(cursorPositionChanged()),
541  this, SLOT(_k_updateActions()) );
542  d->_k_updateActions( true );
543 }
544 
545 TableActionMenu::~TableActionMenu()
546 {
547  delete d;
548 }
549 
550 }
551 
552 #include "moc_tableactionmenu.cpp"
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 23:00:16 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KPIMTextedit Library

Skip menu "KPIMTextedit Library"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Members
  • File List
  • Related Pages

kdepimlibs API Reference

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kldap
  • kmbox
  • kmime
  • kpimidentities
  • kpimtextedit
  • kresources
  • ktnef
  • kxmlrpcclient
  • microblog

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