1 /*
2  * Add contact dialog
3  *
4  * Copyright (C) 2011 David Edmundson <kde@davidedmundson.co.uk>
5  * Copyright (C) 2012 George Kiagiadakis <kiagiadakis.george@gmail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include "add-contact-dialog.h"
23 #include "ui_add-contact-dialog.h"
24 #include "debug.h"
25 
26 #include <KTp/types.h>
27 
28 #include <QObject>
29 #include <QCloseEvent>
30 #include <QDialogButtonBox>
31 
32 #include <KMessageBox>
33 #include <KLocalizedString>
34 
35 #include <TelepathyQt/AccountManager>
36 #include <TelepathyQt/Account>
37 #include <TelepathyQt/Connection>
38 #include <TelepathyQt/ContactManager>
39 #include <TelepathyQt/PendingContacts>
40 #include <TelepathyQt/Filter>
41 #include <TelepathyQt/AccountSet>
42 #include <TelepathyQt/PendingReady>
43 
44 namespace KTp {
45 
46 class KTPCOMMONINTERNALS_NO_EXPORT SubscribableAccountFilter : public Tp::AccountFilter
47 {
48 public:
SubscribableAccountFilter()49     SubscribableAccountFilter() : Tp::AccountFilter()
50     {
51     }
52 
isValid() const53     bool isValid() const override
54     {
55         //return whether the filter is valid which is always true as this filter is hardcoded
56         return true;
57     }
58 
matches(const Tp::AccountPtr & account) const59     bool matches(const Tp::AccountPtr &account) const override
60     {
61         //if there's no connection we can't add contacts as we have no contactmanager
62         if (! account->connection()) {
63             return false;
64         }
65 
66         //only show items which can add a contact (i.e hide accounts like IRC which are online but there's no point listing)
67         if (! account->connection()->contactManager()->canRequestPresenceSubscription()){
68             return false;
69         }
70         return true;
71     }
72 };
73 
74 
75 struct KTPCOMMONINTERNALS_NO_EXPORT AddContactDialog::Private
76 {
PrivateKTp::AddContactDialog::Private77     Private() :
78         ui(new Ui::AddContactDialog),
79         acceptInProgress(false)
80     {}
81 
82     Ui::AddContactDialog *ui;
83     bool acceptInProgress;
84     QDialogButtonBox *buttonBox;
85 };
86 
AddContactDialog(const Tp::AccountManagerPtr & accountManager,QWidget * parent)87 AddContactDialog::AddContactDialog(const Tp::AccountManagerPtr &accountManager, QWidget *parent) :
88     QDialog(parent),
89     d(new Private)
90 {
91     setWindowTitle(i18n("Add new contact"));
92     setWindowIcon(QIcon::fromTheme(QLatin1String("list-add-user")));
93 
94     QWidget *widget = new QWidget(this);
95     d->ui->setupUi(widget);
96 
97     d->buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
98     connect(d->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
99     connect(d->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
100 
101 
102     QVBoxLayout *mainLayout = new QVBoxLayout(this);
103     mainLayout->addWidget(widget);
104     mainLayout->addWidget(d->buttonBox);
105 
106     setLayout(mainLayout);
107 
108     Tp::AccountFilterPtr filter = Tp::AccountFilterPtr(new KTp::SubscribableAccountFilter());
109     Tp::AccountSetPtr accountSet = accountManager->filterAccounts(filter);
110 
111     d->ui->accountCombo->setAccountSet(accountSet);
112     updateSubscriptionMessageVisibility();
113 
114     connect(d->ui->accountCombo, SIGNAL(currentIndexChanged(int)), SLOT(updateSubscriptionMessageVisibility()));
115 
116     //bodge.
117     //Wtih KPeople support we don't enable FeatureRoster
118     //We need FeatureRoster in order to determine canRequestPresenceSubscription();
119     //so we upgrade any accounts here
120 
121     //See https://bugs.kde.org/show_bug.cgi?id=324698
122     Q_FOREACH(const Tp::AccountPtr &account, accountManager->allAccounts()) {
123         if (account->connection()) {
124             Tp::PendingOperation *op = account->connection()->becomeReady(Tp::Connection::FeatureRoster);
125             op->setProperty("account", QVariant::fromValue<Tp::AccountPtr>(account));
126             connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(_k_onAccountUpgraded(Tp::PendingOperation*)));
127         }
128     }
129     //end bodge
130 
131     d->ui->screenNameLineEdit->setFocus();
132 }
133 
~AddContactDialog()134 AddContactDialog::~AddContactDialog()
135 {
136     delete d->ui;
137     delete d;
138 }
139 
140 //bodge
_k_onAccountUpgraded(Tp::PendingOperation * op)141 void AddContactDialog::_k_onAccountUpgraded(Tp::PendingOperation* op)
142 {
143     const Tp::AccountPtr &account = op->property("account").value<Tp::AccountPtr>();
144     //pretend the account changed.
145     //emit that the account properties have changed to invalidate the filter
146     QMetaObject::invokeMethod(account.data(), "propertyChanged", Q_ARG(QString, QString()));
147 }
148 //end bodge
149 
accept()150 void AddContactDialog::accept()
151 {
152     Tp::AccountPtr account = d->ui->accountCombo->currentAccount();
153 
154     if (account.isNull()) {
155         KMessageBox::sorry(this, i18n("No account selected."));
156     } else if (account->connection().isNull()) {
157         KMessageBox::sorry(this, i18n("The requested account has been disconnected "
158                                       "and so the contact could not be added."));
159     } else if (d->ui->screenNameLineEdit->text().isEmpty()) {
160         KMessageBox::sorry(this, i18n("You did not specify the name of the contact to add."));
161     } else {
162         QStringList identifiers = QStringList() << d->ui->screenNameLineEdit->text();
163         qCDebug(KTP_WIDGETS) << "Requesting contacts for identifiers:" << identifiers;
164 
165         Tp::PendingContacts *pendingContacts = account->connection()->contactManager()->contactsForIdentifiers(identifiers);
166         connect(pendingContacts, SIGNAL(finished(Tp::PendingOperation*)),
167                 this, SLOT(_k_onContactsForIdentifiersFinished(Tp::PendingOperation*)));
168 
169         setInProgress(true);
170     }
171 }
172 
closeEvent(QCloseEvent * e)173 void AddContactDialog::closeEvent(QCloseEvent *e)
174 {
175     // ignore close event if we are in the middle of an operation
176     if (!d->acceptInProgress) {
177         QDialog::closeEvent(e);
178     }
179 }
180 
_k_onContactsForIdentifiersFinished(Tp::PendingOperation * op)181 void AddContactDialog::_k_onContactsForIdentifiersFinished(Tp::PendingOperation *op)
182 {
183     if (op->isError()) {
184         qWarning() << "Failed to retrieve a contact for the given identifier"
185                    << op->errorName() << op->errorMessage();
186         KMessageBox::sorry(this, i18n("Failed to create new contact."));
187         setInProgress(false);
188     } else {
189         qCDebug(KTP_WIDGETS) << "Requesting presence subscription";
190 
191         Tp::PendingContacts *pc = qobject_cast<Tp::PendingContacts*>(op);
192         connect(pc->manager()->requestPresenceSubscription(pc->contacts(), d->ui->messageLineEdit->text()),
193                 SIGNAL(finished(Tp::PendingOperation*)),
194                 SLOT(_k_onRequestPresenceSubscriptionFinished(Tp::PendingOperation*)));
195     }
196 }
197 
_k_onRequestPresenceSubscriptionFinished(Tp::PendingOperation * op)198 void AddContactDialog::_k_onRequestPresenceSubscriptionFinished(Tp::PendingOperation *op)
199 {
200     if (op->isError()) {
201         qWarning() << "Failed to request presence subscription"
202                    << op->errorName() << op->errorMessage();
203         KMessageBox::sorry(this, i18n("Failed to request presence subscription "
204                                       "from the requested contact."));
205         setInProgress(false);
206     } else {
207         QDialog::accept();
208     }
209 }
210 
updateSubscriptionMessageVisibility()211 void AddContactDialog::updateSubscriptionMessageVisibility()
212 {
213     Tp::AccountPtr account = d->ui->accountCombo->currentAccount();
214     if (account && account->connection()->contactManager()->subscriptionRequestHasMessage()) {
215         d->ui->messageLineEdit->show();
216         d->ui->messageLineLabel->show();
217     } else {
218         d->ui->messageLineEdit->hide();
219         d->ui->messageLineLabel->hide();
220     }
221 }
222 
setInProgress(bool inProgress)223 void AddContactDialog::setInProgress(bool inProgress)
224 {
225     d->acceptInProgress = inProgress;
226     layout()->parentWidget()->setEnabled(!inProgress);
227     d->buttonBox->setEnabled(!inProgress);
228 }
229 
230 } //namespace KTp
231