Add AccountSettingsPage::accountSyncHandler()
[accounts-sso:libaccounts-ui.git] / lib / AccountsUI / account-settings-page.cpp
1 /*
2  * This file is part of accounts-ui
3  *
4  * Copyright (C) 2009-2010 Nokia Corporation.
5  *
6  * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * version 2.1 as published by the Free Software Foundation.
11  *
12  * This library is distributed in the hope that it will be useful, but
13  * 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
20  * 02110-1301 USA
21  */
22
23 //project
24 #include "account-settings-page-priv.h"
25 #include "provider-plugin-process.h"
26 #include "service-settings-widget.h"
27 #include "credentialdialog.h"
28 #include "service-model.h"
29 #include "sort-service-model.h"
30
31 //Accounts
32 #include <Accounts/Account>
33 #include <Accounts/Provider>
34
35 //Meegotouch
36 #include <MLayout>
37 #include <MMessageBox>
38 #include <MAction>
39 #include <MButton>
40 #include <MImageWidget>
41 #include <MSeparator>
42
43 //Qt
44 #include <QDebug>
45
46 #define INFO_BANNER_TIMEOUT 3000
47
48 using namespace AccountsUI;
49
50 AccountSettingsPagePrivate::AccountSettingsPagePrivate(
51     AbstractAccountSetupContext *context):
52     context(context),
53     account(0),
54     usernameAndStatus(0),
55     enableButton(0),
56     syncHandler(0),
57     changePasswordDialogStarted(false),
58     panel(0),
59     layout(0),
60     panelPolicy(0)
61 {
62     account = context->account();
63     serviceList = account->services();
64     abstractContexts.append(context);
65     panel = new MWidgetController();
66     syncHandler = new AccountSyncHandler(this);
67     connect(syncHandler, SIGNAL(syncStateChanged(const SyncState&)),
68             this, SLOT(onSyncStateChanged(const SyncState&)));
69 }
70
71 void AccountSettingsPagePrivate::saveSettings()
72 {
73     Q_Q(AccountSettingsPage);
74     disconnect(this , SIGNAL(backButtonClicked()), 0, 0);
75     q->setProgressIndicatorVisible(true);
76     qDebug() << Q_FUNC_INFO;
77     if (enableButton) {
78         bool state = enableButton->isChecked();
79         if (serviceList.count() == 1) {
80             account->selectService(serviceList.at(0));
81             if (account->enabled() != state)
82                 account->setEnabled(state);
83         } else if (serviceList.count() > 1) {
84             foreach (AbstractServiceSetupContext *serviceContext, contexts) {
85                 const Accounts::Service *service = serviceContext->service();
86                 QMap<QString, bool>::iterator i =
87                         serviceStatusMap.find(service->name());
88                 if (i == serviceStatusMap.end())
89                     continue;
90                 account->selectService(service);
91                 if (account->enabled() != i.value())
92                         serviceContext->enable(i.value());
93                 serviceStatusMap.remove(i.key());
94             }
95         }
96
97         context->account()->selectService(NULL);
98         if (account->enabled() != state)
99             account->setEnabled(state);
100     }
101     //we should call only validate. Storing will be handled
102     //in onSyncStateChangted func.
103     syncHandler->validate(abstractContexts);
104 }
105
106 void AccountSettingsPagePrivate::onSyncStateChanged(const SyncState &state)
107 {
108     qDebug() << Q_FUNC_INFO;
109
110     Q_Q(AccountSettingsPage);
111     switch (state) {
112         case NotValidated:
113             qDebug() << Q_FUNC_INFO << "NotValidated";
114             q->setProgressIndicatorVisible(false);
115             //Saving the settings on back button press
116             connect(this, SIGNAL(backButtonClicked()),
117                     this, SLOT(saveSettings()));
118             break;
119         case Validated:
120             qDebug() << Q_FUNC_INFO << "Validated";
121             syncHandler->store(abstractContexts);
122             break;
123         case NotStored:
124             qDebug() << Q_FUNC_INFO << "NotStored";
125             connect(context->account(), SIGNAL(synced()),
126                     ProviderPluginProcess::instance(), SLOT(quit()));
127             context->account()->sync();
128             break;
129         case Stored:
130             qDebug() << Q_FUNC_INFO << "Stored";
131             connect(context->account(), SIGNAL(synced()),
132                     ProviderPluginProcess::instance(), SLOT(quit()));
133             context->account()->sync();
134             break;
135         default:
136             return;
137     }
138 }
139
140 void AccountSettingsPagePrivate::openChangePasswordDialog()
141 {
142     //ignore multiple clicks
143     if (changePasswordDialogStarted)
144     {
145         qDebug() << Q_FUNC_INFO << "Change password dialog is started already";
146         return;
147     }
148
149     changePasswordDialogStarted = true;
150
151     CredentialDialog *credentialDialog = new CredentialDialog(account->credentialsId());
152     if (!credentialDialog) {
153         qCritical() << "Cannot create change password dialog";
154         return;
155     }
156     credentialDialog->setParent(this);
157     connect (credentialDialog, SIGNAL(safeToDeleteMe(CredentialDialog*)),
158              this, SLOT(deleteCredentialsDialog()));
159     //% "Change Password"
160     credentialDialog->setTitle(qtTrId("qtn_acc_login_title_change"));
161     credentialDialog->exec();
162 }
163
164 void AccountSettingsPagePrivate::deleteCredentialsDialog()
165 {
166     changePasswordDialogStarted = false;
167     CredentialDialog *credentialDialog;
168
169     if (sender() != NULL &&
170         (credentialDialog = qobject_cast<CredentialDialog *>(sender())) != NULL)
171         credentialDialog->deleteLater();
172 }
173
174
175 /*
176  * The same serviceTypes cannot be enabled in meantime
177  * */
178 void AccountSettingsPagePrivate::disableSameServiceTypes(const QString &serviceType)
179 {
180     qDebug() << Q_FUNC_INFO << __LINE__;
181     if (!sender())
182     {
183         qCritical() << "disableSameServiceTypes() must be called via signaling";
184         return;
185     }
186
187     if (settingsWidgets.count(serviceType) == 1)
188         return;
189
190     foreach (ServiceSettingsWidget *widget, settingsWidgets.values(serviceType)) {
191         if (widget == sender())
192             continue;
193
194         widget->setServiceButtonEnable(false);
195     }
196 }
197
198 void AccountSettingsPagePrivate::setEnabledService(const QString &serviceName,
199                                                    bool enabled)
200 {
201     serviceStatusMap[serviceName] = enabled;
202 }
203
204 AccountSettingsPage::AccountSettingsPage(AbstractAccountSetupContext *context)
205         : MApplicationPage(),
206           d_ptr(new AccountSettingsPagePrivate(context))
207 {
208     Q_D(AccountSettingsPage);
209
210     Q_ASSERT (context != NULL);
211     d->q_ptr = this;
212
213     //Saving the settings on back button press
214     connect(this, SIGNAL(backButtonClicked()),
215             d, SLOT(saveSettings()));
216     setStyleName("AccountsUiPage");
217 }
218
219 AccountSettingsPage::~AccountSettingsPage()
220 {
221     delete d_ptr;
222 }
223
224 void AccountSettingsPage::setServicesToBeShown()
225 {
226     qWarning() << Q_FUNC_INFO << "Deprecated. This function does nothing.";
227 }
228
229 QGraphicsLayoutItem *AccountSettingsPage::createServiceSettingsLayout()
230 {
231     Q_D(AccountSettingsPage);
232
233     MWidget *serviceWidget = new MWidget(this);
234     MLayout *serviceSettingLayout = new MLayout(serviceWidget);
235     MLinearLayoutPolicy *layoutServicePolicy =
236         new MLinearLayoutPolicy(serviceSettingLayout, Qt::Vertical);
237     layoutServicePolicy->setSpacing(0);
238
239     /* List the services available on the account and load all the respective plugins. */
240
241     //% "%1 Settings"
242     setTitle(qtTrId("qtn_acc_ser_prof_set_title").arg(d->context->account()->providerName()));
243
244     ServiceModel *serviceModel = new ServiceModel(d->context->account(), this);
245     SortServiceModel *sortModel = new SortServiceModel(this);
246     sortModel->setSourceModel(serviceModel);
247     sortModel->setEnabledServices(d->context->account()->enabledServices());
248     sortModel->setHiddenServices(d->hiddenServiceList);
249     sortModel->sort(ServiceModel::ServiceNameColumn);
250
251     d->contexts = ServiceModel::createServiceContexts(sortModel, d->context, this);
252
253     /* iterate through the contexts we created for each service, and get the
254      * UI widgets to embed */
255     QMap<QString, bool> enabledServiceTypes;
256     MLayout *layoutPanel = new MLayout(d->panel);
257     d->panelPolicy = new MLinearLayoutPolicy(layoutPanel, Qt::Vertical);
258
259     foreach (AbstractServiceSetupContext *context, d->contexts) {
260         d->abstractContexts.append(context);
261         const Accounts::Service *service = context->service();
262         ServiceSettingsWidget *settingsWidget;
263
264         d->account->selectService(service);
265         d->serviceStatusMap.insert(service->name(), d->account->enabled());
266         emit serviceEnabled(service->name(), d->account->enabled());
267         bool enabled = false;
268         if (d->account->enabled() &&
269             !enabledServiceTypes.contains(service->serviceType())) {
270             enabledServiceTypes.insert(service->serviceType(), true);
271             enabled = true;
272         }
273
274         if (d->serviceList.count() > 1)
275             settingsWidget = new ServiceSettingsWidget(context,
276                                                    d->panel,
277                                                    ServiceSettingsWidget::EnableButton,
278                                                    enabled);
279         else
280             settingsWidget = new ServiceSettingsWidget(context,
281                                                        d->panel,
282                                                        ServiceSettingsWidget::MandatorySettings |
283                                                        ServiceSettingsWidget::NonMandatorySettings,
284                                                        enabled);
285
286         d->settingsWidgets.insertMulti(service->serviceType(), settingsWidget);
287         d->panelPolicy->addItem(settingsWidget);
288     }
289
290     layoutServicePolicy->addItem(d->panel);
291     /*
292      * no need in extra processing of any signals during content creation
293      * */
294
295     if (d->settingsWidgets.count() > 1) {
296         MSeparator *separatorBottom = new MSeparator(this);
297         separatorBottom->setStyleName("CommonItemDividerInverted");
298         separatorBottom->setOrientation(Qt::Horizontal);
299         layoutServicePolicy->addItem(separatorBottom);
300     }
301
302     foreach (ServiceSettingsWidget *settingsWidget, d->settingsWidgets) {
303         connect (settingsWidget, SIGNAL(serviceButtonEnabled(const QString&)),
304                  this, SLOT(disableSameServiceTypes(const QString&)));
305         connect (settingsWidget, SIGNAL(serviceEnabled(const QString&, bool)),
306                  this, SIGNAL(serviceEnabled(const QString&, bool)));
307         connect (settingsWidget, SIGNAL(serviceEnabled(const QString&, bool)),
308                  this, SLOT(setEnabledService(const QString&, bool)));
309     }
310
311     return serviceWidget;
312 }
313
314 QGraphicsLayoutItem *AccountSettingsPage::createAccountSettingsLayout()
315 {
316     Q_D(AccountSettingsPage);
317
318     // First, see if the plugin has own implementation of this widget
319     QGraphicsLayoutItem *accountSettingsWidget = d->context->widget();
320     if (accountSettingsWidget != 0)
321         return accountSettingsWidget;
322
323     // Generic implementation
324     MWidget *upperWidget = new MWidget(this);
325     MLayout *upperLayout = new MLayout(upperWidget);
326     MLinearLayoutPolicy *upperLayoutPolicy =
327         new MLinearLayoutPolicy(upperLayout, Qt::Vertical);
328     upperLayoutPolicy->setSpacing(0);
329
330     MLayout *horizontalLayout = new MLayout();
331     MLinearLayoutPolicy *horizontalLayoutPolicy =
332         new MLinearLayoutPolicy(horizontalLayout, Qt::Horizontal);
333     horizontalLayoutPolicy->setSpacing(0);
334
335     QString providerName(d->account->providerName());
336     QString providerIconId;
337     Accounts::Provider *provider =
338         AccountsManager::instance()->provider(providerName);
339     if (provider) {
340         providerIconId = provider->iconName();
341     }
342
343     d->usernameAndStatus =
344         new MDetailedListItem(MDetailedListItem::IconTitleSubtitleAndTwoSideIcons);
345     d->usernameAndStatus->setStyleName("CommonDetailedListItemInverted");
346     d->usernameAndStatus->setObjectName("wgAccountSettingsPageListItem");
347     d->usernameAndStatus->imageWidget()->setImage(providerIconId);
348     d->usernameAndStatus->setTitle(providerName);
349     d->usernameAndStatus->setSubtitle(d->account->displayName());
350
351     MSeparator *separatorTop = new MSeparator(this);
352     separatorTop->setOrientation(Qt::Horizontal);
353     separatorTop->setStyleName("CommonItemDividerInverted");
354
355     d->enableButton = new MButton(this);
356     d->enableButton->setViewType(MButton::switchType);
357     d->enableButton->setStyleName("CommonSwitchInverted");
358     d->enableButton->setCheckable(true);
359
360     d->account->selectService(NULL);
361     if (d->account->enabled()) {
362         d->panel->setEnabled(true);
363         d->enableButton->setChecked(true);
364     } else {
365         d->panel->setEnabled(false);
366         d->enableButton->setChecked(false);
367     }
368
369     connect(d->enableButton, SIGNAL(toggled(bool)), this, SLOT(enable(bool)));
370
371     horizontalLayoutPolicy->addItem(d->usernameAndStatus,
372                                     Qt::AlignLeft | Qt::AlignVCenter);
373     horizontalLayoutPolicy->addItem(d->enableButton,
374                                     Qt::AlignRight | Qt::AlignVCenter);
375     upperLayoutPolicy->addItem(horizontalLayout);
376     upperLayoutPolicy->addItem(separatorTop);
377
378     return upperWidget;
379 }
380
381 void AccountSettingsPage::createPageActions()
382 {
383     //% "Delete"
384     MAction *action = new MAction(qtTrId("qtn_comm_command_delete"), this);
385     action->setLocation(MAction::ApplicationMenuLocation);
386     addAction(action);
387     connect(action, SIGNAL(triggered()),
388             this, SLOT(removeAccount()));
389 }
390
391 void AccountSettingsPage::createContent()
392 {
393     Q_D(AccountSettingsPage);
394
395     if (d->context == 0) return;
396
397     //we need a central widget to get the right layout size under the menubar
398     MWidget *centralWidget = new MWidget();
399     d->layout = new MLayout(centralWidget);
400     MLinearLayoutPolicy *layoutPolicy =
401         new MLinearLayoutPolicy(d->layout, Qt::Vertical);
402     layoutPolicy->setSpacing(0);
403
404     QGraphicsLayoutItem *accountSettingsLayout = createAccountSettingsLayout();
405     layoutPolicy->addItem(accountSettingsLayout);
406
407     QGraphicsLayoutItem *serviceWidget = createServiceSettingsLayout();
408     layoutPolicy->addItem(serviceWidget);
409
410     layoutPolicy->addStretch();
411
412     setCentralWidget(centralWidget);
413
414     createPageActions();
415 }
416
417 const AbstractAccountSetupContext *AccountSettingsPage::context()
418 {
419     Q_D(AccountSettingsPage);
420     return d->context;
421 }
422
423 void AccountSettingsPage::enable(bool state)
424 {
425     Q_D(AccountSettingsPage);
426     d->panel->setEnabled(state);
427 }
428
429 void AccountSettingsPage::removeAccount()
430 {
431     Q_D(AccountSettingsPage);
432     //% "Delete %1 from your device?"
433     QString dialogTitle =
434         qtTrId("qtn_acc_remove_account").arg(d->context->account()->displayName());
435     //% "All content related to this account will be deleted permanently"
436     MMessageBox removeMBox(dialogTitle, qtTrId("qtn_acc_remove_account_statement"),
437                            M::YesButton | M::NoButton);
438     removeMBox.setStyleName("RemoveDialog");
439
440     if (removeMBox.exec() == M::YesButton) {
441         d->context->account()->remove();
442         d->context->account()->sync();
443         ProviderPluginProcess::instance()->quit();
444     }
445 }
446
447 void AccountSettingsPage::setWidget(MWidget *widget)
448 {
449      Q_D(AccountSettingsPage);
450      d->panelPolicy->addItem(widget);
451 }
452
453 void AccountSettingsPage::setHiddenServices(const Accounts::ServiceList &hiddenServices)
454 {
455     Q_D(AccountSettingsPage);
456     d->hiddenServiceList = hiddenServices;
457 }
458
459 MButton *AccountSettingsPage::enableAccountButton() const
460 {
461     Q_D(const AccountSettingsPage);
462     return d->enableButton;
463 }
464
465 AccountSyncHandler *AccountSettingsPage::accountSyncHandler() const
466 {
467     Q_D(const AccountSettingsPage);
468     return d->syncHandler;
469 }
470