2 Copyright 2013-2015 Mats Sjöberg
4 This file is part of the Pumpa programme.
6 Pumpa is free software: you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 Pumpa is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Pumpa. If not, see <http://www.gnu.org/licenses/>.
20 #include "messagewindow.h"
21 #include "pumpa_defines.h"
22 #include "pumpasettings.h"
25 #include <QFileDialog>
26 #include <QMessageBox>
27 #include <QInputDialog>
29 //------------------------------------------------------------------------------
31 const int max_picture_size
= 160;
33 //------------------------------------------------------------------------------
35 PictureLabel::PictureLabel(QWidget
* parent
) : QLabel(parent
) {}
37 //------------------------------------------------------------------------------
39 void PictureLabel::setOriginalPixmap(QPixmap p
) {
44 //------------------------------------------------------------------------------
46 void PictureLabel::resizeEvent(QResizeEvent
* event
) {
47 if (m_originalPixmap
.isNull())
50 QSize size
= event
->size();
51 setPixmap(m_originalPixmap
.scaled(size
, Qt::KeepAspectRatio
));
54 //------------------------------------------------------------------------------
56 MessageWindow::MessageWindow(PumpaSettings
* s
, const RecipientList
* rl
,
59 m_addressLayout(NULL
),
66 setMinimumSize(QSize(400,400));
67 setWindowTitle(CLIENT_FANCY_NAME
);
69 m_infoLabel
= new QLabel(this);
71 m_markdownCheckBox
= new QCheckBox(tr("Use Markdown"), this);
72 connect(m_markdownCheckBox
, SIGNAL(stateChanged(int)),
73 this, SLOT(onMarkdownChecked(int)));
75 m_markupLabel
= new QLabel(this);
76 m_markupLabel
->setText(QString("<a href=\"%2\">" + tr("[help]") + "</a>").
78 m_markupLabel
->setOpenExternalLinks(true);
79 m_markupLabel
->setTextInteractionFlags(Qt::TextSelectableByMouse
|
80 Qt::LinksAccessibleByMouse
);
82 m_infoLayout
= new QHBoxLayout
;
83 m_infoLayout
->addWidget(m_infoLabel
);
84 m_infoLayout
->addStretch();
85 m_infoLayout
->addWidget(m_markdownCheckBox
);
86 m_infoLayout
->addWidget(m_markupLabel
);
88 m_toRecipients
= new MessageRecipients(this);
89 m_ccRecipients
= new MessageRecipients(this);
91 m_toLabel
= new QLabel(tr("To:"), this);
92 m_ccLabel
= new QLabel(tr("Cc:"), this);
94 m_addressLayout
= new QFormLayout
;
95 m_addressLayout
->addRow(m_toLabel
, m_toRecipients
);
96 m_addressLayout
->addRow(m_ccLabel
, m_ccRecipients
);
97 m_addressLayout
->setContentsMargins(0, 0, 0, 0);
99 m_addPictureButton
= new TextToolButton(this);
100 connect(m_addPictureButton
, SIGNAL(clicked()), this, SLOT(onAddPicture()));
102 m_removePictureButton
= new TextToolButton(tr("&Remove picture"), this);
103 connect(m_removePictureButton
, SIGNAL(clicked()),
104 this, SLOT(onRemovePicture()));
106 m_addToButton
= new TextToolButton(tr("+ &To"), this);
107 connect(m_addToButton
, SIGNAL(clicked()), this, SLOT(onAddTo()));
109 m_addCcButton
= new TextToolButton(tr("+ &Cc"), this);
110 connect(m_addCcButton
, SIGNAL(clicked()), this, SLOT(onAddCc()));
112 m_pictureButtonLayout
= new QHBoxLayout
;
113 m_pictureButtonLayout
->addWidget(m_addPictureButton
, 0, Qt::AlignTop
);
114 m_pictureButtonLayout
->addWidget(m_removePictureButton
, 0, Qt::AlignTop
);
115 m_pictureButtonLayout
->addStretch();
116 m_pictureButtonLayout
->addWidget(m_addToButton
, 0, Qt::AlignTop
);
117 m_pictureButtonLayout
->addWidget(m_addCcButton
, 0, Qt::AlignTop
);
119 m_pictureLabel
= new PictureLabel(this);
120 // m_pictureLabel->setScaledContents(true);
121 m_pictureLabel
->setMaximumSize(max_picture_size
, max_picture_size
);
122 m_pictureLabel
->setFocusPolicy(Qt::NoFocus
);
123 m_pictureLabel
->setFrameStyle(QFrame::Panel
| QFrame::Sunken
);
125 m_title
= new QLineEdit(this);
126 #if QT_VERSION >= 0x040700
127 m_title
->setPlaceholderText(tr("Title (optional)"));
129 connect(m_title
, SIGNAL(textChanged(const QString
&)),
130 this, SLOT(updatePreview()));
132 m_textEdit
= new MessageEdit(m_s
, this);
133 connect(m_textEdit
, SIGNAL(ready()), this, SLOT(accept()));
134 connect(m_textEdit
, SIGNAL(textChanged()), this, SLOT(updatePreview()));
135 connect(m_textEdit
, SIGNAL(addRecipient(QASActor
*)),
136 this, SLOT(onAddRecipient(QASActor
*)));
138 m_previewLabel
= new RichTextLabel
;
139 m_previewLabel
->setSizePolicy(QSizePolicy::Ignored
,
140 QSizePolicy::Maximum
);
141 m_previewArea
= new QScrollArea(this);
142 m_previewArea
->setWidget(m_previewLabel
);
144 m_previewArea
->setWidgetResizable(true);
146 m_charCountLabel
= new QLabel(this);
148 QWidget
* qw
= new QWidget(this);
149 QVBoxLayout
* qwLayout
= new QVBoxLayout
;
150 qwLayout
->addWidget(m_textEdit
);
151 qwLayout
->addWidget(m_charCountLabel
);
152 qwLayout
->setMargin(0);
153 qw
->setLayout(qwLayout
);
155 m_splitter
= new QSplitter(Qt::Vertical
, this);
156 m_splitter
->addWidget(qw
);
157 m_splitter
->addWidget(m_previewArea
);
158 m_splitter
->setChildrenCollapsible(false);
160 m_layout
= new QVBoxLayout
;
161 m_layout
->addLayout(m_infoLayout
);
162 m_layout
->addLayout(m_addressLayout
);
163 m_layout
->addLayout(m_pictureButtonLayout
);
164 m_layout
->addWidget(m_pictureLabel
, 0, Qt::AlignHCenter
);
165 m_layout
->addWidget(m_title
);
166 m_layout
->addWidget(m_splitter
);
168 m_cancelButton
= new QPushButton(tr("Ca&ncel"));
169 connect(m_cancelButton
, SIGNAL(clicked()), this, SLOT(reject()));
171 m_previewButton
= new QPushButton(tr("&Preview"));
172 connect(m_previewButton
, SIGNAL(clicked()), this, SLOT(togglePreview()));
174 m_sendButton
= new QPushButton(tr("&Send message"));
175 connect(m_sendButton
, SIGNAL(clicked()), this, SLOT(accept()));
176 m_sendButton
->setDefault(true);
178 m_buttonLayout
= new QHBoxLayout
;
179 m_buttonLayout
->addWidget(m_cancelButton
);
180 m_buttonLayout
->addWidget(m_previewButton
);
181 m_buttonLayout
->addWidget(m_sendButton
);
182 m_layout
->addLayout(m_buttonLayout
);
186 m_textEdit
->setFocus(Qt::OtherFocusReason
);
188 QTextCursor cursor
= m_textEdit
->textCursor();
189 cursor
.movePosition(QTextCursor::End
);
190 m_textEdit
->setTextCursor(cursor
);
193 //------------------------------------------------------------------------------
195 void MessageWindow::onMarkdownChecked(int state
) {
197 if (state
== Qt::Unchecked
) {
198 m_s
->useMarkdown(false);
200 m_s
->useMarkdown(true);
206 //------------------------------------------------------------------------------
208 void MessageWindow::setCompletions(const MessageEdit::completion_t
*
211 m_textEdit
->setCompletions(completions
);
214 //------------------------------------------------------------------------------
216 void MessageWindow::addToRecipientList(QString name
, QASObject
* obj
) {
217 m_recipientList
.append(name
);
218 if (!m_recipientSelection
.contains(name
))
219 m_recipientSelection
.insert(name
, obj
);
222 //------------------------------------------------------------------------------
224 void MessageWindow::addRecipientWindow(MessageRecipients
* mr
, QString title
) {
225 QInputDialog
* dialog
= new QInputDialog(this);
226 // dialog->setOption(QInputDialog::UseListViewForComboBoxItems);
227 dialog
->setComboBoxItems(m_recipientList
);
228 dialog
->setComboBoxEditable(true);
229 dialog
->setLabelText(title
);
230 dialog
->setInputMode(QInputDialog::TextInput
);
231 dialog
->setWindowTitle(CLIENT_FANCY_NAME
);
235 if (dialog
->result() == QDialog::Accepted
) {
236 QString text
= dialog
->textValue();
237 if (m_recipientSelection
.contains(text
))
238 mr
->addRecipient(m_recipientSelection
[text
]);
242 //------------------------------------------------------------------------------
244 void MessageWindow::onAddTo() {
245 addRecipientWindow(m_toRecipients
, tr("Select recipient (To)"));
248 //------------------------------------------------------------------------------
250 void MessageWindow::onAddCc() {
251 addRecipientWindow(m_ccRecipients
, tr("Select recipient (Cc)"));
254 //------------------------------------------------------------------------------
256 void MessageWindow::onAddRecipient(QASActor
* actor
) {
257 m_toRecipients
->addRecipient(actor
);
260 //------------------------------------------------------------------------------
262 void MessageWindow::initWindow(QString title
, QString buttonText
,
263 bool showRecipients
) {
264 setWindowTitle(QString(CLIENT_FANCY_NAME
) + " - " + title
);
265 m_infoLabel
->setText(title
);
267 m_sendButton
->setText(buttonText
);
269 m_markdownCheckBox
->setChecked(m_s
->useMarkdown() || m_editing
);
271 m_previewArea
->setVisible(m_s
->showPreview());
273 m_toRecipients
->setVisible(showRecipients
);
274 m_ccRecipients
->setVisible(showRecipients
);
275 m_toLabel
->setVisible(showRecipients
);
276 m_ccLabel
->setVisible(showRecipients
);
277 m_addToButton
->setVisible(showRecipients
);
278 m_addCcButton
->setVisible(showRecipients
);
280 m_charCountLabel
->setVisible(m_s
->showCharCount());
286 //------------------------------------------------------------------------------
288 void MessageWindow::newMessage(QASObject
* obj
, QASObjectList
* to
,
295 QASObject
* origObj
= obj
;
296 if (obj
&& !m_s
->commentOnComments() && obj
->inReplyTo())
297 obj
= obj
->inReplyTo();
299 m_isReply
= (obj
!= NULL
);
305 QString title
= m_isReply
? tr("Post a reply") : tr("Post a note");
306 QString buttonText
= m_isReply
? tr("&Send comment") : tr("&Send post");
308 initWindow(title
, buttonText
, true);
310 m_recipientList
.clear();
311 for (int i
=0; i
<m_rl
->size(); ++i
) {
312 QASObject
* obj
= m_rl
->at(i
);
313 addToRecipientList(obj
->displayName() + " (list)", obj
);
316 m_markdownCheckBox
->setEnabled(true);
318 const MessageEdit::completion_t
* completions
= m_textEdit
->getCompletions();
319 MessageEdit::completion_t::const_iterator it
= completions
->constBegin();
320 for (; it
!= completions
->constEnd(); ++it
)
321 addToRecipientList(it
.key(), it
.value());
324 // A new post, use default recipients
325 setDefaultRecipients(m_toRecipients
, m_s
->defaultToAddress());
326 setDefaultRecipients(m_ccRecipients
, m_s
->defaultCcAddress());
328 // For a reply, copy recipients from parent
329 copyRecipients(m_toRecipients
, to
);
330 copyRecipients(m_ccRecipients
, cc
);
332 // add original post author to recipients
333 if (obj
->author() && !obj
->author()->isYou())
334 m_toRecipients
->addRecipient(obj
->author());
336 // if this is a reply to a comment add comment author to
337 // recipients as well
338 if (origObj
!= obj
&& origObj
->author() && !origObj
->author()->isYou())
339 m_toRecipients
->addRecipient(origObj
->author());
343 //------------------------------------------------------------------------------
345 void MessageWindow::editMessage(QASObject
* obj
) {
349 QString type
= obj
->type();
350 m_isReply
= type
== "comment";
352 QString title
= tr("Edit object");
353 // we do this for the sake of easier translation
355 title
= tr("Edit post");
356 else if (type
== "comment")
357 title
= tr("Edit comment");
358 else if (type
== "image")
359 title
= tr("Edit image post");
361 QString buttonText
= tr("&Update object");
362 // we do this for the sake of easier translation
364 buttonText
= tr("&Update post");
365 else if (type
== "comment")
366 buttonText
= tr("&Update comment");
367 else if (type
== "image")
368 buttonText
= tr("&Update image post");
370 m_markdownCheckBox
->setEnabled(false);
372 m_textEdit
->setPlainText(obj
->content());
373 m_title
->setText(obj
->displayName());
375 initWindow(title
, buttonText
, false);
378 //------------------------------------------------------------------------------
380 void MessageWindow::copyRecipients(MessageRecipients
* mr
, QASObjectList
* ol
) {
383 RecipientList rl
= ol
->toRecipientList();
384 for (int i
=0; i
<rl
.size(); ++i
) {
385 QASActor
* actor
= rl
[i
]->asActor();
386 bool isYou
= actor
&& actor
->isYou();
388 if (!isYou
&& !rl
[i
]->type().isEmpty())
389 mr
->addRecipient(rl
[i
]);
394 //------------------------------------------------------------------------------
396 void MessageWindow::setDefaultRecipients(MessageRecipients
* mr
,
399 if (defAddress
== RECIPIENT_PUBLIC
)
400 mr
->addRecipient(m_rl
->at(0));
401 if (defAddress
== RECIPIENT_FOLLOWERS
)
402 mr
->addRecipient(m_rl
->at(1));
405 //------------------------------------------------------------------------------
407 void MessageWindow::clear() {
408 m_imageFileName
= "";
411 m_previewLabel
->setText("");
414 //------------------------------------------------------------------------------
416 void MessageWindow::showEvent(QShowEvent
*) {
417 m_textEdit
->setFocus(Qt::OtherFocusReason
);
418 m_textEdit
->selectAll();
422 //------------------------------------------------------------------------------
424 void MessageWindow::accept() {
425 m_textEdit
->hideCompletion();
426 QString msg
= m_textEdit
->toPlainText();
428 RecipientList to
= m_toRecipients
->recipients();
429 RecipientList cc
= m_ccRecipients
->recipients();
431 QString title
= m_title
->text();
434 emit
sendEdit(m_obj
, msg
, title
);
435 } else if (m_isReply
) {
436 emit
sendReply(m_obj
, msg
, to
, cc
);
438 if (m_imageFileName
.isEmpty()) {
439 emit
sendMessage(msg
, title
, to
, cc
);
441 emit
sendImage(msg
, title
, m_imageFileName
, to
, cc
);
447 //------------------------------------------------------------------------------
449 void MessageWindow::onAddPicture() {
451 QFileDialog::getOpenFileName(this, tr("Select Image"), "",
452 tr("Image files (*.png *.jpg *.jpeg *.gif)"
453 ";;All files (*.*)"));
455 if (!fileName
.isEmpty()) {
456 m_imageFileName
= fileName
;
461 //------------------------------------------------------------------------------
463 void MessageWindow::onRemovePicture() {
464 m_imageFileName
= "";
468 //------------------------------------------------------------------------------
470 void MessageWindow::updateAddPicture() {
471 if (m_isReply
|| m_editing
) {
472 m_addPictureButton
->setVisible(false);
473 m_removePictureButton
->setVisible(false);
474 m_pictureLabel
->setVisible(false);
475 m_title
->setVisible(!m_isReply
);
476 m_removePictureButton
->setVisible(false);
481 if (!m_imageFileName
.isEmpty()) {
482 p
.load(m_imageFileName
);
484 QMessageBox::critical(this, tr("Sorry!"),
485 tr("That file didn't appear to be an image."));
486 m_imageFileName
= "";
490 m_addPictureButton
->setVisible(true);
491 m_title
->setVisible(true);
492 if (m_imageFileName
.isEmpty()) {
493 m_addPictureButton
->setText(tr("&Add picture"));
494 m_removePictureButton
->setVisible(false);
495 m_pictureLabel
->setVisible(false);
497 QPixmap scaledPixmap
= p
.scaled(max_picture_size
,
499 Qt::KeepAspectRatio
);
500 m_pictureLabel
->setOriginalPixmap(scaledPixmap
);
501 m_addPictureButton
->setText(tr("&Change picture"));
502 m_removePictureButton
->setVisible(true);
503 m_pictureLabel
->setVisible(true);
507 //------------------------------------------------------------------------------
509 void MessageWindow::updatePreview(bool force
) {
510 QString previewText
= addTextMarkup(m_textEdit
->toPlainText(),
511 m_s
->useMarkdown() || m_editing
);
512 if (m_charCountLabel
->isVisible() || force
) {
513 QString strippedText
= previewText
;
514 strippedText
.remove(QRegExp(HTML_TAG_REGEX
));
516 qDebug() << "STRIPPEDTEXT" << strippedText
;
518 QString ccText
= QString(tr("Characters: %1")).arg(strippedText
.count());
519 m_charCountLabel
->setText(ccText
);
522 if (m_previewArea
->isVisible() || force
) {
523 QString titleText
= processTitle(m_title
->text(), true);
524 if (!titleText
.isEmpty())
525 previewText
= "<p><b>" + titleText
+ "</b></p>" + previewText
;
526 m_previewLabel
->setText(previewText
);
530 //------------------------------------------------------------------------------
532 void MessageWindow::togglePreview() {
533 bool visible
= !m_previewArea
->isVisible();
534 m_previewArea
->setVisible(visible
);
535 m_s
->showPreview(visible
);
537 m_textEdit
->setFocus(Qt::OtherFocusReason
);