Wt examples  4.0.0
Composer.C
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008 Emweb bvba, Kessel-Lo, 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.h>
17 #include <Wt/WImage.h>
18 #include <Wt/WLineEdit.h>
19 #include <Wt/WPushButton.h>
20 #include <Wt/WText.h>
21 #include <Wt/WTable.h>
22 #include <Wt/WTableCell.h>
23 #include <Wt/WStringUtil.h>
24 #include <algorithm>
25 
27  : WCompositeWidget(),
28  saving_(false),
29  sending_(false)
30 {
31  std::unique_ptr<WContainerWidget> layout
32  = cpp14::make_unique<WContainerWidget>();
33  layout_ = layout.get();
34  setImplementation(std::move(layout));
35 
36  createUi();
37 }
38 
39 void Composer::setTo(const std::vector<Contact>& to)
40 {
42 }
43 
45 {
46  subject_->setText(subject);
47 }
48 
50 {
51  message_->setText(message);
52 }
53 
54 std::vector<Contact> Composer::to() const
55 {
56  return toEdit_->addressees();
57 }
58 
59 std::vector<Contact> Composer::cc() const
60 {
61  return ccEdit_->addressees();
62 }
63 
64 std::vector<Contact> Composer::bcc() const
65 {
66  return bccEdit_->addressees();
67 }
68 
69 void Composer::setAddressBook(const std::vector<Contact>& contacts)
70 {
72 }
73 
74 const WString& Composer::subject() const
75 {
76  return subject_->text();
77 }
78 
79 std::vector<Attachment> Composer::attachments() const
80 {
81  std::vector<Attachment> attachments;
82 
83  for (unsigned i = 0; i < attachments_.size() - 1; ++i) {
84  std::vector<Attachment> toadd = attachments_[i]->attachments();
85 
86  attachments.insert(attachments.end(), toadd.begin(), toadd.end());
87  }
88 
89  return attachments;
90 }
91 
92 const WString& Composer::message() const
93 {
94  return message_->text();
95 }
96 
98 {
99  setStyleClass("darker");
100 
101  // horizontal layout container, used for top and bottom buttons.
102  WContainerWidget *horiz;
103 
104  /*
105  * Top buttons
106  */
107  horiz = layout_->addWidget(cpp14::make_unique<WContainerWidget>());
108  horiz->setPadding(5);
109  topSendButton_ = horiz->addWidget(cpp14::make_unique<WPushButton>(tr("msg.send")));
110  topSendButton_->setStyleClass("default"); // default action
111  topSaveNowButton_ = horiz->addWidget(cpp14::make_unique<WPushButton>(tr("msg.savenow")));
112  topDiscardButton_ = horiz->addWidget(cpp14::make_unique<WPushButton>(tr("msg.discard")));
113 
114  // Text widget which shows status messages, next to the top buttons.
115  statusMsg_ = horiz->addWidget(cpp14::make_unique<WText>());
116  statusMsg_->setMargin(15, Side::Left);
117 
118  /*
119  * To, Cc, Bcc, Subject, Attachments
120  *
121  * They are organized in a two-column table: left column for
122  * labels, and right column for the edit.
123  */
124  edits_ = layout_->addWidget(cpp14::make_unique<WTable>());
125  edits_->setStyleClass("lighter");
126  edits_->resize(WLength(100, LengthUnit::Percentage), WLength::Auto);
127  edits_->elementAt(0, 0)->resize(WLength(1, LengthUnit::Percentage),
128  WLength::Auto);
129 
130  /*
131  * To, Cc, Bcc
132  */
133  toEdit_ = edits_->elementAt(0,1)->addWidget(cpp14::make_unique<AddresseeEdit>(tr("msg.to"), edits_->elementAt(0, 0)));
134  // add some space above To:
135  edits_->elementAt(0, 1)->setMargin(5, Side::Top);
136  ccEdit_ = edits_->elementAt(1,1)->addWidget(cpp14::make_unique<AddresseeEdit>(tr("msg.cc"), edits_->elementAt(1, 0)));
137  bccEdit_ = edits_->elementAt(2,1)->addWidget(cpp14::make_unique<AddresseeEdit>(tr("msg.bcc"), edits_->elementAt(2, 0)));
138 
139  ccEdit_->hide();
140  bccEdit_->hide();
141 
142  /*
143  * Addressbook suggestions popup
144  */
145  contactSuggestions_ = layout_->addWidget(cpp14::make_unique<ContactSuggestions>());
146 
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_ = edits_->elementAt(3, 1)->addWidget(cpp14::make_unique<OptionList>());
157  std::unique_ptr<Option> addcc(new Option(tr("msg.addcc")));
158  addcc_ = addcc.get();
159  std::unique_ptr<Option> addbcc(new Option(tr("msg.addbcc")));
160  addbcc_ = addbcc.get();
161 
162  options_->add(std::move(addcc));
163  options_->add(std::move(addbcc));
164 
165  /*
166  * Subject
167  */
168  edits_->elementAt(4, 0)->addWidget(cpp14::make_unique<Label>(tr("msg.subject"), edits_->elementAt(4, 0)));
169  subject_ = edits_->elementAt(4, 1)->addWidget(cpp14::make_unique<WLineEdit>());
170  subject_->resize(WLength(99, LengthUnit::Percentage), WLength::Auto);
171 
172  /*
173  * Attachments
174  */
175  edits_->elementAt(5, 0)->addWidget(cpp14::make_unique<WImage>("icons/paperclip.png"));
176  edits_->elementAt(5, 0)->setContentAlignment(AlignmentFlag::Right | AlignmentFlag::Top);
177  edits_->elementAt(5, 0)->setPadding(3);
178 
179  // Attachment edits: we always have the next attachmentedit ready
180  // but hidden. This improves the response time, since the show()
181  // and hide() slots are stateless.
182  AttachmentEdit *attachmentEdit = edits_->elementAt(5, 1)->addWidget(cpp14::make_unique<AttachmentEdit>(this));
183  attachments_.push_back(attachmentEdit);
184  attachments_.back()->hide();
185 
186  /*
187  * Two options for attaching files. The first does not say 'another'.
188  */
189  attachFile_ = edits_->elementAt(5, 1)->addWidget(cpp14::make_unique<Option>(tr("msg.attachfile")));
190  attachOtherFile_ = edits_->elementAt(5, 1)->addWidget(cpp14::make_unique<Option>(tr("msg.attachanother")));
192 
193  /*
194  * Message
195  */
196  message_ = layout_->addWidget(cpp14::make_unique<WTextArea>());
197  message_->setColumns(80);
198  message_->setRows(10); // should be 20, but let's keep it smaller
199  message_->setMargin(10);
200 
201  /*
202  * Bottom buttons
203  */
204  horiz = layout_->addWidget(cpp14::make_unique<WContainerWidget>());
205  horiz->setPadding(5);
206  botSendButton_ = horiz->addWidget(cpp14::make_unique<WPushButton>(tr("msg.send")));
207  botSendButton_->setStyleClass("default");
208  botSaveNowButton_ = horiz->addWidget(cpp14::make_unique<WPushButton>(tr("msg.savenow")));
209  botDiscardButton_ = horiz->addWidget(cpp14::make_unique<WPushButton>(tr("msg.discard")));
210 
211  /*
212  * Button events.
213  */
220 
221  /*
222  * Option events to show the cc or Bcc edit.
223  *
224  * Clicking on the option should both show the corresponding edit, and
225  * hide the option itself.
226  */
227  addcc_->item()->clicked().connect(ccEdit_, &WWidget::show);
228  addcc_->item()->clicked().connect(addcc_, &WWidget::hide);
230  addcc_->item()->clicked().connect(ccEdit_, &WWidget::setFocus);
231 
232  addbcc_->item()->clicked().connect(bccEdit_, &WWidget::show);
233  addbcc_->item()->clicked().connect(addbcc_, &WWidget::hide);
235  addbcc_->item()->clicked().connect(bccEdit_, &WWidget::setFocus);
236 
237  /*
238  * Option event to attach the first attachment.
239  *
240  * We show the first attachment, and call attachMore() to prepare the
241  * next attachment edit that will be hidden.
242  *
243  * In addition, we need to show the 'attach More' option, and hide the
244  * 'attach' option.
245  */
246  attachFile_->item()->clicked().connect(attachments_.back(), &WWidget::show);
247  attachFile_->item()->clicked().connect(attachOtherFile_, &WWidget::show);
248  attachFile_->item()->clicked().connect(attachFile_, &WWidget::hide);
251 }
252 
254 {
255  /*
256  * Create and append the next AttachmentEdit, that will be hidden.
257  */
258  std::unique_ptr<AttachmentEdit> edit
259  = cpp14::make_unique<AttachmentEdit>(this);
260  AttachmentEdit *editPtr = edit.get();
261  edits_->elementAt(5, 1)->insertBefore(std::move(edit), attachOtherFile_);
262  attachments_.push_back(editPtr);
263  attachments_.back()->hide();
264 
265  // Connect the attachOtherFile_ option to show this attachment.
267  .connect(attachments_.back(), &WWidget::show);
268 }
269 
271 {
272  /*
273  * Remove the given attachment from the attachments list.
274  */
275  std::vector<AttachmentEdit *>::iterator i
276  = std::find(attachments_.begin(), attachments_.end(), attachment);
277 
278  if (i != attachments_.end()) {
279  attachments_.erase(i);
280  attachment->removeFromParent();
281 
282  if (attachments_.size() == 1) {
283  /*
284  * This was the last visible attachment, thus, we should switch
285  * the option control again.
286  */
288  attachFile_->show();
289  attachFile_->item()->clicked()
290  .connect(attachments_.back(), &WWidget::show);
291  }
292  }
293 }
294 
296 {
297  if (!sending_) {
298  sending_ = true;
299 
300  /*
301  * First save -- this will check for the sending_ state
302  * signal if successfull.
303  */
304  saveNow();
305  }
306 }
307 
309 {
310  if (!saving_) {
311  saving_ = true;
312 
313  /*
314  * Check if any attachments still need to be uploaded.
315  * This may be the case when fileupload change events could not
316  * be caught (for example in Konqueror).
317  */
319 
320  for (unsigned i = 0; i < attachments_.size() - 1; ++i) {
321  if (attachments_[i]->uploadNow()) {
323 
324  // this will trigger attachmentDone() when done, see
325  // the AttachmentEdit constructor.
326  }
327  }
328 
329  std::cerr << "Attachments pending: " << attachmentsPending_ << std::endl;
331  setStatus(tr("msg.uploading"), "status");
332  else
333  saved();
334  }
335 }
336 
338 {
339  if (saving_) {
341  std::cerr << "Attachments still: " << attachmentsPending_ << std::endl;
342 
343  if (attachmentsPending_ == 0)
344  saved();
345  }
346 }
347 
348 void Composer::setStatus(const WString& text, const WString& style)
349 {
350  statusMsg_->setText(text);
351  statusMsg_->setStyleClass(style);
352 }
353 
355 {
356  /*
357  * All attachments have been processed.
358  */
359 
360  bool attachmentsFailed = false;
361  for (unsigned i = 0; i < attachments_.size() - 1; ++i)
362  if (attachments_[i]->uploadFailed()) {
363  attachmentsFailed = true;
364  break;
365  }
366 
367  if (attachmentsFailed) {
368  setStatus(tr("msg.attachment.failed"), "error");
369  } else {
370 #ifndef WIN32
371  time_t t = time(0);
372  struct tm td;
373  gmtime_r(&t, &td);
374  char buffer[100];
375  strftime(buffer, 100, "%H:%M", &td);
376 #else
377  char buffer[] = "server"; // Should fix this; for now just make sense
378 #endif
379  setStatus(tr("msg.ok"), "status");
380  statusMsg_->setText(std::string("Draft saved at ") + buffer);
381 
382  if (sending_) {
383  send.emit();
384  return;
385  }
386  }
387 
388  saving_ = false;
389  sending_ = false;
390 }
391 
393 {
394  discard.emit();
395 }
virtual void insertBefore(std::unique_ptr< WWidget > widget, WWidget *before)
virtual void setStyleClass(const WString &styleClass) override
void createUi()
Definition: Composer.C:97
A clickable option.
Definition: Option.h:31
void forEdit(WFormWidget *edit, WFlags< PopupTrigger > popupTriggers=PopupTrigger::Editing)
AddresseeEdit * bccEdit_
Bcc: Addressees edit.
Definition: Composer.h:113
virtual void setText(const WString &text)
std::vector< Contact > to() const
Get the To: contacts.
Definition: Composer.C:54
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
void discardIt()
Slot attached to the Discard button.
Definition: Composer.C:392
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)
const WString & text() const
void emit(A...args) const
Composer()
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:354
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
std::vector< Contact > cc() const
Get the Cc: contacts.
Definition: Composer.C:59
const WString & subject() const
Get the subject.
Definition: Composer.C:74
void setContentAlignment(WFlags< AlignmentFlag > contentAlignment)
Wt::Signal send
The message is ready to be sent...
Definition: Composer.h:93
void setSubject(const WString &subject)
Set subject.
Definition: Composer.C:44
void removeAttachment(AttachmentEdit *attachment)
Remove the given attachment edit.
Definition: Composer.C:270
bool setText(const WString &text)
Wt::Signals::connection connect(const F &function)
void saveNow()
Slot attached to the Save now button.
Definition: Composer.C:308
void update()
Updates the stateless implementations after an Option has been hidden or shown.
Definition: OptionList.C:31
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
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:295
void setAddressBook(const std::vector< Contact > &addressBook)
Set the address book, for autocomplete suggestions.
Definition: Composer.C:69
void setAddressees(const std::vector< Contact > &contacts)
Set a list of addressees.
Definition: AddresseeEdit.C:27
void setColumns(int cols)
std::vector< Contact > bcc() const
Get the Bc: contacts.
Definition: Composer.C:64
virtual void setText(const WString &text)
WPushButton * botDiscardButton_
Definition: Composer.h:103
const WString & message() const
Get the message.
Definition: Composer.C:92
const WString & text() const
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< Attachment > attachments() const
Get the list of attachments.
Definition: Composer.C:79
WPushButton * topSaveNowButton_
Definition: Composer.h:102
std::unique_ptr< WWidget > removeFromParent()
WLineEdit * subject_
The subject line edit.
Definition: Composer.h:119
Wt::Signal discard
The message must be discarded.
Definition: Composer.h:97
virtual void resize(const WLength &width, const WLength &height) override
WPushButton * topSendButton_
Definition: Composer.h:102
void add(std::unique_ptr< Option > option)
Add an Option to the list.
Definition: OptionList.C:18
void attachmentDone()
Slotcalled when an attachment has been uploaded.
Definition: Composer.C:337
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:49
void setTo(const std::vector< Contact > &to)
Set message To: contacts.
Definition: Composer.C:39
void attachMore()
Add an attachment edit.
Definition: Composer.C:253
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
std::vector< Contact > addressees() const
Get a list of addressees.
Definition: AddresseeEdit.C:74
bool sending_
Definition: Composer.h:140
virtual void addWidget(std::unique_ptr< WWidget > widget)
void setStatus(const WString &text, const WString &style)
Set the status, and apply the given style.
Definition: Composer.C:348

Generated on Mon Sep 4 2017 for the C++ Web Toolkit (Wt) by doxygen 1.8.11