1 /*
2  * This file is part of telepathy-contactslist-prototype
3  *
4  * Copyright (C) 2011 Francesco Nwokeka <francesco.nwokeka@gmail.com>
5  * Copyright (C) 2012 Dominik Cermak <d.cermak@arcor.de>
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 "join-chat-room-dialog.h"
23 #include "ui_join-chat-room-dialog.h"
24 #include "debug.h"
25 
26 #include <KTp/Models/rooms-model.h>
27 
28 #include <KConfig>
29 #include <KConfigGroup>
30 #include <KSharedConfig>
31 #include <KMessageWidget>
32 #include <KLocalizedString>
33 #include <KNotification>
34 #include <KIconLoader>
35 
36 #include <TelepathyQt/Account>
37 #include <TelepathyQt/AccountSet>
38 #include <TelepathyQt/AccountCapabilityFilter>
39 #include <TelepathyQt/AccountManager>
40 #include <TelepathyQt/AccountPropertyFilter>
41 #include <TelepathyQt/AndFilter>
42 #include <TelepathyQt/ChannelTypeRoomListInterface>
43 #include <TelepathyQt/PendingChannel>
44 #include <TelepathyQt/PendingReady>
45 #include <TelepathyQt/RequestableChannelClassSpec>
46 #include <TelepathyQt/RoomListChannel>
47 #include <TelepathyQt/PendingChannelRequest>
48 
49 #include <QSortFilterProxyModel>
50 #include <QDialogButtonBox>
51 
52 class KTp::JoinChatRoomDialog::Private
53 {
54 public:
Private(JoinChatRoomDialog * q)55     Private(JoinChatRoomDialog *q) :
56         ui(new Ui::JoinChatRoomDialog)
57         , model(new RoomsModel(q))
58         , favoritesModel(new FavoriteRoomsModel(q))
59         , favoritesProxyModel(new QSortFilterProxyModel(q))
60         , joinInProgress(false)
61     {}
62 
63     QList<Tp::AccountPtr> accounts;
64     Ui::JoinChatRoomDialog *ui;
65     QDialogButtonBox *buttonBox;
66     Tp::PendingChannel *pendingRoomListChannel;
67     Tp::ChannelPtr roomListChannel;
68     Tp::Client::ChannelTypeRoomListInterface *iface;
69     RoomsModel *model;
70     FavoriteRoomsModel *favoritesModel;
71     QSortFilterProxyModel *favoritesProxyModel;
72     KConfigGroup favoriteRoomsGroup;
73     KConfigGroup recentRoomsGroup;
74     bool joinInProgress;
75 };
76 
JoinChatRoomDialog(Tp::AccountManagerPtr accountManager,QWidget * parent)77 KTp::JoinChatRoomDialog::JoinChatRoomDialog(Tp::AccountManagerPtr accountManager, QWidget* parent)
78     : QDialog(parent, Qt::Dialog)
79     , d(new Private(this))
80 {
81     QWidget *joinChatRoomDialog = new QWidget(this);
82     d->ui->setupUi(joinChatRoomDialog);
83     d->ui->feedbackWidget->hide();
84 
85     d->buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
86 
87     QVBoxLayout *mainLayout = new QVBoxLayout(this);
88     mainLayout->addWidget(joinChatRoomDialog);
89     mainLayout->addWidget(d->buttonBox);
90     setLayout(mainLayout);
91 
92     setWindowIcon(QIcon::fromTheme(QLatin1String("im-irc")));
93     setWindowTitle(i18nc("Dialog title", "Join Chat Room"));
94 
95     d->ui->filterPicture->clear();
96     d->ui->filterPicture->setPixmap(KIconLoader::global()->loadIcon(QLatin1String("view-filter"), KIconLoader::Small));
97 
98     // config
99     KSharedConfigPtr commonConfig = KSharedConfig::openConfig(QLatin1String("ktelepathyrc"));
100     d->favoriteRoomsGroup = commonConfig->group(QLatin1String("FavoriteRooms"));
101     d->recentRoomsGroup = commonConfig->group(QLatin1String("RecentChatRooms"));
102 
103     // load favorite and recent rooms
104     loadFavoriteRooms();
105 
106     // disable OK button on start
107     d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
108     d->buttonBox->button(QDialogButtonBox::Ok)->setText(i18nc("button", "Join/Create"));
109     d->buttonBox->button(QDialogButtonBox::Ok)->setIcon(QIcon::fromTheme(QLatin1String("im-irc")));
110 
111     onAccountSelectionChanged(d->ui->comboBox->currentIndex());
112     connect(accountManager->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)),
113             this, SLOT(onAccountManagerReady(Tp::PendingOperation*)));
114 
115     // Previous Tab
116     d->favoritesProxyModel->setSourceModel(d->favoritesModel);
117     d->favoritesProxyModel->setFilterKeyColumn(FavoriteRoomsModel::AccountIdentifierColumn);
118     d->favoritesProxyModel->setSortRole(Qt::CheckStateRole);
119     d->favoritesProxyModel->setDynamicSortFilter(true);
120 
121     d->ui->previousView->setModel(d->favoritesProxyModel);
122     d->ui->previousView->setHeaderHidden(true);
123     d->ui->previousView->header()->setStretchLastSection(false);
124     d->ui->previousView->header()->setSectionResizeMode(FavoriteRoomsModel::BookmarkColumn, QHeaderView::ResizeToContents);
125     d->ui->previousView->header()->setSectionResizeMode(FavoriteRoomsModel::HandleNameColumn, QHeaderView::Stretch);
126     d->ui->previousView->setColumnHidden(FavoriteRoomsModel::AccountIdentifierColumn, true);
127     d->ui->previousView->sortByColumn(FavoriteRoomsModel::BookmarkColumn, Qt::DescendingOrder);
128 
129     // Search Tab
130     QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
131     proxyModel->setSourceModel(d->model);
132     proxyModel->setSortLocaleAware(true);
133     proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
134     proxyModel->setFilterKeyColumn(RoomsModel::NameColumn);
135     proxyModel->setDynamicSortFilter(true);
136 
137     d->ui->queryView->setModel(proxyModel);
138     d->ui->queryView->header()->setStretchLastSection(false);
139     d->ui->queryView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
140     d->ui->queryView->header()->setSectionResizeMode(1, QHeaderView::Stretch);
141     d->ui->queryView->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
142     d->ui->queryView->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
143     d->ui->queryView->header()->setSortIndicatorShown(false);
144     d->ui->queryView->sortByColumn(RoomsModel::NameColumn, Qt::AscendingOrder);
145 
146     // connects
147     connect(d->ui->lineEdit, SIGNAL(textChanged(QString)), this, SLOT(onTextChanged(QString)));
148     connect(d->ui->previousView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept()));
149     connect(d->ui->previousView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
150             this, SLOT(onFavoriteRoomSelectionChanged(QModelIndex,QModelIndex)));
151     connect(d->favoritesModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
152             this, SLOT(onFavoriteRoomDataChanged(QModelIndex,QModelIndex)));
153     connect(d->ui->clearRecentPushButton, SIGNAL(clicked(bool)), this, SLOT(clearRecentRooms()));
154     connect(d->ui->serverLineEdit, SIGNAL(returnPressed()), this, SLOT(getRoomList()));
155     connect(d->ui->queryButton, SIGNAL(clicked(bool)), this, SLOT(getRoomList()));
156     connect(d->ui->queryView, SIGNAL(clicked(QModelIndex)), this, SLOT(onRoomClicked(QModelIndex)));
157     connect(d->ui->queryView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept()));
158     connect(d->ui->filterBar, SIGNAL(textChanged(QString)), proxyModel, SLOT(setFilterFixedString(QString)));
159     connect(d->ui->comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onAccountSelectionChanged(int)));
160     connect(d->buttonBox, SIGNAL(accepted()), this, SLOT(addRecentRoom()));
161     connect(d->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); //FIXME?
162     connect(d->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
163 }
164 
closeEvent(QCloseEvent * e)165 void KTp::JoinChatRoomDialog::closeEvent(QCloseEvent* e)
166 {
167     // ignore close event if we are in the middle of an operation
168     if (!d->joinInProgress) {
169         QDialog::closeEvent(e);
170     }
171 }
172 
173 
onAccountManagerReady(Tp::PendingOperation * operation)174 void KTp::JoinChatRoomDialog::onAccountManagerReady(Tp::PendingOperation* operation)
175 {
176     Tp::AccountManagerPtr accountManager = Tp::AccountManagerPtr::qObjectCast(
177         qobject_cast<Tp::PendingReady*>(operation)->proxy()
178     );
179     Tp::AccountPropertyFilterPtr isOnlineFilter = Tp::AccountPropertyFilter::create();
180     isOnlineFilter->addProperty(QLatin1String("online"), true);
181 
182     Tp::AccountCapabilityFilterPtr capabilityFilter = Tp::AccountCapabilityFilter::create(
183                 Tp::RequestableChannelClassSpecList() << Tp::RequestableChannelClassSpec::textChatroom());
184     Tp::AccountFilterPtr filter = Tp::AndFilter<Tp::Account>::create((QList<Tp::AccountFilterConstPtr>() <<
185                                              isOnlineFilter <<
186                                              capabilityFilter));
187 
188     d->ui->comboBox->setAccountSet(accountManager->filterAccounts(filter));
189 
190     // queryTab
191     if (d->ui->comboBox->count() > 0) {
192         d->ui->queryButton->setEnabled(true);
193     }
194 
195     // apply the filter after populating
196     onAccountSelectionChanged(d->ui->comboBox->currentIndex());
197 }
198 
~JoinChatRoomDialog()199 KTp::JoinChatRoomDialog::~JoinChatRoomDialog()
200 {
201     delete d->ui;
202     delete d;
203 }
204 
selectedAccount() const205 Tp::AccountPtr KTp::JoinChatRoomDialog::selectedAccount() const
206 {
207     return d->ui->comboBox->currentAccount();
208 }
209 
accept()210 void KTp::JoinChatRoomDialog::accept()
211 {
212     d->ui->feedbackWidget->hide();
213     const Tp::AccountPtr account = selectedAccount();
214     if (account) {
215         setJoinInProgress(true);
216         Tp::PendingChannelRequest *request = account->ensureTextChatroom(selectedChatRoom());
217         connect(request, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onStartChatFinished(Tp::PendingOperation*)));
218     }
219 }
220 
221 
onAccountSelectionChanged(int newIndex)222 void KTp::JoinChatRoomDialog::onAccountSelectionChanged(int newIndex)
223 {
224     // Show only favorites associated with the selected account
225     Q_UNUSED(newIndex)
226 
227     if (!d->ui->comboBox->currentAccount()) {
228         // Set a filter expression that matches no account identifier
229         d->favoritesProxyModel->setFilterRegExp(QLatin1String("a^"));
230         return;
231     }
232 
233     QString accountIdentifier = d->ui->comboBox->currentAccount()->uniqueIdentifier();
234     d->favoritesProxyModel->setFilterFixedString(accountIdentifier);
235 
236     // Enable/disable the buttons as appropriate
237     d->ui->clearRecentPushButton->setEnabled(!d->recentRoomsGroup.keyList().empty());
238 }
239 
onFavoriteRoomDataChanged(const QModelIndex & topLeft,const QModelIndex & bottomRight)240 void KTp::JoinChatRoomDialog::onFavoriteRoomDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
241 {
242     // Because previousView only allows editing of a single row, assume that topLeft points to the changed data.
243     Q_UNUSED(bottomRight);
244 
245     bool bookmarked = topLeft.data(Qt::CheckStateRole) == Qt::Checked ? true : false;
246     const QString &favoriteHandle = topLeft.data(FavoriteRoomsModel::HandleNameRole).toString();
247     const QString &favoriteAccount = topLeft.data(FavoriteRoomsModel::AccountRole).toString();
248 
249     const QString &key = favoriteHandle + favoriteAccount;
250 
251     // Write the changed room to the config file
252     QVariantList favorite;
253     favorite.append(favoriteHandle);
254     favorite.append(favoriteAccount);
255 
256     if (bookmarked) {
257         if (d->recentRoomsGroup.keyList().contains(key)) {
258             d->recentRoomsGroup.deleteEntry(key);
259             d->recentRoomsGroup.sync();
260         }
261         d->favoriteRoomsGroup.writeEntry(key, favorite);
262         d->favoriteRoomsGroup.sync();
263     } else {
264         if (d->favoriteRoomsGroup.keyList().contains(key)) {
265             d->favoriteRoomsGroup.deleteEntry(key);
266             d->favoriteRoomsGroup.sync();
267         }
268         d->recentRoomsGroup.writeEntry(key, favorite);
269         d->recentRoomsGroup.sync();
270     }
271 
272     onAccountSelectionChanged(d->ui->comboBox->currentIndex());
273 }
274 
addRecentRoom()275 void KTp::JoinChatRoomDialog::addRecentRoom()
276 {
277     Tp::AccountPtr account = d->ui->comboBox->currentAccount();
278     if (!account || d->ui->lineEdit->text().isEmpty()) {
279         return;
280     }
281 
282     QString recentAccount = account->uniqueIdentifier();
283     QString recentHandle = d->ui->lineEdit->text();
284     const QString &key = recentHandle + recentAccount;
285 
286     QVariantList recent;
287     recent.append(recentHandle);
288     recent.append(recentAccount);
289 
290     if(d->favoriteRoomsGroup.keyList().contains(key) || d->recentRoomsGroup.keyList().contains(key)) {
291         return;
292     }
293 
294     d->recentRoomsGroup.writeEntry(key, recent);
295     d->recentRoomsGroup.sync();
296 }
297 
298 
clearRecentRooms()299 void KTp::JoinChatRoomDialog::clearRecentRooms()
300 {
301     QString accountIdentifier = d->ui->comboBox->currentAccount()->uniqueIdentifier();
302 
303     KSharedConfigPtr commonConfig = KSharedConfig::openConfig(QLatin1String("ktelepathyrc"));
304     commonConfig->deleteGroup(QLatin1String("RecentChatRooms"));
305     commonConfig->sync();
306 
307     // Reload the model
308     d->favoritesModel->clearRooms();
309     loadFavoriteRooms();
310 
311     // Update the list
312     onAccountSelectionChanged(d->ui->comboBox->currentIndex());
313 }
314 
getRoomList()315 void KTp::JoinChatRoomDialog::getRoomList()
316 {
317     Tp::AccountPtr account = d->ui->comboBox->currentAccount();
318     if (!account) {
319         return;
320     }
321 
322     // Clear the list from previous items
323     d->model->clearRoomInfoList();
324 
325     // Build the channelrequest
326     QVariantMap request;
327     request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"),
328                    TP_QT_IFACE_CHANNEL_TYPE_ROOM_LIST);
329     request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"),
330                    Tp::HandleTypeNone);
331 
332     // If the user provided a server use it, else use the standard server for the selected account
333     if (!d->ui->serverLineEdit->text().isEmpty()) {
334         request.insert(TP_QT_IFACE_CHANNEL_TYPE_ROOM_LIST + QLatin1String(".Server"),
335                        d->ui->serverLineEdit->text());
336     }
337 
338     d->pendingRoomListChannel = account->createAndHandleChannel(request, QDateTime::currentDateTime());
339     connect(d->pendingRoomListChannel, SIGNAL(finished(Tp::PendingOperation*)),
340             this, SLOT(onRoomListChannelReadyForHandling(Tp::PendingOperation*)));
341 
342 }
343 
stopListing()344 void KTp::JoinChatRoomDialog::stopListing()
345 {
346     d->iface->StopListing();
347 }
348 
onRoomListChannelReadyForHandling(Tp::PendingOperation * operation)349 void KTp::JoinChatRoomDialog::onRoomListChannelReadyForHandling(Tp::PendingOperation *operation)
350 {
351     if (operation->isError()) {
352         qCDebug(KTP_WIDGETS) << operation->errorName();
353         qCDebug(KTP_WIDGETS) << operation->errorMessage();
354         QString errorMsg(operation->errorName() + QLatin1String(": ") + operation->errorMessage());
355         sendNotificationToUser(errorMsg);
356     } else {
357         d->roomListChannel = d->pendingRoomListChannel->channel();
358 
359         connect(d->roomListChannel->becomeReady(),
360                 SIGNAL(finished(Tp::PendingOperation*)),
361                 SLOT(onRoomListChannelReady(Tp::PendingOperation*)));
362     }
363 }
364 
onRoomListChannelReady(Tp::PendingOperation * operation)365 void KTp::JoinChatRoomDialog::onRoomListChannelReady(Tp::PendingOperation *operation)
366 {
367     if (operation->isError()) {
368         qCDebug(KTP_WIDGETS) << operation->errorName();
369         qCDebug(KTP_WIDGETS) << operation->errorMessage();
370         QString errorMsg(operation->errorName() + QLatin1String(": ") + operation->errorMessage());
371         sendNotificationToUser(errorMsg);
372     } else {
373         d->iface = d->roomListChannel->interface<Tp::Client::ChannelTypeRoomListInterface>();
374 
375         d->iface->ListRooms();
376 
377         connect(d->iface, SIGNAL(ListingRooms(bool)), SLOT(onListing(bool)));
378         connect(d->iface, SIGNAL(GotRooms(Tp::RoomInfoList)), SLOT(onGotRooms(Tp::RoomInfoList)));
379     }
380 }
381 
onRoomListChannelClosed(Tp::PendingOperation * operation)382 void KTp::JoinChatRoomDialog::onRoomListChannelClosed(Tp::PendingOperation *operation)
383 {
384     if (operation->isError()) {
385         qCDebug(KTP_WIDGETS) << operation->errorName();
386         qCDebug(KTP_WIDGETS) << operation->errorMessage();
387         QString errorMsg(operation->errorName() + QLatin1String(": ") + operation->errorMessage());
388         sendNotificationToUser(errorMsg);
389     } else {
390         d->ui->queryButton->setEnabled(true);
391         d->ui->queryButton->setIcon(QIcon::fromTheme(QLatin1String("media-playback-start")));
392         d->ui->queryButton->setText(i18nc("Button text", "Query"));
393         d->ui->queryButton->setToolTip(i18nc("Tooltip text", "Start query"));
394         connect(d->ui->queryButton, SIGNAL(clicked(bool)), this, SLOT(getRoomList()));
395         disconnect(d->ui->queryButton, SIGNAL(clicked(bool)), this, SLOT(stopListing()));
396     }
397 }
398 
onListing(bool isListing)399 void KTp::JoinChatRoomDialog::onListing(bool isListing)
400 {
401     if (isListing) {
402         qCDebug(KTP_WIDGETS) << "listing";
403         d->ui->queryButton->setEnabled(true);
404         d->ui->queryButton->setIcon(QIcon::fromTheme(QLatin1String("media-playback-stop")));
405         d->ui->queryButton->setText(i18nc("Button text", "Stop"));
406         d->ui->queryButton->setToolTip(i18nc("Tooltip text", "Stop query"));
407         disconnect(d->ui->queryButton, SIGNAL(clicked(bool)), this, SLOT(getRoomList()));
408         connect(d->ui->queryButton, SIGNAL(clicked(bool)), this, SLOT(stopListing()));
409     } else {
410         qCDebug(KTP_WIDGETS) << "finished listing";
411         Tp::PendingOperation *op =  d->roomListChannel->requestClose();
412         connect(op,
413                 SIGNAL(finished(Tp::PendingOperation*)),
414                 SLOT(onRoomListChannelClosed(Tp::PendingOperation*)));
415     }
416 }
417 
onGotRooms(Tp::RoomInfoList roomInfoList)418 void KTp::JoinChatRoomDialog::onGotRooms(Tp::RoomInfoList roomInfoList)
419 {
420     d->model->addRooms(roomInfoList);
421 }
422 
onFavoriteRoomSelectionChanged(const QModelIndex & current,const QModelIndex & previous)423 void KTp::JoinChatRoomDialog::onFavoriteRoomSelectionChanged(const QModelIndex &current, const QModelIndex &previous)
424 {
425     Q_UNUSED(previous);
426     if (current.isValid()) {
427         d->ui->lineEdit->setText(current.data(FavoriteRoomsModel::HandleNameRole).toString());
428     }
429 }
430 
onRoomClicked(const QModelIndex & index)431 void KTp::JoinChatRoomDialog::onRoomClicked(const QModelIndex &index)
432 {
433     d->ui->lineEdit->setText(index.data(RoomsModel::HandleNameRole).toString());
434 }
435 
selectedChatRoom() const436 QString KTp::JoinChatRoomDialog::selectedChatRoom() const
437 {
438     return d->ui->lineEdit->text();
439 }
440 
onTextChanged(QString newText)441 void KTp::JoinChatRoomDialog::onTextChanged(QString newText)
442 {
443     d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!newText.isEmpty());
444 }
445 
onStartChatFinished(Tp::PendingOperation * op)446 void KTp::JoinChatRoomDialog::onStartChatFinished(Tp::PendingOperation *op)
447 {
448     setJoinInProgress(false);
449     if (op->isError()) {
450         qCDebug(KTP_WIDGETS) << "failed to join room";
451         qCDebug(KTP_WIDGETS) << op->errorName() << op->errorMessage();
452 
453         d->ui->feedbackWidget->setMessageType(KMessageWidget::KMessageWidget::Error);
454         d->ui->feedbackWidget->setText(i18n("Could not join chatroom"));
455         d->ui->feedbackWidget->animatedShow();
456     } else {
457         close();
458     }
459 }
460 
setJoinInProgress(bool inProgress)461 void KTp::JoinChatRoomDialog::setJoinInProgress(bool inProgress)
462 {
463     d->joinInProgress = inProgress;
464     layout()->parentWidget()->setEnabled(!inProgress);
465     d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!inProgress);
466     d->buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(!inProgress);
467 }
468 
469 
sendNotificationToUser(const QString & errorMsg)470 void KTp::JoinChatRoomDialog::sendNotificationToUser(const QString& errorMsg)
471 {
472     //The pointer is automatically deleted when the event is closed
473     KNotification *notification;
474     notification = new KNotification(QLatin1String("telepathyError"), this);
475 
476     notification->setText(errorMsg);
477     notification->sendEvent();
478 }
479 
loadFavoriteRooms()480 void KTp::JoinChatRoomDialog::loadFavoriteRooms()
481 {
482     QList<QVariantMap> roomList;
483 
484     Q_FOREACH(const QString &key, d->favoriteRoomsGroup.keyList()) {
485         QVariantList favorite = d->favoriteRoomsGroup.readEntry(key, QVariantList());
486         // Keep compatibility with KTp 0.8 and previous
487         if(favorite.size() == 3) {
488             // Update the entry in the config file
489             favorite.removeFirst();
490             d->favoriteRoomsGroup.writeEntry(key, favorite);
491             d->favoriteRoomsGroup.sync();
492         }
493         QString favoriteHandle = favorite.at(0).toString();
494         QString favoriteAccount = favorite.at(1).toString();
495         QVariantMap room;
496         room.insert(QLatin1String("is-bookmarked"), true);
497         room.insert(QLatin1String("handle-name"), favoriteHandle);
498         room.insert(QLatin1String("account-identifier"), favoriteAccount);
499         roomList.append(room);
500     }
501 
502     Q_FOREACH (const QString &key, d->recentRoomsGroup.keyList()) {
503         QVariantList recent = d->recentRoomsGroup.readEntry(key, QVariantList());
504         QString recentHandle = recent.at(0).toString();
505         QString recentAccount = recent.at(1).toString();
506         QVariantMap room;
507         room.insert(QLatin1String("is-bookmarked"), false);
508         room.insert(QLatin1String("handle-name"), recentHandle);
509         room.insert(QLatin1String("account-identifier"), recentAccount);
510         roomList.append(room);
511     }
512 
513     d->favoritesModel->addRooms(roomList);
514 }
515