1 /*
2 This file is part of Choqok, the KDE micro-blogging client
3 
4 Copyright (C) 2008-2012 Mehrdad Momeny <mehrdad.momeny@gmail.com>
5 
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of
9 the License or (at your option) version 3 or any later version
10 accepted by the membership of KDE e.V. (or its successor approved
11 by the membership of KDE e.V.), which shall act as a proxy
12 defined in Section 14 of version 3 of the license.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, see http://www.gnu.org/licenses/
21 */
22 #include "composerwidget.h"
23 
24 #include <QGridLayout>
25 #include <QLabel>
26 #include <QPointer>
27 #include <QPushButton>
28 
29 #include "account.h"
30 #include "choqoktextedit.h"
31 #include "libchoqokdebug.h"
32 #include "microblog.h"
33 #include "notifymanager.h"
34 #include "shortenmanager.h"
35 
36 namespace Choqok
37 {
38 namespace UI
39 {
40 
41 class ComposerWidget::Private
42 {
43 public:
Private(Account * account)44     Private(Account *account)
45         : editor(nullptr), currentAccount(account), postToSubmit(nullptr)
46     {}
47     QPointer<TextEdit> editor;
48     Account *currentAccount;
49     Choqok::Post *postToSubmit;
50     QWidget *editorContainer;
51     QPointer<QLabel> replyToUsernameLabel;
52     QPointer<QPushButton> btnCancelReply;
53 };
54 
ComposerWidget(Choqok::Account * account,QWidget * parent)55 ComposerWidget::ComposerWidget(Choqok::Account *account, QWidget *parent /*= 0*/)
56     : QWidget(parent), btnAbort(nullptr), d(new Private(account))
57 {
58     QVBoxLayout *layout = new QVBoxLayout(this);
59     layout->setContentsMargins(0, 0, 0, 0);
60     d->editorContainer = new QWidget(this);
61     QGridLayout *internalLayout = new QGridLayout;
62     internalLayout->setContentsMargins(0, 0, 0, 0);
63     d->editorContainer->setLayout(internalLayout);
64     layout->addWidget(editorContainer());
65     setEditor(new TextEdit(account->postCharLimit(), this));
66 
67     d->replyToUsernameLabel = new QLabel(editorContainer());
68     d->btnCancelReply = new QPushButton(editorContainer());
69     d->btnCancelReply->setIcon(QIcon::fromTheme(QLatin1String("dialog-cancel")));
70     d->btnCancelReply->setToolTip(i18n("Discard Reply"));
71     d->btnCancelReply->setMaximumWidth(d->btnCancelReply->height());
72     connect(d->btnCancelReply, &QPushButton::clicked, this, &ComposerWidget::editorCleared);
73     internalLayout->addWidget(d->replyToUsernameLabel, 2, 0);
74     internalLayout->addWidget(d->btnCancelReply, 2, 1);
75 
76     d->btnCancelReply->hide();
77     d->replyToUsernameLabel->hide();
78 }
79 
~ComposerWidget()80 ComposerWidget::~ComposerWidget()
81 {
82     delete d;
83 }
84 
setEditor(TextEdit * editor)85 void ComposerWidget::setEditor(TextEdit *editor)
86 {
87     qCDebug(CHOQOK);
88     if (d->editor) {
89         d->editor->deleteLater();
90     }
91     d->editor = editor;
92     qCDebug(CHOQOK);
93     if (d->editor) {
94         QGridLayout *internalLayout = qobject_cast<QGridLayout *>(d->editorContainer->layout());
95         internalLayout->addWidget(d->editor, 0, 0);
96         connect(d->editor, &TextEdit::returnPressed, this, &ComposerWidget::submitPost);
97         connect(d->editor, &TextEdit::textChanged, this, &ComposerWidget::editorTextChanged);
98         connect(d->editor, &TextEdit::cleared, this, &ComposerWidget::editorCleared);
99         editorTextChanged();
100     } else {
101         qCDebug(CHOQOK) << "Editor is NULL!";
102     }
103 }
104 
setText(const QString & text,const QString & replyToId,const QString & replyToUsername)105 void ComposerWidget::setText(const QString &text, const QString &replyToId, const QString &replyToUsername)
106 {
107     d->editor->prependText(text);
108     this->replyToId = replyToId;
109     this->replyToUsername = replyToUsername;
110     if (!replyToUsername.isEmpty()) {
111         d->replyToUsernameLabel->setText(i18n("Replying to <b>%1</b>", replyToUsername));
112         d->btnCancelReply->show();
113         d->replyToUsernameLabel->show();
114     }
115     d->editor->setFocus();
116 }
117 
submitPost(const QString & txt)118 void ComposerWidget::submitPost(const QString &txt)
119 {
120     qCDebug(CHOQOK);
121     editorContainer()->setEnabled(false);
122     QString text = txt;
123     if (currentAccount()->postCharLimit() &&
124             text.size() > (int)currentAccount()->postCharLimit()) {
125         text = Choqok::ShortenManager::self()->parseText(text);
126     }
127     delete d->postToSubmit;
128     d->postToSubmit = new Choqok::Post;
129     d->postToSubmit->content = text;
130     if (!replyToId.isEmpty()) {
131         d->postToSubmit->replyToPostId = replyToId;
132     }
133     connect(d->currentAccount->microblog(), &MicroBlog::postCreated,
134             this, &ComposerWidget::slotPostSubmited);
135     connect(d->currentAccount->microblog(), &MicroBlog::errorPost,
136             this, &ComposerWidget::slotErrorPost);
137     btnAbort = new QPushButton(QIcon::fromTheme(QLatin1String("dialog-cancel")), i18n("Abort"), this);
138     layout()->addWidget(btnAbort);
139     connect(btnAbort, &QPushButton::clicked, this, &ComposerWidget::abort);
140     currentAccount()->microblog()->createPost(currentAccount(), d->postToSubmit);
141 }
142 
slotPostSubmited(Choqok::Account * theAccount,Choqok::Post * post)143 void ComposerWidget::slotPostSubmited(Choqok::Account *theAccount, Choqok::Post *post)
144 {
145     qCDebug(CHOQOK);
146     if (currentAccount() == theAccount && post == d->postToSubmit) {
147         qCDebug(CHOQOK) << "Accepted";
148         disconnect(d->currentAccount->microblog(), &MicroBlog::postCreated,
149                    this, &ComposerWidget::slotPostSubmited);
150         disconnect(d->currentAccount->microblog(), &MicroBlog::errorPost,
151                    this, &ComposerWidget::slotErrorPost);
152         if (btnAbort) {
153             btnAbort->deleteLater();
154         }
155         d->editor->clear();
156         editorCleared();
157         editorContainer()->setEnabled(true);
158         delete d->postToSubmit;
159         d->postToSubmit = nullptr;
160         currentAccount()->microblog()->updateTimelines(currentAccount());
161     }
162 }
163 
slotErrorPost(Account * theAccount,Post * post)164 void ComposerWidget::slotErrorPost(Account *theAccount, Post *post)
165 {
166     qCDebug(CHOQOK);
167     if (theAccount == d->currentAccount && post == d->postToSubmit) {
168         qCDebug(CHOQOK);
169         disconnect(d->currentAccount->microblog(), &MicroBlog::postCreated,
170                    this, &ComposerWidget::slotPostSubmited);
171         disconnect(d->currentAccount->microblog(), &MicroBlog::errorPost,
172                    this, &ComposerWidget::slotErrorPost);
173         if (btnAbort) {
174             btnAbort->deleteLater();
175         }
176         editorContainer()->setEnabled(true);
177         editor()->setFocus();
178     }
179 }
180 
editorTextChanged()181 void ComposerWidget::editorTextChanged()
182 {
183     if (d->editor->toPlainText().length()) {
184         d->editor->setMaximumHeight(qMax(d->editor->fontMetrics().height() * 3,
185                                          80));
186         d->editor->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
187     } else {
188         d->editor->setMaximumHeight(qMax(d->editor->fontMetrics().height(),
189                                          30));
190         d->editor->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
191     }
192 }
193 
editor()194 TextEdit *ComposerWidget::editor()
195 {
196     return d->editor;
197 }
198 
editorContainer()199 QWidget *ComposerWidget::editorContainer()
200 {
201     return d->editorContainer;
202 }
203 
postToSubmit()204 Post *ComposerWidget::postToSubmit()
205 {
206     return d->postToSubmit;
207 }
208 
setPostToSubmit(Post * post)209 void ComposerWidget::setPostToSubmit(Post *post)
210 {
211     delete d->postToSubmit;
212     d->postToSubmit = post;
213 }
214 
btnCancelReply()215 QPointer< QPushButton > ComposerWidget::btnCancelReply()
216 {
217     return d->btnCancelReply;
218 }
219 
currentAccount()220 Account *ComposerWidget::currentAccount()
221 {
222     return d->currentAccount;
223 }
224 
replyToUsernameLabel()225 QPointer< QLabel > ComposerWidget::replyToUsernameLabel()
226 {
227     return d->replyToUsernameLabel;
228 }
229 
editorCleared()230 void ComposerWidget::editorCleared()
231 {
232     replyToId.clear();
233     replyToUsername.clear();
234     d->btnCancelReply->hide();
235     d->replyToUsernameLabel->hide();
236 }
237 
abort()238 void ComposerWidget::abort()
239 {
240     if (btnAbort) {
241         btnAbort->deleteLater();
242     }
243     editorContainer()->setEnabled(true);
244     currentAccount()->microblog()->abortCreatePost(currentAccount(), d->postToSubmit);
245     editor()->setFocus();
246 }
247 
248 }
249 }
250