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

Generated on Mon Jul 11 2022 for the C++ Web Toolkit (Wt) by doxygen 1.9.4