KDirStat – a graphical disk usage utility
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

kfeedback.cpp 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /*
  2. * File name: kfeedback.cpp
  3. * Summary: User feedback form
  4. * License: LGPL - See file COPYING.LIB for details.
  5. * Author: Stefan Hundhammer <sh@suse.de>
  6. *
  7. * Updated: 2004-11-23
  8. */
  9. #include <tqheader.h>
  10. #include <tqlayout.h>
  11. #include <tqlabel.h>
  12. #include <tqmultilineedit.h>
  13. #include <tqhbox.h>
  14. #include <tdeglobal.h>
  15. #include <kapp.h>
  16. #include <tdelocale.h>
  17. #include <kdebug.h>
  18. #include <tdeaboutdata.h>
  19. #include <kiconloader.h>
  20. #include <kurl.h>
  21. #include "kfeedback.h"
  22. KFeedbackDialog::KFeedbackDialog( const TQString & feedbackMailAddress,
  23. const TQString & helpTopic )
  24. : KDialogBase( Plain, // dialogFace
  25. i18n( "Feedback" ), // caption
  26. Apply | Cancel
  27. | ( helpTopic.isEmpty() ? 0 : (int) Help ), // buttonMask
  28. Apply ) // defaultButton
  29. {
  30. TQVBoxLayout * layout = new TQVBoxLayout( plainPage(), 0, spacingHint() );
  31. setButtonApply( KGuiItem( i18n( "&Mail this..." ) ) );
  32. if ( ! helpTopic.isEmpty() )
  33. setHelp( helpTopic );
  34. _form = new KFeedbackForm( feedbackMailAddress, plainPage() );
  35. TQ_CHECK_PTR( _form );
  36. layout->addWidget( _form );
  37. checkSendButton();
  38. connect( this, TQT_SIGNAL( applyClicked() ),
  39. _form, TQT_SLOT ( sendMail() ) );
  40. connect( _form, TQT_SIGNAL( mailSent() ),
  41. this, TQT_SLOT ( hide() ) );
  42. connect( _form, TQT_SIGNAL( mailSent() ),
  43. this, TQT_SIGNAL( mailSent() ) );
  44. connect( _form, TQT_SIGNAL( checkComplete() ),
  45. this, TQT_SLOT ( checkSendButton() ) );
  46. }
  47. KFeedbackDialog::~KFeedbackDialog()
  48. {
  49. // NOP
  50. }
  51. void
  52. KFeedbackDialog::checkSendButton()
  53. {
  54. enableButtonApply( _form->readyToSend() );
  55. }
  56. KFeedbackForm::KFeedbackForm( const TQString & feedbackMailAddress,
  57. TQWidget * parent )
  58. : TQVBox( parent )
  59. , _feedbackMailAddress( feedbackMailAddress )
  60. {
  61. //
  62. // Explanation above the question list
  63. //
  64. TQLabel * label = new TQLabel( i18n( "<p><b>Please tell us your opinion about this program.</b></p>"
  65. "<p>You will be able to review everything in your mailer "
  66. "before any mail is sent.<br>"
  67. "Nothing will be sent behind your back.</p>"
  68. ), this );
  69. //
  70. // Question list
  71. //
  72. _questionList = new KFeedbackQuestionList( this );
  73. TQ_CHECK_PTR( _questionList );
  74. connect( _questionList, TQT_SIGNAL( checkComplete() ),
  75. this, TQT_SLOT ( slotCheckComplete() ) );
  76. //
  77. // Explanation below the question list
  78. //
  79. TQHBox * hbox = new TQHBox( this );
  80. TQ_CHECK_PTR( hbox );
  81. TQSizePolicy pol( TQSizePolicy::Fixed, TQSizePolicy::Fixed ); // hor / vert
  82. label = new TQLabel( i18n( "Questions marked with " ), hbox );
  83. TQ_CHECK_PTR( label );
  84. label->setSizePolicy( pol );
  85. label = new TQLabel( hbox );
  86. TQ_CHECK_PTR( label );
  87. label->setPixmap( TDEGlobal::iconLoader()->loadIcon( "edit", TDEIcon::Small ) );
  88. label->setSizePolicy( pol );
  89. label = new TQLabel( i18n( " must be answered before a mail can be sent.") , hbox );
  90. TQ_CHECK_PTR( label );
  91. label->setSizePolicy( pol );
  92. new TQWidget( hbox ); // Fill any leftover space to the right.
  93. //
  94. // Free-text comment field
  95. //
  96. label = new TQLabel( "\n" + i18n( "&Additional Comments:" ), this ); TQ_CHECK_PTR( label );
  97. _comment = new TQMultiLineEdit( this ); TQ_CHECK_PTR( _comment );
  98. label->setBuddy( _comment );
  99. _comment->setWordWrap( TQMultiLineEdit::FixedColumnWidth );
  100. _comment->setWrapColumnOrWidth( 70 );
  101. }
  102. KFeedbackForm::~KFeedbackForm()
  103. {
  104. // NOP
  105. }
  106. void
  107. KFeedbackForm::sendMail()
  108. {
  109. //
  110. // Build mail subject
  111. //
  112. TQString subject;
  113. const TDEAboutData * aboutData = TDEGlobal::instance()->aboutData();
  114. if ( aboutData )
  115. subject = aboutData->programName() + "-" + aboutData->version();
  116. else
  117. subject = kapp->name();
  118. subject = "[kde-feedback] " + subject + " user feedback";
  119. //
  120. // Build mail body
  121. //
  122. TQString body = subject + "\n\n"
  123. + formatComment()
  124. + _questionList->result();
  125. //
  126. // Build "mailto:" URL from all this
  127. //
  128. KURL mail;
  129. mail.setProtocol( "mailto" );
  130. mail.setPath( _feedbackMailAddress );
  131. mail.setQuery( "?subject=" + KURL::encode_string( subject ) +
  132. "&body=" + KURL::encode_string( body ) );
  133. // TODO: Check for maximum command line length.
  134. //
  135. // The hard part with this is how to get this from all that 'autoconf'
  136. // stuff into 'config.h' or some other include file without hardcoding
  137. // anything - this is too system dependent.
  138. //
  139. // Actually send mail
  140. //
  141. kapp->invokeMailer( mail );
  142. emit mailSent();
  143. }
  144. void
  145. KFeedbackForm::slotCheckComplete()
  146. {
  147. emit checkComplete();
  148. }
  149. TQString
  150. KFeedbackForm::formatComment()
  151. {
  152. TQString result = _comment->text();
  153. if ( ! result.isEmpty() )
  154. {
  155. result = "<comment>\n" + result + "\n</comment>\n\n";
  156. }
  157. return result;
  158. }
  159. bool
  160. KFeedbackForm::readyToSend()
  161. {
  162. return _questionList->isComplete();
  163. }
  164. KFeedbackQuestionList::KFeedbackQuestionList( TQWidget *parent )
  165. : TQListView( parent )
  166. {
  167. addColumn( "" );
  168. header()->hide();
  169. }
  170. KFeedbackQuestionList::~KFeedbackQuestionList()
  171. {
  172. // NOP
  173. }
  174. bool
  175. KFeedbackQuestionList::isComplete()
  176. {
  177. KFeedbackQuestion * question = firstQuestion();
  178. while ( question )
  179. {
  180. if ( question->isRequired() && ! question->isAnswered() )
  181. return false;
  182. question = question->nextQuestion();
  183. }
  184. return true;
  185. }
  186. TQString
  187. KFeedbackQuestionList::result()
  188. {
  189. TQString res;
  190. KFeedbackQuestion * question = firstQuestion();
  191. while ( question )
  192. {
  193. res += question->result();
  194. question = question->nextQuestion();
  195. }
  196. return res;
  197. }
  198. KFeedbackQuestion *
  199. KFeedbackQuestionList::addQuestion( const TQString & text,
  200. const TQString & id,
  201. bool exclusiveAnswer,
  202. bool required )
  203. {
  204. KFeedbackQuestion * question = new KFeedbackQuestion( this, text, id,
  205. exclusiveAnswer,
  206. required );
  207. TQ_CHECK_PTR( question );
  208. return question;
  209. }
  210. void
  211. KFeedbackQuestionList::addYesNoQuestion( const TQString & text,
  212. const TQString & id,
  213. bool required )
  214. {
  215. KFeedbackQuestion * question = new KFeedbackQuestion( this, text, id,
  216. true, // exclusive
  217. required );
  218. TQ_CHECK_PTR( question );
  219. question->addAnswer( i18n( "yes" ), "yes" );
  220. question->addAnswer( i18n( "no" ), "no" );
  221. }
  222. void
  223. KFeedbackQuestionList::questionAnswered()
  224. {
  225. emit checkComplete();
  226. }
  227. void
  228. KFeedbackQuestionList::questionAdded( KFeedbackQuestion * question)
  229. {
  230. if ( question->isRequired() )
  231. emit checkComplete();
  232. }
  233. static int nextNo = 0;
  234. KFeedbackQuestion::KFeedbackQuestion( KFeedbackQuestionList * parent,
  235. const TQString & text,
  236. const TQString & id,
  237. bool exclusiveAnswer,
  238. bool required,
  239. bool open )
  240. : TQCheckListItem( parent, text )
  241. , _id( id )
  242. , _exclusiveAnswer( exclusiveAnswer )
  243. , _required( required )
  244. {
  245. if ( required )
  246. {
  247. setPixmap( 0, TDEGlobal::iconLoader()->loadIcon( "edit", TDEIcon::Small ) );
  248. }
  249. setOpen( open );
  250. _no = nextNo++;
  251. parent->questionAdded( this );
  252. }
  253. void
  254. KFeedbackQuestion::addAnswer( const TQString & text,
  255. const TQString & id )
  256. {
  257. new KFeedbackAnswer( this, text, id, _exclusiveAnswer );
  258. }
  259. bool
  260. KFeedbackQuestion::isAnswered()
  261. {
  262. if ( ! _exclusiveAnswer )
  263. {
  264. /**
  265. * If any number of answers is permitted for this question, this
  266. * question is always considered to be answered.
  267. **/
  268. return true;
  269. }
  270. /**
  271. * If this question requires an exclusive answer, exactly one of them
  272. * should be checked. We don't need to bother about more than one being
  273. * checked here - TQListView does that for us.
  274. **/
  275. KFeedbackAnswer *answer = firstAnswer();
  276. while ( answer )
  277. {
  278. if ( answer->isChecked() )
  279. return true;
  280. answer = answer->nextAnswer();
  281. }
  282. return false;
  283. }
  284. TQString
  285. KFeedbackQuestion::result()
  286. {
  287. TQString res;
  288. int answers = 0;
  289. KFeedbackAnswer *answer = firstAnswer();
  290. while ( answer )
  291. {
  292. if ( answer->isChecked() )
  293. {
  294. res += _id + "=\"" + answer->id() + "\"\n";
  295. answers++;
  296. }
  297. answer = answer->nextAnswer();
  298. }
  299. if ( answers > 1 )
  300. {
  301. res = "\n" + res + "\n";
  302. }
  303. return res;
  304. }
  305. TQString
  306. KFeedbackQuestion::text()
  307. {
  308. return TQCheckListItem::text(0);
  309. }
  310. TQString
  311. KFeedbackQuestion::key( int, bool ) const
  312. {
  313. TQString no;
  314. no.sprintf( "%08d", _no );
  315. return no;
  316. }
  317. KFeedbackQuestionList *
  318. KFeedbackQuestion::questionList() const
  319. {
  320. return dynamic_cast<KFeedbackQuestionList *>( listView() );
  321. }
  322. KFeedbackAnswer::KFeedbackAnswer( KFeedbackQuestion * parent,
  323. const TQString & text,
  324. const TQString & id,
  325. bool exclusive )
  326. : TQCheckListItem( parent,
  327. text,
  328. exclusive
  329. ? TQCheckListItem::RadioButton
  330. : TQCheckListItem::CheckBox )
  331. , _id( id )
  332. {
  333. _no = nextNo++;
  334. }
  335. TQString
  336. KFeedbackAnswer::text()
  337. {
  338. return TQCheckListItem::text(0);
  339. }
  340. TQString
  341. KFeedbackAnswer::key( int, bool ) const
  342. {
  343. TQString no;
  344. no.sprintf( "%08d", _no );
  345. return no;
  346. }
  347. void
  348. KFeedbackAnswer::stateChange( bool newState )
  349. {
  350. if ( newState && question()->isRequired() )
  351. {
  352. KFeedbackQuestionList * list = question()->questionList();
  353. if ( list )
  354. list->questionAnswered();
  355. }
  356. }
  357. #include "kfeedback.moc"
  358. // EOF