kdeui Library API Documentation

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., 59 Temple Place - Suite 330,
00017    Boston, MA 02111-1307, USA.
00018 */
00019 
00020 #include <qhbuttongroup.h>
00021 #include <qpushbutton.h>
00022 #include <qlabel.h>
00023 #include <qlayout.h>
00024 #include <qmultilineedit.h>
00025 #include <qradiobutton.h>
00026 #include <qwhatsthis.h>
00027 #include <qregexp.h>
00028 
00029 #include <kapplication.h>
00030 #include <kaboutdata.h>
00031 #include <kconfig.h>
00032 #include <kstandarddirs.h>
00033 #include <klineedit.h>
00034 #include <klocale.h>
00035 #include <kurl.h>
00036 #include <kmessagebox.h>
00037 #include <kdebug.h>
00038 #include <kprocess.h>
00039 #include <kurllabel.h>
00040 
00041 #include "kbugreport.h"
00042 
00043 #include <stdio.h>
00044 #include <pwd.h>
00045 #include <unistd.h>
00046 
00047 #include <sys/utsname.h>
00048 
00049 #include "kdepackages.h"
00050 #include <kcombobox.h>
00051 #include <config.h>
00052 #include <ktempfile.h>
00053 #include <qtextstream.h>
00054 #include <qfile.h>
00055 
00056 class KBugReportPrivate {
00057 public:
00058     KComboBox *appcombo;
00059     QString lastError;
00060     QString kde_version;
00061     QString appname;
00062     QString os;
00063     KURLLabel *webFormLabel;
00064 };
00065 
00066 KBugReport::KBugReport( QWidget * parentw, bool modal, const KAboutData *aboutData )
00067   : KDialogBase( Plain,
00068                  i18n("Submit Bug Report"),
00069                  Ok | Cancel,
00070                  Ok,
00071                  parentw,
00072                  "KBugReport",
00073                  modal, // modal
00074                  true // separator
00075                  )
00076 {
00077   d = new KBugReportPrivate;
00078 
00079   // Use supplied aboutdata, otherwise the one from the active instance
00080   // otherwise the KGlobal one. _activeInstance should neved be 0L in theory.
00081   m_aboutData = aboutData
00082     ? aboutData
00083     : ( KGlobal::_activeInstance ? KGlobal::_activeInstance->aboutData()
00084                                  : KGlobal::instance()->aboutData() );
00085   m_process = 0;
00086   QWidget * parent = plainPage();
00087   d->webFormLabel = 0;
00088 
00089   if ( m_aboutData->bugAddress() == QString::fromLatin1("submit@bugs.kde.org") )
00090   {
00091     // This is a core KDE application -> redirect to the web form
00092     d->webFormLabel = new KURLLabel( parent );
00093     setButtonCancelText(i18n("&Close"));
00094   }
00095 
00096   QLabel * tmpLabel;
00097   QVBoxLayout * lay = new QVBoxLayout( parent, 0, spacingHint() );
00098 
00099   QGridLayout *glay = new QGridLayout( lay, 4, 3 );
00100   glay->setColStretch( 1, 10 );
00101   glay->setColStretch( 2, 10 );
00102 
00103   int row = 0;
00104 
00105   if ( !d->webFormLabel )
00106   {
00107     // From
00108     QString qwtstr = i18n( "Your email address. If incorrect, use the Configure Email button to change it" );
00109     tmpLabel = new QLabel( i18n("From:"), parent );
00110     glay->addWidget( tmpLabel, row,0 );
00111     QWhatsThis::add( tmpLabel, qwtstr );
00112     m_from = new QLabel( parent );
00113     glay->addWidget( m_from, row, 1 );
00114     QWhatsThis::add( m_from, qwtstr );
00115 
00116 
00117     // Configure email button
00118     m_configureEmail = new QPushButton( i18n("Configure Email..."),
00119                                         parent );
00120     connect( m_configureEmail, SIGNAL( clicked() ), this,
00121              SLOT( slotConfigureEmail() ) );
00122     glay->addMultiCellWidget( m_configureEmail, 0, 2, 2, 2, AlignTop|AlignRight );
00123 
00124     // To
00125     qwtstr = i18n( "The email address this bug report is sent to." );
00126     tmpLabel = new QLabel( i18n("To:"), parent );
00127     glay->addWidget( tmpLabel, ++row,0 );
00128     QWhatsThis::add( tmpLabel, qwtstr );
00129     tmpLabel = new QLabel( m_aboutData->bugAddress(), parent );
00130     glay->addWidget( tmpLabel, row, 1 );
00131     QWhatsThis::add( tmpLabel, qwtstr );
00132 
00133     setButtonOKText(i18n("&Send"),
00134                     i18n("Send bug report."),
00135                     i18n("Send this bug report to the KDE buglist."));
00136 
00137   }
00138   else
00139   {
00140     m_configureEmail = 0;
00141     m_from = 0;
00142     showButtonOK( false );
00143   }
00144 
00145   // Program name
00146   QString 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" );
00147   tmpLabel = new QLabel( i18n("Application: "), parent );
00148   glay->addWidget( tmpLabel, ++row, 0 );
00149   QWhatsThis::add( tmpLabel, qwtstr );
00150   d->appcombo = new KComboBox( false, parent, "app");
00151   QWhatsThis::add( d->appcombo, qwtstr );
00152   d->appcombo->insertStrList((const char**)packages);
00153   connect(d->appcombo, SIGNAL(activated(int)), SLOT(appChanged(int)));
00154   d->appname = QString::fromLatin1( m_aboutData
00155                                     ? m_aboutData->appName()
00156                                     : qApp->name() );
00157   glay->addWidget( d->appcombo, row, 1 );
00158   int index = 0;
00159   for (; index < d->appcombo->count(); index++) {
00160       if (d->appcombo->text(index) == d->appname) {
00161           break;
00162       }
00163   }
00164   if (index == d->appcombo->count()) { // not present
00165       d->appcombo->insertItem(d->appname);
00166   }
00167   d->appcombo->setCurrentItem(index);
00168 
00169   QWhatsThis::add( tmpLabel, qwtstr );
00170 
00171   // Version
00172   qwtstr = i18n( "The version of this application - please make sure that no newer version is available before sending a bug report" );
00173   tmpLabel = new QLabel( i18n("Version:"), parent );
00174   glay->addWidget( tmpLabel, ++row, 0 );
00175   QWhatsThis::add( tmpLabel, qwtstr );
00176   if (m_aboutData)
00177       m_strVersion = m_aboutData->version();
00178   else
00179       m_strVersion = i18n("no version set (programmer error!)");
00180   d->kde_version = QString::fromLatin1(" (KDE " KDE_VERSION_STRING ") ("
00181           KDE_DISTRIBUTION_TEXT ")");
00182   m_strVersion += d->kde_version;
00183   m_version = new QLabel( m_strVersion, parent );
00184   //glay->addWidget( m_version, row, 1 );
00185   glay->addMultiCellWidget( m_version, row, row, 1, 2 );
00186   QWhatsThis::add( m_version, qwtstr );
00187 
00188   tmpLabel = new QLabel(i18n("OS:"), parent);
00189   glay->addWidget( tmpLabel, ++row, 0 );
00190 
00191   struct utsname unameBuf;
00192   uname( &unameBuf );
00193   d->os = QString::fromLatin1( unameBuf.sysname ) +
00194                     " (" + QString::fromLatin1( unameBuf.machine ) + ") "
00195           "release " + QString::fromLatin1( unameBuf.release );
00196 
00197   tmpLabel = new QLabel(d->os, parent);
00198   glay->addMultiCellWidget( tmpLabel, row, row, 1, 2 );
00199 
00200   tmpLabel = new QLabel(i18n("Compiler:"), parent);
00201   glay->addWidget( tmpLabel, ++row, 0 );
00202   tmpLabel = new QLabel(QString::fromLatin1(KDE_COMPILER_VERSION), parent);
00203   glay->addMultiCellWidget( tmpLabel, row, row, 1, 2 );
00204 
00205   if ( !d->webFormLabel )
00206   {
00207     // Severity
00208     m_bgSeverity = new QHButtonGroup( i18n("Se&verity"), parent );
00209     static const char * const sevNames[5] = { "critical", "grave", "normal", "wishlist", "i18n" };
00210     const QString sevTexts[5] = { i18n("Critical"), i18n("Grave"), i18n("normal severity","Normal"), i18n("Wishlist"), i18n("Translation") };
00211 
00212     for (int i = 0 ; i < 5 ; i++ )
00213     {
00214       // Store the severity string as the name
00215       QRadioButton *rb = new QRadioButton( sevTexts[i], m_bgSeverity, sevNames[i] );
00216       if (i==2) rb->setChecked(true); // default : "normal"
00217     }
00218 
00219     lay->addWidget( m_bgSeverity );
00220 
00221     // Subject
00222     QHBoxLayout * hlay = new QHBoxLayout( lay );
00223     tmpLabel = new QLabel( i18n("S&ubject: "), parent );
00224     hlay->addWidget( tmpLabel );
00225     m_subject = new KLineEdit( parent );
00226     m_subject->setFocus();
00227     tmpLabel->setBuddy(m_subject);
00228     hlay->addWidget( m_subject );
00229 
00230     QString text = i18n(""
00231                         "Enter the text (in English if possible) that you wish to submit for the "
00232                         "bug report.\n"
00233                         "If you press \"Send\", a mail message will be sent to the maintainer of "
00234                         "this program \n"
00235                         "and to the KDE buglist.");
00236     QLabel * label = new QLabel( parent, "label" );
00237 
00238     /*
00239       2000-01-15 Espen
00240       Does not work (yet). The label has no well defined height so the
00241       dialog can be resized so that the action buttons become obscured
00242 
00243       QString text = i18n(""
00244       "Enter the text (in English if possible) that you wish to submit for the "
00245       "bug report. If you press \"Send\", a mail message will be sent to the "
00246       "maintainer of this program and to the KDE buglist.");
00247       QLabel * label = new QLabel( parent, "label" );
00248       label->setTextFormat( RichText );
00249     */
00250 
00251     label->setText( text );
00252     lay->addWidget( label );
00253 
00254     // The multiline-edit
00255     m_lineedit = new QMultiLineEdit( parent, "QMultiLineEdit" );
00256     m_lineedit->setMinimumHeight( 180 ); // make it big
00257     m_lineedit->setWordWrap(QMultiLineEdit::WidgetWidth);
00258     lay->addWidget( m_lineedit, 10 /*stretch*/ );
00259 
00260 
00261     hlay = new QHBoxLayout( lay, 0 );
00262 
00263     text = i18n("Please check that the bug you are about to report is not already listed at ");
00264     label = new QLabel( text, parent, "label");
00265     hlay->addWidget( label, 0, AlignBottom );
00266     hlay->addSpacing(1); // Looks better :)
00267 
00268     text = "http://bugs.kde.org/";
00269     KURLLabel *url = new KURLLabel( parent );
00270     url->setText(text);
00271     url->setURL(text);
00272     connect( url, SIGNAL(leftClickedURL(const QString &)),
00273              this, SLOT(slotUrlClicked(const QString &)));
00274     hlay->addWidget( url, 0, AlignBottom );
00275 
00276     hlay->addStretch( 10 );
00277 
00278     // Necessary for vertical label and url alignment.
00279     label->setFixedHeight( fontMetrics().lineSpacing() );
00280     url->setFixedHeight( fontMetrics().lineSpacing());
00281 
00282     slotSetFrom();
00283   } else {
00284     // Point to the web form
00285 
00286     lay->addSpacing(20);
00287     QString text = i18n("To submit a bug report, click on the link below.\n"
00288                         "This will open a web browser window on http://bugs.kde.org where you'll find a form to fill in.\n"
00289                         "The information displayed above will be transferred to that server.");
00290     QLabel * label = new QLabel( text, parent, "label");
00291     lay->addWidget( label );
00292     lay->addSpacing(20);
00293 
00294     updateURL();
00295     d->webFormLabel->setText( "http://bugs.kde.org/wizard/index.php" );
00296     lay->addWidget( d->webFormLabel );
00297     lay->addSpacing(20);
00298 
00299     connect( d->webFormLabel, SIGNAL(leftClickedURL(const QString &)),
00300              this, SLOT(slotUrlClicked(const QString &)));
00301   }
00302 }
00303 
00304 KBugReport::~KBugReport()
00305 {
00306     delete d;
00307 }
00308 
00309 void KBugReport::updateURL()
00310 {
00311     QString url = QString::fromLatin1("http://bugs.kde.org/wizard/index.php");
00312     url += "?os=";
00313     url += KURL::encode_string( d->os );
00314     url += "&compiler=";
00315     url += KURL::encode_string( QString::fromLatin1(KDE_COMPILER_VERSION) );
00316     url += "&version=";
00317     url += KURL::encode_string( m_strVersion );
00318     url += "&package=";
00319     url += KURL::encode_string( d->appcombo->currentText() );
00320     url += "&kbugreport=1";
00321     d->webFormLabel->setURL( url );
00322 }
00323 
00324 void KBugReport::appChanged(int i)
00325 {
00326     if (d->appname == d->appcombo->text(i) && m_aboutData)
00327         m_strVersion = m_aboutData->version();
00328     else
00329         m_strVersion = i18n("unknown program name", "unknown");
00330 
00331     m_strVersion += d->kde_version;
00332     m_version->setText(m_strVersion);
00333     if ( d->webFormLabel )
00334         updateURL();
00335 }
00336 
00337 void KBugReport::slotConfigureEmail()
00338 {
00339   if (m_process) return;
00340   m_process = new KProcess;
00341   *m_process << QString::fromLatin1("kcmshell") << QString::fromLatin1("email");
00342   connect(m_process, SIGNAL(processExited(KProcess *)), SLOT(slotSetFrom()));
00343   if (!m_process->start())
00344   {
00345     kdDebug() << "Couldn't start kcmshell.." << endl;
00346     delete m_process;
00347     m_process = 0;
00348     return;
00349   }
00350   m_configureEmail->setEnabled(false);
00351 }
00352 
00353 void KBugReport::slotSetFrom()
00354 {
00355   delete m_process;
00356   m_process = 0;
00357   m_configureEmail->setEnabled(true);
00358 
00359   // ### KDE3: why oh why is KEmailSettings in kio?
00360   KConfig emailConf( QString::fromLatin1("emaildefaults") );
00361 
00362   // find out the default profile
00363   emailConf.setGroup( QString::fromLatin1("Defaults") );
00364   QString profile = QString::fromLatin1("PROFILE_");
00365   profile += emailConf.readEntry( QString::fromLatin1("Profile"),
00366                                   QString::fromLatin1("Default") );
00367 
00368   emailConf.setGroup( profile );
00369   QString fromaddr = emailConf.readEntry( QString::fromLatin1("EmailAddress") );
00370   if (fromaddr.isEmpty()) {
00371      struct passwd *p;
00372      p = getpwuid(getuid());
00373      fromaddr = QString::fromLatin1(p->pw_name);
00374   } else {
00375      QString name = emailConf.readEntry( QString::fromLatin1("FullName"));
00376      if (!name.isEmpty())
00377         fromaddr = name + QString::fromLatin1(" <") + fromaddr + QString::fromLatin1(">");
00378   }
00379   m_from->setText( fromaddr );
00380 }
00381 
00382 void KBugReport::slotUrlClicked(const QString &urlText)
00383 {
00384   if ( kapp )
00385     kapp->invokeBrowser( urlText );
00386 
00387   // When using the web form, a click can also close the window, as there's
00388   // not much to do. It also gives the user a direct response to his click:
00389   if ( d->webFormLabel )
00390       KDialogBase::slotCancel();
00391 }
00392 
00393 
00394 void KBugReport::slotOk( void )
00395 {
00396     if ( d->webFormLabel)
00397         return;
00398 
00399     if( m_lineedit->text().isEmpty() == true ||
00400         m_subject->text().isEmpty() == true )
00401     {
00402         QString msg = i18n("You must specify both a subject and a description "
00403                            "before the report can be sent.");
00404         KMessageBox::error(this,msg);
00405         return;
00406     }
00407 
00408     switch ( m_bgSeverity->id( m_bgSeverity->selected() ) )
00409     {
00410         case 0: // critical
00411             if ( KMessageBox::questionYesNo( this, i18n(
00412                 "<p>You chose the severity <b>Critical</b>. "
00413                 "Please note that this severity is intended only for bugs that</p>"
00414                 "<ul><li>break unrelated software on the system (or the whole system)</li>"
00415                 "<li>cause serious data loss</li>"
00416                 "<li>introduce a security hole on the system where the affected package is installed</li></ul>\n"
00417                 "<p>Does the bug you are reporting cause any of the above damage? "
00418                 "If it does not, please select a lower severity. Thank you!</p>" ) ) == KMessageBox::No )
00419                 return;
00420             break;
00421         case 1: // grave
00422             if ( KMessageBox::questionYesNo( this, i18n(
00423                 "<p>You chose the severity <b>Grave</b>. "
00424                 "Please note that this severity is intended only for bugs that</p>"
00425                 "<ul><li>make the package in question unusable or mostly so</li>"
00426                 "<li>cause data loss</li>"
00427                 "<li>introduce a security hole allowing access to the accounts of users who use the affected package</li></ul>\n"
00428                 "<p>Does the bug you are reporting cause any of the above damage? "
00429                 "If it does not, please select a lower severity. Thank you!</p>" ) ) == KMessageBox::No )
00430                 return;
00431             break;
00432     }
00433     if( !sendBugReport() )
00434     {
00435         QString msg = i18n(""
00436                            "Unable to send the bug report.\n"
00437                            "Please submit a bug report manually...\n"
00438                            "See http://bugs.kde.org/ for instructions.");
00439         KMessageBox::error(this, msg + "\n\n" + d->lastError);
00440         return;
00441     }
00442 
00443     KMessageBox::information(this,
00444                              i18n("Bug report sent, thank you for your input."));
00445     accept();
00446 }
00447 
00448 void KBugReport::slotCancel()
00449 {
00450   if( !d->webFormLabel && ( m_lineedit->edited() || m_subject->edited() ) )
00451   {
00452     int rc = KMessageBox::warningYesNo( this,
00453              i18n( "Close and discard\nedited message?" ),
00454              i18n( "Close message" ), i18n( "&Discard" ), i18n("&Continue") );
00455     if( rc == KMessageBox::No )
00456       return;
00457   }
00458   KDialogBase::slotCancel();
00459 }
00460 
00461 
00462 QString KBugReport::text() const
00463 {
00464     kdDebug() << m_bgSeverity->selected()->name() << endl;
00465     // Prepend the pseudo-headers to the contents of the mail
00466   QString severity = QString::fromLatin1(m_bgSeverity->selected()->name());
00467   QString appname = d->appcombo->currentText();
00468   QString os = QString::fromLatin1("OS: %1 (%2)\n").
00469                arg(KDE_COMPILING_OS).
00470                arg(KDE_DISTRIBUTION_TEXT);
00471   QString bodyText;
00472   for(int i = 0; i < m_lineedit->numLines(); i++)
00473   {
00474      QString line = m_lineedit->textLine(i);
00475      if (line.right(1) != "\n")
00476         line += '\n';
00477      bodyText += line;
00478   }
00479 
00480   if (severity == QString::fromLatin1("i18n") && KGlobal::locale()->language() != KLocale::defaultLanguage()) {
00481       // Case 1 : i18n bug
00482       QString package = QString::fromLatin1("i18n_%1").arg(KGlobal::locale()->language());
00483       package = package.replace(QRegExp("_"), QString::fromLatin1("-"));
00484       return QString::fromLatin1("Package: %1").arg(package) +
00485           QString::fromLatin1("\n"
00486                               "Application: %1\n"
00487                               // not really i18n's version, so better here IMHO
00488                               "Version: %2\n").arg(appname).arg(m_strVersion)+
00489           os+QString::fromLatin1("\n")+bodyText;
00490   } else {
00491       appname = appname.replace(QRegExp("_"), QString::fromLatin1("-"));
00492       // Case 2 : normal bug
00493       return QString::fromLatin1("Package: %1\n"
00494                                  "Version: %2\n"
00495                                  "Severity: %3\n")
00496           .arg(appname).arg(m_strVersion).arg(severity)+
00497           QString::fromLatin1("Compiler: %1\n").arg(KDE_COMPILER_VERSION)+
00498           os+QString::fromLatin1("\n")+bodyText;
00499   }
00500 }
00501 
00502 bool KBugReport::sendBugReport()
00503 {
00504   QString recipient ( m_aboutData ?
00505     m_aboutData->bugAddress() :
00506     QString::fromLatin1("submit@bugs.kde.org") );
00507 
00508   QString command;
00509   command = locate("exe", "ksendbugmail");
00510   if (command.isEmpty())
00511       command = KStandardDirs::findExe( QString::fromLatin1("ksendbugmail") );
00512 
00513   KTempFile outputfile;
00514   outputfile.close();
00515 
00516   QString subject = m_subject->text();
00517   subject = subject.replace(QRegExp("\""), QString::fromLatin1("\\\""));
00518   command += QString::fromLatin1(" --subject \"%1\" --recipient \"%2\" > %3").
00519              arg(KProcess::quote(subject)).
00520              arg(KProcess::quote(recipient)).
00521              arg(outputfile.name());
00522 
00523   fflush(stdin);
00524   fflush(stderr);
00525 
00526   FILE * fd = popen(command.local8Bit(), "w");
00527   if (!fd)
00528   {
00529     kdError() << "Unable to open a pipe to " << command << endl;
00530     return false;
00531   }
00532 
00533   QString btext = text();
00534   fwrite(btext.ascii(),btext.length(),1,fd);
00535   fflush(fd);
00536 
00537   int error = pclose(fd);
00538   kdDebug() << "exit status1 " << error << " " << (WIFEXITED(error)) << " " <<  WEXITSTATUS(error) << endl;
00539 
00540   if ((WIFEXITED(error)) && WEXITSTATUS(error) == 1) {
00541       QFile of(outputfile.name());
00542       if (of.open(IO_ReadOnly )) {
00543           QTextStream is(&of);
00544           is.setEncoding(QTextStream::UnicodeUTF8);
00545           QString line;
00546           while (!is.eof())
00547               line = is.readLine();
00548           d->lastError = line;
00549       } else {
00550           d->lastError = QString::null;
00551       }
00552       outputfile.unlink();
00553       return false;
00554   }
00555   outputfile.unlink();
00556   return true;
00557 }
00558 
00559 void KBugReport::virtual_hook( int id, void* data )
00560 { KDialogBase::virtual_hook( id, data ); }
00561 
00562 #include "kbugreport.moc"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:20:57 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001