source: qutecom-2.2/qutecom/src/presentation/qt/profilebar/QtIMProfileWidget.cpp @ 666:2852829a2283

Last change on this file since 666:2852829a2283 was 666:2852829a2283, checked in by laurent, Dmitriy.Trt, 3 years ago

utf8 support

File size: 15.1 KB
Line 
1/*
2 * QuteCom, a voice over Internet phone
3 * Copyright (C) 2010 Mbdsys
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20#include "QtIMProfileWidget.h"
21
22#include "ui_IMProfileWidget.h"
23
24#include "QtIMAccountPresenceMenuManager.h"
25
26#include <presentation/qt/QtIMAccountMonitor.h>
27#include <presentation/qt/QtIMAccountHelper.h>
28#include <presentation/qt/profile/QtProfileDetails.h>
29#include <presentation/qt/imaccount/QtIMAccountManager.h>
30#include <presentation/PFactory.h>
31
32#include <control/CQuteCom.h>
33#include <control/profile/CUserProfile.h>
34#include <control/profile/CUserProfileHandler.h>
35
36#include <model/profile/UserProfile.h>
37
38#include <util/Logger.h>
39#include <util/SafeDelete.h>
40#include <thread/ThreadEvent.h>
41
42#include <qtutil/LanguageChangeEventFilter.h>
43#include <qtutil/SafeConnect.h>
44#include <qtutil/PixmapMerging.h>
45
46#include <QtGui/QHBoxLayout>
47#include <QtGui/QMenu>
48#include <QtGui/QPainter>
49
50#include "imaccount/QtIMAccountSettings.h"
51
52const int ACCOUNT_ICON_WIDTH = 28;
53const int ACCOUNT_ICON_HEIGHT = 22;
54
55static QPixmap createAccountButtonPixmap(EnumIMProtocol::IMProtocol imProtocol, QtIMAccountMonitor::ConnectionState connectionState, EnumPresenceState::PresenceState presenceState) {
56        QString name = ":pics/protocols/";
57
58        // Append protocol name
59        switch (imProtocol) {
60        case EnumIMProtocol::IMProtocolMSN:
61                name += "msn";
62                break;
63
64        case EnumIMProtocol::IMProtocolYahoo:
65                name += "yahoo";
66                break;
67
68        case EnumIMProtocol::IMProtocolAIM:
69                name += "aim";
70                break;
71
72        case EnumIMProtocol::IMProtocolICQ:
73                name += "icq";
74                break;
75
76        case EnumIMProtocol::IMProtocolJabber:
77                name += "jabber";
78                break;
79       
80        case EnumIMProtocol::IMProtocolGoogleTalk:
81                name += "google-talk";
82                break;
83
84        case EnumIMProtocol::IMProtocolQuteCom:
85                name += "qutecom";
86                break;
87
88        case EnumIMProtocol::IMProtocolFaceBook:
89                name += "facebook";
90                break;
91
92        case EnumIMProtocol::IMProtocolMySpace:
93                name += "myspace";
94                break;
95
96        case EnumIMProtocol::IMProtocolSkype:
97                name += "skype";
98                break;
99
100        case EnumIMProtocol::IMProtocolTwitter:
101                name += "twitter";
102                break;
103       
104        case EnumIMProtocol::IMProtocolSIPSIMPLE:
105        case EnumIMProtocol::IMProtocolSIP:
106                name += "sip";
107                break;
108       
109        case EnumIMProtocol::IMProtocolUnknown:
110        case EnumIMProtocol::IMProtocolAll:
111                LOG_FATAL("Protocol should not be " + EnumIMProtocol::toString(imProtocol));
112        }
113
114        // Special cases: Disconnected or failure
115        if (connectionState == QtIMAccountMonitor::StateDisconnected
116                || connectionState == QtIMAccountMonitor::StateFailure) {
117                name += "_off";
118        }
119
120        // Load pix
121        name += ".png";
122        QPixmap protocolPix;
123        if (!protocolPix.load(name)) {
124                LOG_WARN(QString("Could not load icon " + name).toUtf8());
125                return QPixmap();
126        }
127
128        // Load overlay
129        QPixmap overlay;
130        // Append connection state
131        switch (connectionState) {
132        case QtIMAccountMonitor::StateConnected:
133                {
134                        QString presenceString = QString::fromUtf8(EnumPresenceState::toString(presenceState).c_str());
135                        overlay.load(
136                                QString(":pics/protocols/overlay_presence_%1.png").arg(presenceString)
137                                );
138                }
139                break;
140
141        case QtIMAccountMonitor::StateConnecting:
142                overlay.load(":pics/protocols/overlay_progress.png");
143                break;
144
145        case QtIMAccountMonitor::StateFailure:
146                overlay.load(":pics/protocols/overlay_error.png");
147                break;
148
149        case QtIMAccountMonitor::StateDisconnected:
150                break;
151        }
152
153        // Paint overlay
154        QPixmap pix(ACCOUNT_ICON_WIDTH, ACCOUNT_ICON_HEIGHT);
155        pix.fill(QColor(0,0,0,0));
156        QPainter painter(&pix);
157        painter.drawPixmap(pix.width() - protocolPix.width(), 0, protocolPix);
158        if (!overlay.isNull()) {
159                painter.drawPixmap(0, pix.height() - overlay.height(), overlay);
160        }
161        painter.end();
162
163        return pix;
164}
165
166
167QtIMProfileWidget::QtIMProfileWidget(QWidget * parent)
168        : QObject(parent)
169        , _cUserProfile(0)
170        , _qtImAccountMonitor(0) {
171
172        _imProfileWidget = new QWidget(parent);
173
174        _ui = new Ui::IMProfileWidget();
175        _ui->setupUi(_imProfileWidget);
176
177        // Init addIMAccountButton
178        // FIXME: This is copied from QtIMAccountManager ctor and should be
179        // factorized
180#ifdef MULTIIMWRAPPER
181        QMenu * addIMAccountMenu = new QMenu(_ui->addIMAccountButton);
182        SAFE_CONNECT(addIMAccountMenu, SIGNAL(triggered(QAction *)), SLOT(addIMAccount(QAction *)));
183
184        addIMAccountMenu->addAction(QIcon(":pics/protocols/msn.png"),
185                                QtEnumIMProtocol::toString(QtEnumIMProtocol::IMProtocolMSN));
186        addIMAccountMenu->addAction(QIcon(":pics/protocols/aim.png"),
187                                QtEnumIMProtocol::toString(QtEnumIMProtocol::IMProtocolAIM));
188        addIMAccountMenu->addAction(QIcon(":pics/protocols/icq.png"),
189                                QtEnumIMProtocol::toString(QtEnumIMProtocol::IMProtocolICQ));
190        addIMAccountMenu->addAction(QIcon(":pics/protocols/yahoo.png"),
191                                QtEnumIMProtocol::toString(QtEnumIMProtocol::IMProtocolYahoo));
192        addIMAccountMenu->addAction(QIcon(":pics/protocols/jabber.png"),
193                                QtEnumIMProtocol::toString(QtEnumIMProtocol::IMProtocolJabber));
194        addIMAccountMenu->addAction(QIcon(":pics/protocols/google-talk.png"),
195                                QtEnumIMProtocol::toString(QtEnumIMProtocol::IMProtocolGoogleTalk));
196
197        addIMAccountMenu->addAction(QIcon(":pics/protocols/facebook.png"),
198                                QtEnumIMProtocol::toString(QtEnumIMProtocol::IMProtocolFaceBook));
199        addIMAccountMenu->addAction(QIcon(":pics/protocols/myspace.png"),
200                                QtEnumIMProtocol::toString(QtEnumIMProtocol::IMProtocolMySpace));
201        addIMAccountMenu->addAction(QIcon(":pics/protocols/skype.png"),
202                                QtEnumIMProtocol::toString(QtEnumIMProtocol::IMProtocolSkype));
203        addIMAccountMenu->addAction(QIcon(":pics/protocols/twitter.png"),
204                                QtEnumIMProtocol::toString(QtEnumIMProtocol::IMProtocolTwitter));
205
206        _ui->addIMAccountButton->setPopupMode(QToolButton::InstantPopup);
207        _ui->addIMAccountButton->setMenu(addIMAccountMenu);
208#else
209        _ui->addIMAccountButton->hide();
210#endif
211        ////
212
213        LANGUAGE_CHANGE(_imProfileWidget);
214
215        //Widget connections
216        SAFE_CONNECT(_ui->aliasLineEdit, SIGNAL(returnPressed()), SLOT(aliasTextChanged()));
217        SAFE_CONNECT(_ui->avatarButton, SIGNAL(clicked()), SLOT(changeAvatarClicked()));
218
219        //Init _accountFrame
220        _accountFrame = new QFrame();
221        _accountFrameLayout = new QHBoxLayout(_accountFrame);
222        _accountFrameLayout->setMargin(0);
223        _accountFrameLayout->setSpacing(0);
224
225        // Change size constraint to make sure the frame get resized when we add
226        // buttons to it
227        _accountFrameLayout->setSizeConstraint(QLayout::SetFixedSize);
228        _ui->accountScrollFrame->setChild(_accountFrame);
229        _ui->accountScrollFrame->setScrollStep(ACCOUNT_ICON_WIDTH / 2);
230        _imProfileWidget->setEnabled(false);
231}
232
233QtIMProfileWidget::~QtIMProfileWidget() {
234        OWSAFE_DELETE(_ui);
235}
236
237void QtIMProfileWidget::init(CUserProfile* cUserProfile, QtIMAccountMonitor* qtImAccountMonitor) {
238        _cUserProfile = cUserProfile;
239        _qtImAccountMonitor = qtImAccountMonitor;
240
241        //UserProfile changed event connection
242        _cUserProfile->getUserProfile().profileChangedEvent +=
243                boost::bind(&QtIMProfileWidget::profileChangedEventHandler, this);
244
245        // IMAccountMonitor connections
246        SAFE_CONNECT_TYPE(_qtImAccountMonitor, SIGNAL(imAccountAdded(QString)),
247                SLOT(addAccountButton(QString)), Qt::QueuedConnection);
248        SAFE_CONNECT_TYPE(_qtImAccountMonitor, SIGNAL(imAccountRemoved(QString)),
249                SLOT(removeAccountButton(QString)), Qt::QueuedConnection);
250        SAFE_CONNECT_TYPE(_qtImAccountMonitor, SIGNAL(imAccountUpdated(QString)),
251                SLOT(updateAccountButton(QString)), Qt::QueuedConnection);
252
253        _imProfileWidget->setEnabled(true);
254        updateWidgets();
255}
256
257QWidget * QtIMProfileWidget::getWidget() const {
258        return _imProfileWidget;
259}
260
261void QtIMProfileWidget::addAccountButton(QString imAccountId) {
262        // Check the button does not already exists
263        AccountIdToButton::const_iterator it = _accountIdToButton.find(imAccountId);
264        if (it != _accountIdToButton.end()) {
265                LOG_WARN("there is already a button for account " + imAccountId.toUtf8());
266                return;
267        }
268
269        // Look for the account
270        IMAccount * imAccount =
271        _cUserProfile->getUserProfile().getIMAccountManager().getIMAccount(std::string(imAccountId.toUtf8()));
272
273        if (!imAccount) {
274                LOG_WARN("Account does not exist");
275                return;
276        }
277
278        // Recreate all buttons. This is a bit brutal, but adding an account is not
279        // done very often, so it's not that bad.
280        // If it becomes necessary to just add the button, the
281        // addAccountButton(const IMAccount*) should be modified to insert the
282        // button at the correct position
283        createAccountButtons();
284}
285
286void QtIMProfileWidget::addAccountButton(const IMAccount* account) {
287        // Create button
288
289        QString id = QString::fromUtf8(account->getUUID().c_str());
290        AccountIdToButton::const_iterator it = _accountIdToButton.find(id);
291        if (it != _accountIdToButton.end()) {
292                LOG_WARN("there is already a button for account " + id.toUtf8());
293                return;
294        }
295
296        QToolButton* button = new QToolButton(_accountFrame);
297        button->setAutoRaise(true);
298        button->setIconSize(QSize(ACCOUNT_ICON_WIDTH, ACCOUNT_ICON_HEIGHT));
299        button->setPopupMode(QToolButton::InstantPopup);
300
301        // Add menu
302        QMenu* menu = new QMenu(button);
303        QAction* action = menu->addAction(QString::fromUtf8(account->getLogin().c_str()));
304        action->setEnabled(false);
305        menu->addAction(action);
306        menu->addSeparator();
307
308        QtIMAccountPresenceMenuManager* manager = new QtIMAccountPresenceMenuManager(menu, *_cUserProfile, account->getUUID());
309        manager->addPresenceActions(menu);
310        button->setMenu(menu);
311
312        // Integrate button
313        _accountFrameLayout->addWidget(button);
314
315        _accountIdToButton[id] = button;
316        updateAccountButton(id);
317}
318
319void QtIMProfileWidget::removeAccountButton(QString imAccountId) {
320        AccountIdToButton::iterator it = _accountIdToButton.find(imAccountId);
321        if (it == _accountIdToButton.end()) {
322                LOG_WARN("No button exists for account with id " + imAccountId.toUtf8());
323                return;
324        }
325        OWSAFE_DELETE(it->second);
326        _accountIdToButton.erase(it);
327        updateAddIMAccountButton();
328}
329
330void QtIMProfileWidget::updateAccountButton(QString imAccountId) {
331        // Look for the corresponding button
332        AccountIdToButton::const_iterator it = _accountIdToButton.find(imAccountId);
333        if (it == _accountIdToButton.end()) {
334                // Button does not exist
335                LOG_WARN("There is no button for account " + imAccountId.toUtf8());
336                return;
337        }
338        QToolButton* button = it->second;
339
340        // Look for the account
341        IMAccount * imAccount =
342        _cUserProfile->getUserProfile().getIMAccountManager().getIMAccount(std::string(imAccountId.toUtf8()));
343
344        if (!imAccount) {
345                // Account does not exist, this probably means the account has been
346                // removed
347                LOG_DEBUG("Account " + imAccountId.toUtf8() + " does not exist");
348                return;
349        }
350
351        // Get account info
352        EnumIMProtocol::IMProtocol imProtocol = imAccount->getProtocol();
353        QString protocolString = QString::fromUtf8(EnumIMProtocol::toString(imProtocol).c_str());
354        QString login = QString::fromUtf8(imAccount->getLogin().c_str());
355        EnumPresenceState::PresenceState presenceState = imAccount->getPresenceState();
356
357        OWSAFE_DELETE(imAccount);
358
359        QtIMAccountMonitor::IMAccountInfoAutoPtr info = _qtImAccountMonitor->getIMAccountInfo(imAccountId);
360        QtIMAccountMonitor::ConnectionState connectionState = info->connectionState();
361        QString message = info->message();
362        // Init button
363        QPixmap protocolPix = createAccountButtonPixmap(imProtocol, connectionState, presenceState);
364        button->setIcon(protocolPix);
365
366        QString toolTip = tr("%1 (%2)\n%3", "%1 is login, %2 is protocol, %3 is status")
367                .arg(login)
368                .arg(protocolString)
369                .arg(message);
370        button->setToolTip(toolTip);
371}
372
373void QtIMProfileWidget::changeAvatarClicked() {
374        QtProfileDetails qtProfileDetails(*_cUserProfile, _cUserProfile->getUserProfile(), _imProfileWidget, tr("Edit My Profile"));
375        //TODO UserProfile must be updated if QtProfileDetails was accepted
376        qtProfileDetails.changeUserProfileAvatar();
377        updateAvatar();
378}
379
380void QtIMProfileWidget::updateWidgets() {
381        if (!_cUserProfile) {
382                return;
383        }
384
385        if (!_cUserProfile->getUserProfile().getAlias().empty()) {
386                _ui->aliasLineEdit->setText(QString::fromUtf8(_cUserProfile->getUserProfile().getAlias().c_str()));
387        }
388
389        //aliasTextChanged();
390
391        updateAvatar();
392
393        createAccountButtons();
394}
395
396void QtIMProfileWidget::createAccountButtons() {
397        // Remove existing buttons
398        resetAccountButton();
399
400        // Sort accounts, using the same order as the meta presence
401        IMAccountList imAccountList = _cUserProfile->getUserProfile().getIMAccountManager().getIMAccountListCopy();
402        QtIMAccountHelper::QtIMAccountPtrVector imAccountPtrVector;
403        QtIMAccountHelper::copyListToPtrVector(imAccountList, &imAccountPtrVector);
404        std::sort(imAccountPtrVector.begin(), imAccountPtrVector.end(), QtIMAccountHelper::compareIMAccountPtrs);
405
406        // Updates IMAccounts icons status
407        QtIMAccountHelper::QtIMAccountPtrVector::const_iterator
408                it = imAccountPtrVector.begin(),
409                end = imAccountPtrVector.end();
410
411        for (; it!=end; ++it) {
412                addAccountButton(*it);
413        }
414
415        updateAddIMAccountButton();
416}
417
418// FIXME: This is copied from QtIMAccountManager ctor and should be
419// factorized
420void QtIMProfileWidget::addIMAccount(QAction * action) {
421        QString protocolName = action->text();
422        QtEnumIMProtocol::IMProtocol imProtocol = QtEnumIMProtocol::toIMProtocol(protocolName);
423        QtIMAccountSettings(_cUserProfile->getUserProfile(), imProtocol, _imProfileWidget);
424}
425
426void QtIMProfileWidget::updateAvatar() {
427        std::string backgroundPixmapFilename = ":/pics/avatar_background.png";
428        std::string foregroundPixmapData = _cUserProfile->getUserProfile().getIcon().getData();
429
430        _ui->avatarButton->setIcon(PixmapMerging::merge(foregroundPixmapData, backgroundPixmapFilename));
431}
432
433void QtIMProfileWidget::updateAddIMAccountButton() {
434        IMAccountList imAccountList = _cUserProfile->getUserProfile().getIMAccountManager().getIMAccountListCopy();
435        if (imAccountList.size() >= 2) {
436                _ui->addIMAccountButton->setToolButtonStyle(Qt::ToolButtonIconOnly);
437        } else {
438                _ui->addIMAccountButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
439        }
440       
441}
442
443void QtIMProfileWidget::showImAccountManager() {
444        QtIMAccountManager imAccountManager(_cUserProfile->getUserProfile(),
445                true, _imProfileWidget);
446}
447
448void QtIMProfileWidget::aliasTextChanged() {
449        //Update alias text
450        std::string alias(_ui->aliasLineEdit->text().toUtf8().constData());
451        _cUserProfile->getUserProfile().setAlias(alias, NULL);
452
453        _ui->aliasLineEdit->update();
454}
455
456void QtIMProfileWidget::profileChangedEventHandler() {
457        typedef ThreadEvent0<void ()> MyThreadEvent;
458        MyThreadEvent * event = new MyThreadEvent(boost::bind(&QtIMProfileWidget::updateWidgets, this));
459        PFactory::postEvent(event);
460}
461
462void QtIMProfileWidget::languageChanged() {
463        _ui->retranslateUi(_imProfileWidget);
464        updateWidgets();
465        _ui->aliasLineEdit->setLayoutDirection(QApplication::layoutDirection());
466}
467
468void QtIMProfileWidget::resetAccountButton() 
469{
470        AccountIdToButton::iterator
471                buttonIt = _accountIdToButton.begin(),
472                buttonEnd = _accountIdToButton.end();
473        for (; buttonIt!=buttonEnd; ++buttonIt) {
474                delete buttonIt->second;
475        }
476        _accountIdToButton.clear();
477}
478
479void QtIMProfileWidget::reset() 
480{
481        resetAccountButton();
482
483        _cUserProfile = 0;
484        _qtImAccountMonitor = 0;
485}
Note: See TracBrowser for help on using the repository browser.