/* * File name: kfeedback.cpp * Summary: User feedback form * License: LGPL - See file COPYING.LIB for details. * Author: Stefan Hundhammer * * Updated: 2004-11-23 */ #include #include #include #include #include #include #include #include #include #include #include #include #include "kfeedback.h" KFeedbackDialog::KFeedbackDialog( const TQString & feedbackMailAddress, const TQString & helpTopic ) : KDialogBase( Plain, // dialogFace i18n( "Feedback" ), // caption Apply | Cancel | ( helpTopic.isEmpty() ? 0 : (int) Help ), // buttonMask Apply ) // defaultButton { TQVBoxLayout * layout = new TQVBoxLayout( plainPage(), 0, spacingHint() ); setButtonApply( KGuiItem( i18n( "&Mail this..." ) ) ); if ( ! helpTopic.isEmpty() ) setHelp( helpTopic ); _form = new KFeedbackForm( feedbackMailAddress, plainPage() ); TQ_CHECK_PTR( _form ); layout->addWidget( _form ); checkSendButton(); connect( this, TQ_SIGNAL( applyClicked() ), _form, TQ_SLOT ( sendMail() ) ); connect( _form, TQ_SIGNAL( mailSent() ), this, TQ_SLOT ( hide() ) ); connect( _form, TQ_SIGNAL( mailSent() ), this, TQ_SIGNAL( mailSent() ) ); connect( _form, TQ_SIGNAL( checkComplete() ), this, TQ_SLOT ( checkSendButton() ) ); } KFeedbackDialog::~KFeedbackDialog() { // NOP } void KFeedbackDialog::checkSendButton() { enableButtonApply( _form->readyToSend() ); } KFeedbackForm::KFeedbackForm( const TQString & feedbackMailAddress, TQWidget * parent ) : TQVBox( parent ) , _feedbackMailAddress( feedbackMailAddress ) { // // Explanation above the question list // TQLabel * label = new TQLabel( i18n( "

Please tell us your opinion about this program.

" "

You will be able to review everything in your mailer " "before any mail is sent.
" "Nothing will be sent behind your back.

" ), this ); // // Question list // _questionList = new KFeedbackQuestionList( this ); TQ_CHECK_PTR( _questionList ); connect( _questionList, TQ_SIGNAL( checkComplete() ), this, TQ_SLOT ( slotCheckComplete() ) ); // // Explanation below the question list // TQHBox * hbox = new TQHBox( this ); TQ_CHECK_PTR( hbox ); TQSizePolicy pol( TQSizePolicy::Fixed, TQSizePolicy::Fixed ); // hor / vert label = new TQLabel( i18n( "Questions marked with " ), hbox ); TQ_CHECK_PTR( label ); label->setSizePolicy( pol ); label = new TQLabel( hbox ); TQ_CHECK_PTR( label ); label->setPixmap( TDEGlobal::iconLoader()->loadIcon( "edit", TDEIcon::Small ) ); label->setSizePolicy( pol ); label = new TQLabel( i18n( " must be answered before a mail can be sent.") , hbox ); TQ_CHECK_PTR( label ); label->setSizePolicy( pol ); new TQWidget( hbox ); // Fill any leftover space to the right. // // Free-text comment field // label = new TQLabel( "\n" + i18n( "&Additional Comments:" ), this ); TQ_CHECK_PTR( label ); _comment = new TQMultiLineEdit( this ); TQ_CHECK_PTR( _comment ); label->setBuddy( _comment ); _comment->setWordWrap( TQMultiLineEdit::FixedColumnWidth ); _comment->setWrapColumnOrWidth( 70 ); } KFeedbackForm::~KFeedbackForm() { // NOP } void KFeedbackForm::sendMail() { // // Build mail subject // TQString subject; const TDEAboutData * aboutData = TDEGlobal::instance()->aboutData(); if ( aboutData ) subject = aboutData->programName() + "-" + aboutData->version(); else subject = kapp->name(); subject = "[kde-feedback] " + subject + " user feedback"; // // Build mail body // TQString body = subject + "\n\n" + formatComment() + _questionList->result(); // // Build "mailto:" URL from all this // KURL mail; mail.setProtocol( "mailto" ); mail.setPath( _feedbackMailAddress ); mail.setQuery( "?subject=" + KURL::encode_string( subject ) + "&body=" + KURL::encode_string( body ) ); // TODO: Check for maximum command line length. // // The hard part with this is how to get this from all that 'autoconf' // stuff into 'config.h' or some other include file without hardcoding // anything - this is too system dependent. // // Actually send mail // kapp->invokeMailer( mail ); emit mailSent(); } void KFeedbackForm::slotCheckComplete() { emit checkComplete(); } TQString KFeedbackForm::formatComment() { TQString result = _comment->text(); if ( ! result.isEmpty() ) { result = "\n" + result + "\n\n\n"; } return result; } bool KFeedbackForm::readyToSend() { return _questionList->isComplete(); } KFeedbackQuestionList::KFeedbackQuestionList( TQWidget *parent ) : TQListView( parent ) { addColumn( "" ); header()->hide(); } KFeedbackQuestionList::~KFeedbackQuestionList() { // NOP } bool KFeedbackQuestionList::isComplete() { KFeedbackQuestion * question = firstQuestion(); while ( question ) { if ( question->isRequired() && ! question->isAnswered() ) return false; question = question->nextQuestion(); } return true; } TQString KFeedbackQuestionList::result() { TQString res; KFeedbackQuestion * question = firstQuestion(); while ( question ) { res += question->result(); question = question->nextQuestion(); } return res; } KFeedbackQuestion * KFeedbackQuestionList::addQuestion( const TQString & text, const TQString & id, bool exclusiveAnswer, bool required ) { KFeedbackQuestion * question = new KFeedbackQuestion( this, text, id, exclusiveAnswer, required ); TQ_CHECK_PTR( question ); return question; } void KFeedbackQuestionList::addYesNoQuestion( const TQString & text, const TQString & id, bool required ) { KFeedbackQuestion * question = new KFeedbackQuestion( this, text, id, true, // exclusive required ); TQ_CHECK_PTR( question ); question->addAnswer( i18n( "yes" ), "yes" ); question->addAnswer( i18n( "no" ), "no" ); } void KFeedbackQuestionList::questionAnswered() { emit checkComplete(); } void KFeedbackQuestionList::questionAdded( KFeedbackQuestion * question) { if ( question->isRequired() ) emit checkComplete(); } static int nextNo = 0; KFeedbackQuestion::KFeedbackQuestion( KFeedbackQuestionList * parent, const TQString & text, const TQString & id, bool exclusiveAnswer, bool required, bool open ) : TQCheckListItem( parent, text ) , _id( id ) , _exclusiveAnswer( exclusiveAnswer ) , _required( required ) { if ( required ) { setPixmap( 0, TDEGlobal::iconLoader()->loadIcon( "edit", TDEIcon::Small ) ); } setOpen( open ); _no = nextNo++; parent->questionAdded( this ); } void KFeedbackQuestion::addAnswer( const TQString & text, const TQString & id ) { new KFeedbackAnswer( this, text, id, _exclusiveAnswer ); } bool KFeedbackQuestion::isAnswered() { if ( ! _exclusiveAnswer ) { /** * If any number of answers is permitted for this question, this * question is always considered to be answered. **/ return true; } /** * If this question requires an exclusive answer, exactly one of them * should be checked. We don't need to bother about more than one being * checked here - TQListView does that for us. **/ KFeedbackAnswer *answer = firstAnswer(); while ( answer ) { if ( answer->isChecked() ) return true; answer = answer->nextAnswer(); } return false; } TQString KFeedbackQuestion::result() { TQString res; int answers = 0; KFeedbackAnswer *answer = firstAnswer(); while ( answer ) { if ( answer->isChecked() ) { res += _id + "=\"" + answer->id() + "\"\n"; answers++; } answer = answer->nextAnswer(); } if ( answers > 1 ) { res = "\n" + res + "\n"; } return res; } TQString KFeedbackQuestion::text() { return TQCheckListItem::text(0); } TQString KFeedbackQuestion::key( int, bool ) const { TQString no; no.sprintf( "%08d", _no ); return no; } KFeedbackQuestionList * KFeedbackQuestion::questionList() const { return dynamic_cast( listView() ); } KFeedbackAnswer::KFeedbackAnswer( KFeedbackQuestion * parent, const TQString & text, const TQString & id, bool exclusive ) : TQCheckListItem( parent, text, exclusive ? TQCheckListItem::RadioButton : TQCheckListItem::CheckBox ) , _id( id ) { _no = nextNo++; } TQString KFeedbackAnswer::text() { return TQCheckListItem::text(0); } TQString KFeedbackAnswer::key( int, bool ) const { TQString no; no.sprintf( "%08d", _no ); return no; } void KFeedbackAnswer::stateChange( bool newState ) { if ( newState && question()->isRequired() ) { KFeedbackQuestionList * list = question()->questionList(); if ( list ) list->questionAnswered(); } } #include "kfeedback.moc" // EOF