Wt examples  3.7.1
Composer.C
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008 Emweb bv, Herent, Belgium.
3  *
4  * See the LICENSE file for terms of use.
5  */
6 #include <iostream>
7 
8 #include "AddresseeEdit.h"
9 #include "AttachmentEdit.h"
10 #include "Composer.h"
11 #include "ContactSuggestions.h"
12 #include "Label.h"
13 #include "Option.h"
14 #include "OptionList.h"
15 
16 #include <Wt/WContainerWidget>
17 #include <Wt/WImage>
18 #include <Wt/WLineEdit>
19 #include <Wt/WLocalDateTime>
20 #include <Wt/WPushButton>
21 #include <Wt/WText>
22 #include <Wt/WTable>
23 #include <Wt/WTableCell>
24 #include <Wt/WStringUtil>
25 
27  : WCompositeWidget(parent),
28  saving_(false),
29  sending_(false)
30 {
32 
33  createUi();
34 }
35 
36 void Composer::setTo(const std::vector<Contact>& to)
37 {
39 }
40 
42 {
43  subject_->setText(subject);
44 }
45 
47 {
48  message_->setText(message);
49 }
50 
51 std::vector<Contact> Composer::to() const
52 {
53  return toEdit_->addressees();
54 }
55 
56 std::vector<Contact> Composer::cc() const
57 {
58  return ccEdit_->addressees();
59 }
60 
61 std::vector<Contact> Composer::bcc() const
62 {
63  return bccEdit_->addressees();
64 }
65 
66 void Composer::setAddressBook(const std::vector<Contact>& contacts)
67 {
69 }
70 
71 const WString& Composer::subject() const
72 {
73  return subject_->text();
74 }
75 
76 std::vector<Attachment> Composer::attachments() const
77 {
78  std::vector<Attachment> attachments;
79 
80  for (unsigned i = 0; i < attachments_.size() - 1; ++i) {
81  std::vector<Attachment> toadd = attachments_[i]->attachments();
82 
83  attachments.insert(attachments.end(), toadd.begin(), toadd.end());
84  }
85 
86  return attachments;
87 }
88 
89 const WString& Composer::message() const
90 {
91  return message_->text();
92 }
93 
95 {
96  setStyleClass("darker");
97 
98  // horizontal layout container, used for top and bottom buttons.
99  WContainerWidget *horiz;
100 
101  /*
102  * Top buttons
103  */
104  horiz = new WContainerWidget(layout_);
105  horiz->setPadding(5);
106  topSendButton_ = new WPushButton(tr("msg.send"), horiz);
107  topSendButton_->setStyleClass("default"); // default action
108  topSaveNowButton_ = new WPushButton(tr("msg.savenow"), horiz);
109  topDiscardButton_ = new WPushButton(tr("msg.discard"), horiz);
110 
111  // Text widget which shows status messages, next to the top buttons.
112  statusMsg_ = new WText(horiz);
113  statusMsg_->setMargin(15, Left);
114 
115  /*
116  * To, Cc, Bcc, Subject, Attachments
117  *
118  * They are organized in a two-column table: left column for
119  * labels, and right column for the edit.
120  */
121  edits_ = new WTable(layout_);
122  edits_->setStyleClass("lighter");
123  edits_->resize(WLength(100, WLength::Percentage), WLength::Auto);
124  edits_->elementAt(0, 0)->resize(WLength(1, WLength::Percentage),
125  WLength::Auto);
126 
127  /*
128  * To, Cc, Bcc
129  */
130  toEdit_ = new AddresseeEdit(tr("msg.to"), edits_->elementAt(0, 1),
131  edits_->elementAt(0, 0));
132  // add some space above To:
133  edits_->elementAt(0, 1)->setMargin(5, Top);
134  ccEdit_ = new AddresseeEdit(tr("msg.cc"), edits_->elementAt(1, 1),
135  edits_->elementAt(1, 0));
136  bccEdit_ = new AddresseeEdit(tr("msg.bcc"), edits_->elementAt(2, 1),
137  edits_->elementAt(2, 0));
138 
139  ccEdit_->hide();
140  bccEdit_->hide();
141 
142  /*
143  * Addressbook suggestions popup
144  */
146 
149  contactSuggestions_->forEdit(bccEdit_);
150 
151  /*
152  * We use an OptionList widget to show the expand options for
153  * ccEdit_ and bccEdit_ nicely next to each other, separated
154  * by pipe characters.
155  */
156  options_ = new OptionList(edits_->elementAt(3, 1));
157 
158  options_->add(addcc_ = new Option(tr("msg.addcc")));
159  options_->add(addbcc_ = new Option(tr("msg.addbcc")));
160 
161  /*
162  * Subject
163  */
164  new Label(tr("msg.subject"), edits_->elementAt(4, 0));
165  subject_ = new WLineEdit(edits_->elementAt(4, 1));
166  subject_->resize(WLength(99, WLength::Percentage), WLength::Auto);
167 
168  /*
169  * Attachments
170  */
171  new WImage("icons/paperclip.png", edits_->elementAt(5, 0));
172  edits_->elementAt(5, 0)->setContentAlignment(AlignRight | AlignTop);
173  edits_->elementAt(5, 0)->setPadding(3);
174 
175  // Attachment edits: we always have the next attachmentedit ready
176  // but hidden. This improves the response time, since the show()
177  // and hide() slots are stateless.
178  attachments_.push_back(new AttachmentEdit(this, edits_->elementAt(5, 1)));
179  attachments_.back()->hide();
180 
181  /*
182  * Two options for attaching files. The first does not say 'another'.
183  */
184  attachFile_ = new Option(tr("msg.attachfile"),
185  edits_->elementAt(5, 1));
186  attachOtherFile_ = new Option(tr("msg.attachanother"),
187  edits_->elementAt(5, 1));
188  attachOtherFile_->hide();
189 
190  /*
191  * Message
192  */
193  message_ = new WTextArea(layout_);
194  message_->setColumns(80);
195  message_->setRows(10); // should be 20, but let's keep it smaller
196  message_->setMargin(10);
197 
198  /*
199  * Bottom buttons
200  */
201  horiz = new WContainerWidget(layout_);
202  horiz->setPadding(5);
203  botSendButton_ = new WPushButton(tr("msg.send"), horiz);
204  botSendButton_->setStyleClass("default");
205  botSaveNowButton_ = new WPushButton(tr("msg.savenow"), horiz);
206  botDiscardButton_ = new WPushButton(tr("msg.discard"), horiz);
207 
208  /*
209  * Button events.
210  */
211  topSendButton_->clicked().connect(this, &Composer::sendIt);
212  botSendButton_->clicked().connect(this, &Composer::sendIt);
213  topSaveNowButton_->clicked().connect(this, &Composer::saveNow);
214  botSaveNowButton_->clicked().connect(this, &Composer::saveNow);
215  topDiscardButton_->clicked().connect(this, &Composer::discardIt);
216  botDiscardButton_->clicked().connect(this, &Composer::discardIt);
217 
218  /*
219  * Option events to show the cc or Bcc edit.
220  *
221  * Clicking on the option should both show the corresponding edit, and
222  * hide the option itself.
223  */
224  addcc_->item()->clicked().connect(ccEdit_, &WWidget::show);
225  addcc_->item()->clicked().connect(addcc_, &WWidget::hide);
226  addcc_->item()->clicked().connect(options_, &OptionList::update);
227  addcc_->item()->clicked().connect(ccEdit_, &WWidget::setFocus);
228 
229  addbcc_->item()->clicked().connect(bccEdit_, &WWidget::show);
230  addbcc_->item()->clicked().connect(addbcc_, &WWidget::hide);
232  addbcc_->item()->clicked().connect(bccEdit_, &WWidget::setFocus);
233 
234  /*
235  * Option event to attach the first attachment.
236  *
237  * We show the first attachment, and call attachMore() to prepare the
238  * next attachment edit that will be hidden.
239  *
240  * In addition, we need to show the 'attach More' option, and hide the
241  * 'attach' option.
242  */
243  attachFile_->item()->clicked().connect(attachments_.back(), &WWidget::show);
244  attachFile_->item()->clicked().connect(attachOtherFile_, &WWidget::show);
245  attachFile_->item()->clicked().connect(attachFile_, &WWidget::hide);
246  attachFile_->item()->clicked().connect(this, &Composer::attachMore);
247  attachOtherFile_->item()->clicked().connect(this, &Composer::attachMore);
248 }
249 
251 {
252  /*
253  * Create and append the next AttachmentEdit, that will be hidden.
254  */
255  AttachmentEdit *edit = new AttachmentEdit(this);
257  attachments_.push_back(edit);
258  attachments_.back()->hide();
259 
260  // Connect the attachOtherFile_ option to show this attachment.
262  .connect(attachments_.back(), &WWidget::show);
263 }
264 
266 {
267  /*
268  * Remove the given attachment from the attachments list.
269  */
270  std::vector<AttachmentEdit *>::iterator i
271  = std::find(attachments_.begin(), attachments_.end(), attachment);
272 
273  if (i != attachments_.end()) {
274  attachments_.erase(i);
275  delete attachment;
276 
277  if (attachments_.size() == 1) {
278  /*
279  * This was the last visible attachment, thus, we should switch
280  * the option control again.
281  */
283  attachFile_->show();
284  attachFile_->item()->clicked()
285  .connect(attachments_.back(), &WWidget::show);
286  }
287  }
288 }
289 
291 {
292  if (!sending_) {
293  sending_ = true;
294 
295  /*
296  * First save -- this will check for the sending_ state
297  * signal if successfull.
298  */
299  saveNow();
300  }
301 }
302 
304 {
305  if (!saving_) {
306  saving_ = true;
307 
308  /*
309  * Check if any attachments still need to be uploaded.
310  * This may be the case when fileupload change events could not
311  * be caught (for example in Konqueror).
312  */
314 
315  for (unsigned i = 0; i < attachments_.size() - 1; ++i) {
316  if (attachments_[i]->uploadNow()) {
318 
319  // this will trigger attachmentDone() when done, see
320  // the AttachmentEdit constructor.
321  }
322  }
323 
324  std::cerr << "Attachments pending: " << attachmentsPending_ << std::endl;
326  setStatus(tr("msg.uploading"), "status");
327  else
328  saved();
329  }
330 }
331 
333 {
334  if (saving_) {
336  std::cerr << "Attachments still: " << attachmentsPending_ << std::endl;
337 
338  if (attachmentsPending_ == 0)
339  saved();
340  }
341 }
342 
343 void Composer::setStatus(const WString& text, const WString& style)
344 {
345  statusMsg_->setText(text);
346  statusMsg_->setStyleClass(style);
347 }
348 
350 {
351  /*
352  * All attachments have been processed.
353  */
354 
355  bool attachmentsFailed = false;
356  for (unsigned i = 0; i < attachments_.size() - 1; ++i)
357  if (attachments_[i]->uploadFailed()) {
358  attachmentsFailed = true;
359  break;
360  }
361 
362  if (attachmentsFailed) {
363  setStatus(tr("msg.attachment.failed"), "error");
364  } else {
365  setStatus(tr("msg.ok"), "status");
367  statusMsg_->setText(Wt::utf8("Draft saved at {1}").arg(timeStr));
368 
369  if (sending_) {
370  send.emit();
371  return;
372  }
373  }
374 
375  saving_ = false;
376  sending_ = false;
377 }
378 
380 {
381  discard.emit();
382 }
virtual void insertBefore(std::unique_ptr< WWidget > widget, WWidget *before)
virtual void setStyleClass(const WString &styleClass) override
const WString & subject() const
Get the subject.
Definition: Composer.C:71
void createUi()
Definition: Composer.C:94
std::vector< Contact > cc() const
Get the Cc: contacts.
Definition: Composer.C:56
A clickable option.
Definition: Option.h:31
std::vector< Attachment > attachments() const
Get the list of attachments.
Definition: Composer.C:76
void forEdit(WFormWidget *edit, WFlags< PopupTrigger > popupTriggers=PopupTrigger::Editing)
AddresseeEdit * bccEdit_
Bcc: Addressees edit.
Definition: Composer.h:113
virtual void setText(const WString &text)
const WString & text() const
WInteractWidget * item()
Returns the clickable part.
Definition: Option.h:44
AddresseeEdit * toEdit_
To: Addressees edit.
Definition: Composer.h:109
WTable * edits_
Definition: Composer.h:106
const WString & message() const
Get the message.
Definition: Composer.C:89
void discardIt()
Slot attached to the Discard button.
Definition: Composer.C:379
WContainerWidget * layout_
Definition: Composer.h:100
EventSignal< WMouseEvent > & clicked()
Option * attachOtherFile_
Option for attaching another file.
Definition: Composer.h:131
Option * addbcc_
Option for editing Bcc:
Definition: Composer.h:127
static WString tr(const char *key)
An edit field for an email attachment.
void setPadding(const WLength &padding, WFlags< Side > sides=AllSides)
WString toString() const
Composer(WContainerWidget *parent=0)
Construct a new Composer.
Definition: Composer.C:26
void saved()
All attachments have been processed, determine the result of saving the message.
Definition: Composer.C:349
WPushButton * botSaveNowButton_
Definition: Composer.h:103
std::vector< AttachmentEdit * > attachments_
Array which holds all the attachments, including one extra invisible one.
Definition: Composer.h:134
WTextArea * message_
WTextArea for the main message.
Definition: Composer.h:137
Wt::Signal< void > send
The message is ready to be sent...
Definition: Composer.h:93
void setContentAlignment(WFlags< AlignmentFlag > contentAlignment)
void emit(A... args) const
Wt::Signal< void > discard
The message must be discarded.
Definition: Composer.h:97
void setSubject(const WString &subject)
Set subject.
Definition: Composer.C:41
void removeAttachment(AttachmentEdit *attachment)
Remove the given attachment edit.
Definition: Composer.C:265
bool setText(const WString &text)
void saveNow()
Slot attached to the Save now button.
Definition: Composer.C:303
void update()
Updates the stateless implementations after an Option has been hidden or shown.
Definition: OptionList.C:30
void setAddressBook(const std::vector< Contact > &contacts)
Set the address book.
virtual void setMargin(const WLength &margin, WFlags< Side > sides=AllSides) override
virtual void setStyleClass(const WString &styleClass) override
A label.
Definition: Label.h:24
WTableCell * elementAt(int row, int column)
WPushButton * botSendButton_
Definition: Composer.h:103
void setImplementation(std::unique_ptr< WWidget > widget)
WPushButton * topDiscardButton_
Definition: Composer.h:102
void sendIt()
Slot attached to the Send button.
Definition: Composer.C:290
A list of options, separated by &#39;|&#39;.
Definition: OptionList.h:40
void setAddressBook(const std::vector< Contact > &addressBook)
Set the address book, for autocomplete suggestions.
Definition: Composer.C:66
void setAddressees(const std::vector< Contact > &contacts)
Set a list of addressees.
Definition: AddresseeEdit.C:27
void setColumns(int cols)
virtual void setText(const WString &text)
An edit field for an email addressee.
Definition: AddresseeEdit.h:31
WPushButton * botDiscardButton_
Definition: Composer.h:103
A suggestion popup suggesting contacts from an addressbook.
std::vector< Contact > bcc() const
Get the Bc: contacts.
Definition: Composer.C:61
static WLocalDateTime currentDateTime(const WLocale &locale=WLocale::currentLocale())
bool saving_
state when waiting asyncrhonously for attachments to be uploaded
Definition: Composer.h:140
Option * attachFile_
Option for attaching a file.
Definition: Composer.h:129
std::vector< Contact > to() const
Get the To: contacts.
Definition: Composer.C:51
WPushButton * topSaveNowButton_
Definition: Composer.h:102
friend class AttachmentEdit
Definition: Composer.h:194
WLineEdit * subject_
The subject line edit.
Definition: Composer.h:119
virtual void resize(const WLength &width, const WLength &height) override
WPushButton * topSendButton_
Definition: Composer.h:102
const WString & text() const
std::vector< Contact > addressees() const
Get a list of addressees.
Definition: AddresseeEdit.C:74
void attachmentDone()
Slotcalled when an attachment has been uploaded.
Definition: Composer.C:332
Option * addcc_
Option for editing Cc:
Definition: Composer.h:125
ContactSuggestions * contactSuggestions_
The suggestions popup for the addressee edits.
Definition: Composer.h:116
void setMessage(const WString &message)
Set the message.
Definition: Composer.C:46
void setTo(const std::vector< Contact > &to)
Set message To: contacts.
Definition: Composer.C:36
void attachMore()
Add an attachment edit.
Definition: Composer.C:250
AddresseeEdit * ccEdit_
Cc: Addressees edit.
Definition: Composer.h:111
int attachmentsPending_
number of attachments waiting to be uploaded during saving
Definition: Composer.h:143
OptionList * options_
OptionsList for editing Cc or Bcc.
Definition: Composer.h:122
void setRows(int rows)
WText * statusMsg_
Definition: Composer.h:104
bool sending_
Definition: Composer.h:140
void add(Option *option)
Add an Option to the list.
Definition: OptionList.C:18
void setStatus(const WString &text, const WString &style)
Set the status, and apply the given style.
Definition: Composer.C:343

Generated on Tue Dec 15 2020 for the C++ Web Toolkit (Wt) by doxygen 1.8.13