• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kdeui
 

kdeui

kbugreport.cpp
00001 /* This file is part of the KDE project
00002    Copyright (C) 1999 David Faure <faure@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <tqhbuttongroup.h>
00021 #include <tqpushbutton.h>
00022 #include <tqlabel.h>
00023 #include <tqlayout.h>
00024 #include <tqmultilineedit.h>
00025 #include <tqradiobutton.h>
00026 #include <tqwhatsthis.h>
00027 #include <tqregexp.h>
00028 
00029 #include <kaboutdata.h>
00030 #include <kapplication.h>
00031 #include <kconfig.h>
00032 #include <kdebug.h>
00033 #include <klineedit.h>
00034 #include <klocale.h>
00035 #include <kmessagebox.h>
00036 #include <kprocess.h>
00037 #include <kstandarddirs.h>
00038 #include <kstdguiitem.h>
00039 #include <kurl.h>
00040 #include <kurllabel.h>
00041 
00042 #include "kbugreport.h"
00043 
00044 #include <stdio.h>
00045 #include <pwd.h>
00046 #include <unistd.h>
00047 
00048 #include <sys/utsname.h>
00049 
00050 #include "kdepackages.h"
00051 #include <kcombobox.h>
00052 #include <config.h>
00053 #include <ktempfile.h>
00054 #include <tqtextstream.h>
00055 #include <tqfile.h>
00056 
00057 class KBugReportPrivate {
00058 public:
00059     KComboBox *appcombo;
00060     TQString lastError;
00061     TQString kde_version;
00062     TQString appname;
00063     TQString os;
00064     TQPushButton *submitBugButton;
00065     KURL url;
00066 };
00067 
00068 KBugReport::KBugReport( TQWidget * parentw, bool modal, const KAboutData *aboutData )
00069   : KDialogBase( Plain,
00070                  i18n("Submit Bug Report"),
00071                  Ok | Cancel,
00072                  Ok,
00073                  parentw,
00074                  "KBugReport",
00075                  modal, // modal
00076                  true // separator
00077                  )
00078 {
00079   d = new KBugReportPrivate;
00080 
00081   // Use supplied aboutdata, otherwise the one from the active instance
00082   // otherwise the KGlobal one. _activeInstance should neved be 0L in theory.
00083   m_aboutData = aboutData
00084     ? aboutData
00085     : ( KGlobal::_activeInstance ? KGlobal::_activeInstance->aboutData()
00086                                  : KGlobal::instance()->aboutData() );
00087   m_process = 0;
00088   TQWidget * parent = plainPage();
00089   d->submitBugButton = 0;
00090 
00091   //if ( m_aboutData->bugAddress() == TQString::fromLatin1("submit@bugs.trinitydesktop.org") )
00092   //{
00093   //  // This is a core KDE application -> redirect to the web form
00094     // Always redirect to the Web form for Trinity
00095     d->submitBugButton = new TQPushButton( parent );
00096     setButtonCancel( KStdGuiItem::close() );
00097   //}
00098 
00099   TQLabel * tmpLabel;
00100   TQVBoxLayout * lay = new TQVBoxLayout( parent, 0, spacingHint() );
00101 
00102   TQGridLayout *glay = new TQGridLayout( lay, 4, 3 );
00103   glay->setColStretch( 1, 10 );
00104   glay->setColStretch( 2, 10 );
00105 
00106   int row = 0;
00107 
00108   if ( !d->submitBugButton )
00109   {
00110     // From
00111     TQString qwtstr = i18n( "Your email address. If incorrect, use the Configure Email button to change it" );
00112     tmpLabel = new TQLabel( i18n("From:"), parent );
00113     glay->addWidget( tmpLabel, row,0 );
00114     TQWhatsThis::add( tmpLabel, qwtstr );
00115     m_from = new TQLabel( parent );
00116     glay->addWidget( m_from, row, 1 );
00117     TQWhatsThis::add( m_from, qwtstr );
00118 
00119 
00120     // Configure email button
00121     m_configureEmail = new TQPushButton( i18n("Configure Email..."),
00122                                         parent );
00123     connect( m_configureEmail, TQT_SIGNAL( clicked() ), this,
00124              TQT_SLOT( slotConfigureEmail() ) );
00125     glay->addMultiCellWidget( m_configureEmail, 0, 2, 2, 2, (TQ_Alignment)(AlignTop|AlignRight) );
00126 
00127     // To
00128     qwtstr = i18n( "The email address this bug report is sent to." );
00129     tmpLabel = new TQLabel( i18n("To:"), parent );
00130     glay->addWidget( tmpLabel, ++row,0 );
00131     TQWhatsThis::add( tmpLabel, qwtstr );
00132     tmpLabel = new TQLabel( m_aboutData->bugAddress(), parent );
00133     glay->addWidget( tmpLabel, row, 1 );
00134     TQWhatsThis::add( tmpLabel, qwtstr );
00135 
00136     setButtonOK( KGuiItem( i18n("&Send"), "mail_send", i18n( "Send bug report." ),
00137                     i18n( "Send this bug report to %1." ).arg( m_aboutData->bugAddress() ) ) );
00138 
00139   }
00140   else
00141   {
00142     m_configureEmail = 0;
00143     m_from = 0;
00144     showButtonOK( false );
00145   }
00146 
00147   // Program name
00148   TQString qwtstr = i18n( "The application for which you wish to submit a bug report - if incorrect, please use the Report Bug menu item of the correct application" );
00149   tmpLabel = new TQLabel( i18n("Application: "), parent );
00150   glay->addWidget( tmpLabel, ++row, 0 );
00151   TQWhatsThis::add( tmpLabel, qwtstr );
00152   d->appcombo = new KComboBox( false, parent, "app");
00153   TQWhatsThis::add( d->appcombo, qwtstr );
00154   d->appcombo->insertStrList((const char**)packages);
00155   connect(d->appcombo, TQT_SIGNAL(activated(int)), TQT_SLOT(appChanged(int)));
00156   d->appname = TQString::fromLatin1( m_aboutData
00157                                     ? m_aboutData->productName()
00158                                     : tqApp->name() );
00159   glay->addWidget( d->appcombo, row, 1 );
00160   int index = 0;
00161   for (; index < d->appcombo->count(); index++) {
00162       if (d->appcombo->text(index) == d->appname) {
00163           break;
00164       }
00165   }
00166   if (index == d->appcombo->count()) { // not present
00167       d->appcombo->insertItem(d->appname);
00168   }
00169   d->appcombo->setCurrentItem(index);
00170 
00171   TQWhatsThis::add( tmpLabel, qwtstr );
00172 
00173   // Version
00174   qwtstr = i18n( "The version of this application - please make sure that no newer version is available before sending a bug report" );
00175   tmpLabel = new TQLabel( i18n("Version:"), parent );
00176   glay->addWidget( tmpLabel, ++row, 0 );
00177   TQWhatsThis::add( tmpLabel, qwtstr );
00178   if (m_aboutData)
00179       m_strVersion = m_aboutData->version();
00180   else
00181       m_strVersion = i18n("no version set (programmer error!)");
00182   d->kde_version = TQString::fromLatin1( KDE_VERSION_STRING );
00183   d->kde_version += ", " + TQString::fromLatin1( KDE_DISTRIBUTION_TEXT );
00184   if ( !d->submitBugButton )
00185       m_strVersion += " " + d->kde_version;
00186   m_version = new TQLabel( m_strVersion, parent );
00187   //glay->addWidget( m_version, row, 1 );
00188   glay->addMultiCellWidget( m_version, row, row, 1, 2 );
00189   TQWhatsThis::add( m_version, qwtstr );
00190 
00191   tmpLabel = new TQLabel(i18n("OS:"), parent);
00192   glay->addWidget( tmpLabel, ++row, 0 );
00193 
00194   struct utsname unameBuf;
00195   uname( &unameBuf );
00196   d->os = TQString::fromLatin1( unameBuf.sysname ) +
00197           " (" + TQString::fromLatin1( unameBuf.machine ) + ") "
00198           "release " + TQString::fromLatin1( unameBuf.release );
00199 
00200   tmpLabel = new TQLabel(d->os, parent);
00201   glay->addMultiCellWidget( tmpLabel, row, row, 1, 2 );
00202 
00203   tmpLabel = new TQLabel(i18n("Compiler:"), parent);
00204   glay->addWidget( tmpLabel, ++row, 0 );
00205   tmpLabel = new TQLabel(TQString::fromLatin1(KDE_COMPILER_VERSION), parent);
00206   glay->addMultiCellWidget( tmpLabel, row, row, 1, 2 );
00207 
00208   if ( !d->submitBugButton )
00209   {
00210     // Severity
00211     m_bgSeverity = new TQHButtonGroup( i18n("Se&verity"), parent );
00212     static const char * const sevNames[5] = { "critical", "grave", "normal", "wishlist", "i18n" };
00213     const TQString sevTexts[5] = { i18n("Critical"), i18n("Grave"), i18n("normal severity","Normal"), i18n("Wishlist"), i18n("Translation") };
00214 
00215     for (int i = 0 ; i < 5 ; i++ )
00216     {
00217       // Store the severity string as the name
00218       TQRadioButton *rb = new TQRadioButton( sevTexts[i], m_bgSeverity, sevNames[i] );
00219       if (i==2) rb->setChecked(true); // default : "normal"
00220     }
00221 
00222     lay->addWidget( m_bgSeverity );
00223 
00224     // Subject
00225     TQHBoxLayout * hlay = new TQHBoxLayout( lay );
00226     tmpLabel = new TQLabel( i18n("S&ubject: "), parent );
00227     hlay->addWidget( tmpLabel );
00228     m_subject = new KLineEdit( parent );
00229     m_subject->setFocus();
00230     tmpLabel->setBuddy(m_subject);
00231     hlay->addWidget( m_subject );
00232 
00233     TQString text = i18n("Enter the text (in English if possible) that you wish to submit for the "
00234                         "bug report.\n"
00235                         "If you press \"Send\", a mail message will be sent to the maintainer of "
00236                         "this program.\n");
00237     TQLabel * label = new TQLabel( parent, "label" );
00238 
00239     label->setText( text );
00240     lay->addWidget( label );
00241 
00242     // The multiline-edit
00243     m_lineedit = new TQMultiLineEdit( parent, TQMULTILINEEDIT_OBJECT_NAME_STRING );
00244     m_lineedit->setMinimumHeight( 180 ); // make it big
00245     m_lineedit->setWordWrap(TQMultiLineEdit::WidgetWidth);
00246     lay->addWidget( m_lineedit, 10 /*stretch*/ );
00247 
00248     slotSetFrom();
00249   } else {
00250     // Point to the web form
00251 
00252     lay->addSpacing(10);
00253     TQString text = i18n("Reporting bugs and requesting enhancements are maintained using the Bugzilla reporting system.\n"
00254                         "You'll need a login account and password to use the reporting system.\n"
00255                         "To control spam and rogue elements the login requires a valid email address.\n"
00256                         "Consider using any large email service if you want to avoid using your private email address.\n"
00257                         "\n"
00258                         "Selecting the button below opens your web browser to http://bugs.trinitydesktop.org,\n"
00259                         "where you will find the report form.\n"
00260                         "The information displayed above will be transferred to the reporting system.\n"
00261                         "Session cookies must be enabled to use the reporting system.\n"
00262                         "\n"
00263                         "Thank you for helping!");
00264     TQLabel * label = new TQLabel( text, parent, "label");
00265     lay->addWidget( label );
00266     lay->addSpacing(10);
00267 
00268     updateURL();
00269     d->submitBugButton->setText( i18n("&Launch Bug Report Wizard") );
00270     d->submitBugButton->setSizePolicy(TQSizePolicy::Fixed,TQSizePolicy::Fixed);
00271     lay->addWidget( d->submitBugButton );
00272     lay->addSpacing(10);
00273 
00274     connect( d->submitBugButton, TQT_SIGNAL(clicked()),
00275              this, TQT_SLOT(slotOk()));
00276   }
00277 }
00278 
00279 KBugReport::~KBugReport()
00280 {
00281     delete d;
00282 }
00283 
00284 void KBugReport::updateURL()
00285 {
00286     KURL url ( "http://bugs.trinitydesktop.org/enter_bug.cgi" );
00287     url.addQueryItem( "product", "TDE" );
00288     url.addQueryItem( "op_sys", d->os );
00289     url.addQueryItem( "cf_kde_compiler", KDE_COMPILER_VERSION );
00290     url.addQueryItem( "cf_kde_version", d->kde_version );
00291     url.addQueryItem( "cf_kde_appversion", m_strVersion );
00292     url.addQueryItem( "cf_kde_package", d->appcombo->currentText() );
00293     url.addQueryItem( "cf_kde_kbugreport", "1" );
00294     d->url = url;
00295 }
00296 
00297 void KBugReport::appChanged(int i)
00298 {
00299     TQString appName = d->appcombo->text(i);
00300     int index = appName.find( '/' );
00301     if ( index > 0 )
00302         appName = appName.left( index );
00303     kdDebug() << "appName " << appName << endl;
00304 
00305     if (d->appname == appName && m_aboutData)
00306         m_strVersion = m_aboutData->version();
00307     else
00308         m_strVersion = i18n("unknown program name", "unknown");
00309 
00310     if ( !d->submitBugButton )
00311         m_strVersion += d->kde_version;
00312 
00313     m_version->setText(m_strVersion);
00314     if ( d->submitBugButton )
00315         updateURL();
00316 }
00317 
00318 void KBugReport::slotConfigureEmail()
00319 {
00320   if (m_process) return;
00321   m_process = new KProcess;
00322   *m_process << TQString::fromLatin1("kcmshell") << TQString::fromLatin1("kcm_useraccount");
00323   connect(m_process, TQT_SIGNAL(processExited(KProcess *)), TQT_SLOT(slotSetFrom()));
00324   if (!m_process->start())
00325   {
00326     kdDebug() << "Couldn't start kcmshell.." << endl;
00327     delete m_process;
00328     m_process = 0;
00329     return;
00330   }
00331   m_configureEmail->setEnabled(false);
00332 }
00333 
00334 void KBugReport::slotSetFrom()
00335 {
00336   delete m_process;
00337   m_process = 0;
00338   m_configureEmail->setEnabled(true);
00339 
00340   // ### KDE4: why oh why is KEmailSettings in kio?
00341   KConfig emailConf( TQString::fromLatin1("emaildefaults") );
00342 
00343   // find out the default profile
00344   emailConf.setGroup( TQString::fromLatin1("Defaults") );
00345   TQString profile = TQString::fromLatin1("PROFILE_");
00346   profile += emailConf.readEntry( TQString::fromLatin1("Profile"),
00347                                   TQString::fromLatin1("Default") );
00348 
00349   emailConf.setGroup( profile );
00350   TQString fromaddr = emailConf.readEntry( TQString::fromLatin1("EmailAddress") );
00351   if (fromaddr.isEmpty()) {
00352      struct passwd *p;
00353      p = getpwuid(getuid());
00354      fromaddr = TQString::fromLatin1(p->pw_name);
00355   } else {
00356      TQString name = emailConf.readEntry( TQString::fromLatin1("FullName"));
00357      if (!name.isEmpty())
00358         fromaddr = name + TQString::fromLatin1(" <") + fromaddr + TQString::fromLatin1(">");
00359   }
00360   m_from->setText( fromaddr );
00361 }
00362 
00363 void KBugReport::slotUrlClicked(const TQString &urlText)
00364 {
00365   if ( kapp )
00366     kapp->invokeBrowser( urlText );
00367 
00368   // When using the web form, a click can also close the window, as there's
00369   // not much to do. It also gives the user a direct response to his click:
00370   if ( d->submitBugButton )
00371       KDialogBase::slotCancel();
00372 }
00373 
00374 
00375 void KBugReport::slotOk( void )
00376 {
00377     if ( d->submitBugButton ) {
00378         if ( kapp )
00379             kapp->invokeBrowser( d->url.url() );
00380         return;
00381     }
00382 
00383     if( m_lineedit->text().isEmpty() ||
00384         m_subject->text().isEmpty() )
00385     {
00386         TQString msg = i18n("You must specify both a subject and a description "
00387                            "before the report can be sent.");
00388         KMessageBox::error(this,msg);
00389         return;
00390     }
00391 
00392     switch ( m_bgSeverity->id( m_bgSeverity->selected() ) )
00393     {
00394         case 0: // critical
00395             if ( KMessageBox::questionYesNo( this, i18n(
00396                 "<p>You chose the severity <b>Critical</b>. "
00397                 "Please note that this severity is intended only for bugs that</p>"
00398                 "<ul><li>break unrelated software on the system (or the whole system)</li>"
00399                 "<li>cause serious data loss</li>"
00400                 "<li>introduce a security hole on the system where the affected package is installed</li></ul>\n"
00401                 "<p>Does the bug you are reporting cause any of the above damage? "
00402                 "If it does not, please select a lower severity. Thank you!</p>" ),TQString::null,KStdGuiItem::cont(),KStdGuiItem::cancel() ) == KMessageBox::No )
00403                 return;
00404             break;
00405         case 1: // grave
00406             if ( KMessageBox::questionYesNo( this, i18n(
00407                 "<p>You chose the severity <b>Grave</b>. "
00408                 "Please note that this severity is intended only for bugs that</p>"
00409                 "<ul><li>make the package in question unusable or mostly so</li>"
00410                 "<li>cause data loss</li>"
00411                 "<li>introduce a security hole allowing access to the accounts of users who use the affected package</li></ul>\n"
00412                 "<p>Does the bug you are reporting cause any of the above damage? "
00413                 "If it does not, please select a lower severity. Thank you!</p>" ),TQString::null,KStdGuiItem::cont(),KStdGuiItem::cancel() ) == KMessageBox::No )
00414                 return;
00415             break;
00416     }
00417     if( !sendBugReport() )
00418     {
00419         TQString msg = i18n("Unable to send the bug report.\n"
00420                            "Please submit a bug report manually...\n"
00421                            "See http://bugs.trinitydesktop.org/ for instructions.");
00422         KMessageBox::error(this, msg + "\n\n" + d->lastError);
00423         return;
00424     }
00425 
00426     KMessageBox::information(this,
00427                              i18n("Bug report sent, thank you for your input."));
00428     accept();
00429 }
00430 
00431 void KBugReport::slotCancel()
00432 {
00433   if( !d->submitBugButton && ( m_lineedit->edited() || m_subject->edited() ) )
00434   {
00435     int rc = KMessageBox::warningYesNo( this,
00436              i18n( "Close and discard\nedited message?" ),
00437              i18n( "Close Message" ), KStdGuiItem::discard(), KStdGuiItem::cont() );
00438     if( rc == KMessageBox::No )
00439       return;
00440   }
00441   KDialogBase::slotCancel();
00442 }
00443 
00444 
00445 TQString KBugReport::text() const
00446 {
00447     kdDebug() << m_bgSeverity->selected()->name() << endl;
00448     // Prepend the pseudo-headers to the contents of the mail
00449   TQString severity = TQString::fromLatin1(m_bgSeverity->selected()->name());
00450   TQString appname = d->appcombo->currentText();
00451   TQString os = TQString::fromLatin1("OS: %1 (%2)\n").
00452                arg(KDE_COMPILING_OS).
00453                arg(KDE_DISTRIBUTION_TEXT);
00454   TQString bodyText;
00455   for(int i = 0; i < m_lineedit->numLines(); i++)
00456   {
00457      TQString line = m_lineedit->textLine(i);
00458      if (!line.endsWith("\n"))
00459         line += '\n';
00460      bodyText += line;
00461   }
00462 
00463   if (severity == TQString::fromLatin1("i18n") && KGlobal::locale()->language() != KLocale::defaultLanguage()) {
00464       // Case 1 : i18n bug
00465       TQString package = TQString::fromLatin1("i18n_%1").arg(KGlobal::locale()->language());
00466       package = package.replace(TQString::fromLatin1("_"), TQString::fromLatin1("-"));
00467       return TQString::fromLatin1("Package: %1").arg(package) +
00468           TQString::fromLatin1("\n"
00469                               "Application: %1\n"
00470                               // not really i18n's version, so better here IMHO
00471                               "Version: %2\n").arg(appname).arg(m_strVersion)+
00472           os+TQString::fromLatin1("\n")+bodyText;
00473   } else {
00474       appname = appname.replace(TQString::fromLatin1("_"), TQString::fromLatin1("-"));
00475       // Case 2 : normal bug
00476       return TQString::fromLatin1("Package: %1\n"
00477                                  "Version: %2\n"
00478                                  "Severity: %3\n")
00479           .arg(appname).arg(m_strVersion).arg(severity)+
00480           TQString::fromLatin1("Compiler: %1\n").arg(KDE_COMPILER_VERSION)+
00481           os+TQString::fromLatin1("\n")+bodyText;
00482   }
00483 }
00484 
00485 bool KBugReport::sendBugReport()
00486 {
00487   TQString recipient ( m_aboutData ?
00488     m_aboutData->bugAddress() :
00489     TQString::fromLatin1("submit@bugs.trinitydesktop.org") );
00490 
00491   TQString command;
00492   command = locate("exe", "ksendbugmail");
00493   if (command.isEmpty())
00494       command = KStandardDirs::findExe( TQString::fromLatin1("ksendbugmail") );
00495 
00496   KTempFile outputfile;
00497   outputfile.close();
00498 
00499   TQString subject = m_subject->text();
00500   command += " --subject ";
00501   command += KProcess::quote(subject);
00502   command += " --recipient ";
00503   command += KProcess::quote(recipient);
00504   command += " > ";
00505   command += KProcess::quote(outputfile.name());
00506 
00507   fflush(stdin);
00508   fflush(stderr);
00509 
00510   FILE * fd = popen(TQFile::encodeName(command), "w");
00511   if (!fd)
00512   {
00513     kdError() << "Unable to open a pipe to " << command << endl;
00514     return false;
00515   }
00516 
00517   TQString btext = text();
00518   fwrite(btext.ascii(),btext.length(),1,fd);
00519   fflush(fd);
00520 
00521   int error = pclose(fd);
00522   kdDebug() << "exit status1 " << error << " " << (WIFEXITED(error)) << " " <<  WEXITSTATUS(error) << endl;
00523 
00524   if ((WIFEXITED(error)) && WEXITSTATUS(error) == 1) {
00525       TQFile of(outputfile.name());
00526       if (of.open(IO_ReadOnly )) {
00527           TQTextStream is(&of);
00528           is.setEncoding(TQTextStream::UnicodeUTF8);
00529           TQString line;
00530           while (!is.eof())
00531               line = is.readLine();
00532           d->lastError = line;
00533       } else {
00534           d->lastError = TQString::null;
00535       }
00536       outputfile.unlink();
00537       return false;
00538   }
00539   outputfile.unlink();
00540   return true;
00541 }
00542 
00543 void KBugReport::virtual_hook( int id, void* data )
00544 { KDialogBase::virtual_hook( id, data ); }
00545 
00546 #include "kbugreport.moc"

kdeui

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

kdeui

Skip menu "kdeui"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kdeui by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |