1
/*
2
 * meego-handset-people - Contacts application
3
 * Copyright © 2010, Intel Corporation.
4
 *
5
 * This program is licensed under the terms and conditions of the
6
 * Apache License, version 2.0.  The full text of the Apache License is at
7
 * http://www.apache.org/licenses/LICENSE-2.0
8
 *
9
 */
10
11
#include <QDebug>
12
13
#include <QGraphicsLinearLayout>
14
#include <QtDBus/QtDBus>
15
#include <QDBusConnection>
16
#include <MAction>
17
#include <QActionGroup>
18
19
#include <MApplicationPage>
20
#include <MTextEdit>
21
#include <MButton>
22
#include <MPannableViewport>
23
#include <MSceneManager>
24
25
#include <seasidesyncmodel.h>
26
#include <seasidepersonmodel.h>
27
28
#include "peopleapp.h"
29
#include "window.h"
30
#include "people.h"
31
#include "person.h"
32
#include "slider.h"
33
#include "personcommspage.h"
34
#include "peopledbusadaptor.h"
35
36
PeopleApplication *PeopleApplication::theApp = NULL;
37
38
PeopleApplication *PeopleApplication::instance()
39
{
40
    return theApp;
41
}
42
43
PeopleApplication::PeopleApplication(int &argc, char**argv):
44
        MApplication(argc, argv)
45
{
46
    theApp = this;
47
48
    m_realModel = SeasideSyncModel::instance();
49
50
    m_window = new SeasideWindow;
51
    m_window->show();
52
53
    m_mainPage = NULL;
54
    m_detailPage = NULL;
55
    m_editPage = NULL;
56
    m_commPage = NULL;
57
58
    m_topSpacer = NULL;
59
    m_bottomSpacer = NULL;
60
61
    m_people = NULL;
62
    m_sliderH = NULL;
63
    m_sliderV = NULL;
64
    m_searchWidget = NULL;
65
    m_searchEdit = NULL;
66
67
    m_currentPerson = NULL;
68
    m_editModel = NULL;
69
    m_editModelModified = NULL;
70
    m_callPending = false;
71
72
73
//    m_AccountPath = NULL;
74
75
    createPeoplePage();
76
77
    connect(m_window, SIGNAL(orientationChanged(M::Orientation)),
78
            this, SLOT(repositionOverlays()));
79
80
     PeopleDBusAdaptor *adpt = new PeopleDBusAdaptor(this);
81
     if(!adpt)
82
        qWarning() << "People Application Dbus adaptor failed" << adpt;
83
84
     bool err;
85
     err = QDBusConnection::sessionBus().registerService(DBUSINTFNAME);
86
     if(!err)
87
          qDebug() << "People Application Dbus calls error:" << err;
88
       err = QDBusConnection::sessionBus().registerObject(DBUSOBJPATH, this);
89
       if(!err)
90
            qDebug() << "People Application Dbus calls error:" << err;
91
92
       m_dbusDialerWatcher = new QDBusServiceWatcher("com.meego.dialer" , QDBusConnection::sessionBus(),
93
                                           QDBusServiceWatcher::WatchForRegistration|QDBusServiceWatcher::WatchForUnregistration,
94
                                           this);
95
       m_dbusEmailWatcher = new QDBusServiceWatcher("com.meego.email" , QDBusConnection::sessionBus(),
96
                                           QDBusServiceWatcher::WatchForRegistration|QDBusServiceWatcher::WatchForUnregistration,
97
                                           this);
98
       m_dbusIMWatcher = new QDBusServiceWatcher("com.meego.meego_handset_chat" , QDBusConnection::sessionBus(),
99
                                           QDBusServiceWatcher::WatchForRegistration|QDBusServiceWatcher::WatchForUnregistration,
100
                                           this);
101
       m_dbusSMSWatcher = new QDBusServiceWatcher("com.meego.sms" , QDBusConnection::sessionBus(),
102
                                           QDBusServiceWatcher::WatchForRegistration|QDBusServiceWatcher::WatchForUnregistration,
103
                                           this);
104
105
    connect(m_dbusDialerWatcher, SIGNAL(serviceRegistered(QString)),
106
            this, SLOT(handleDialerRegistered())); 
107
    connect(m_dbusEmailWatcher, SIGNAL(serviceRegistered(QString)),
108
            this, SLOT(handleEmailRegistered()));
109
    connect(m_dbusIMWatcher, SIGNAL(serviceRegistered(QString)),
110
            this, SLOT(handleIMRegistered()));
111
    connect(m_dbusSMSWatcher, SIGNAL(serviceRegistered(QString)),
112
            this, SLOT(handleSMSRegistered()));
113
}
114
115
PeopleApplication::~PeopleApplication()
116
{
117
    delete m_mainPage;
118
    delete m_window;
119
    m_realModel->releaseInstance();
120
121
    if (theApp == this)
122
        theApp = NULL;
123
}
124
125
void PeopleApplication::createPeoplePage()
126
{
127
128
    //m_AccountManager = AccountManger::getInstance();
129
    m_mainPage = new MApplicationPage;
130
    m_mainPage->setTitle(QObject::tr("People","Title of the application"));
131
132
    QGraphicsLinearLayout *linear = new QGraphicsLinearLayout(Qt::Vertical);
133
    linear->setContentsMargins(0, 0, 0, 0);
134
    linear->setSpacing(0);
135
    m_mainPage->centralWidget()->setLayout(linear);
136
137
    m_topSpacer = new QGraphicsWidget;
138
    m_topSpacer->setPreferredHeight(0);
139
    linear->addItem(m_topSpacer);
140
141
    m_people = new SeasidePeople;
142
    linear->addItem(m_people);
143
144
    m_bottomSpacer = new QGraphicsWidget;
145
    m_bottomSpacer->setPreferredHeight(0);
146
    linear->addItem(m_bottomSpacer); 
147
148
    m_actionSearch = new MAction(QObject::tr("Search","Menu action to bring up search for contact list"), this);
149
    m_actionSearch->setLocation(MAction::ApplicationMenuLocation);
150
    m_mainPage->addAction(m_actionSearch);
151
    connect(m_actionSearch, SIGNAL(triggered()), this, SLOT(searchClicked()));
152
153
    m_actionAdd = new MAction(QObject::tr("Add Contact","Menu action to add contact"), this);
154
    m_actionAdd->setLocation(MAction::ApplicationMenuLocation);
155
    m_mainPage->addAction(m_actionAdd);
156
    connect(m_actionAdd, SIGNAL(triggered()), this, SLOT(addNewContact()));
157
158
    m_actionAll = new MAction(QObject::tr("<b>Show All</b>","Menu filter to show all contacts"), this);  
159
    m_actionAll->setLocation(MAction::ApplicationMenuLocation);
160
    m_actionAll->setObjectName("ShowAllFilter");
161
    m_actionAll->setCheckable(true);
162
    connect(m_actionAll, SIGNAL(triggered()), m_people, SLOT(filterAll()));
163
164
    m_actionFav = new MAction(QObject::tr("Show Favorites", "Menu filter to show all contacts marked as favorites"), this);
165
    m_actionFav->setLocation(MAction::ApplicationMenuLocation);
166
    m_actionFav->setObjectName("ShowFavoritesFilter");
167
    m_actionFav->setCheckable(true);
168
    connect(m_actionFav, SIGNAL(triggered()), m_people, SLOT(filterFavorites()));
169
170
    m_actionRecent = new MAction(QObject::tr("Show Recent","Menu filter to show all contacts with recent communications"), this);
171
    m_actionRecent->setLocation(MAction::ApplicationMenuLocation);
172
    m_actionRecent->setCheckable(true);
173
    m_actionRecent->setObjectName("ShowRecentFilter");
174
    connect(m_actionRecent, SIGNAL(triggered()), m_people, SLOT(filterRecent()));
175
176
    m_actionFilters = new QActionGroup(this);
177
    m_actionFilters->addAction(m_actionAll);
178
    m_actionFilters->addAction(m_actionRecent);
179
    m_actionFilters->addAction(m_actionFav);
180
    m_actionFilters->setExclusive(true);
181
    m_mainPage->addActions(m_actionFilters->actions());
182
    connect(m_actionFilters, SIGNAL(triggered(QAction*)), this, SLOT(menuFilterSelected(QAction*)));
183
184
    connect(m_people, SIGNAL(itemClicked(QModelIndex)),
185
            this, SLOT(createDetailPage(QModelIndex)));
186
    connect(m_people, SIGNAL(editRequest(QModelIndex)),
187
            this, SLOT(createEditPage(QModelIndex)));
188
189
    connect(m_people, SIGNAL(callNumber(const QString&)),
190
            this, SLOT(callNumber(const QString&)));
191
    connect(m_people, SIGNAL(composeSMS(const QString&)),
192
            this, SLOT(composeSMS(const QString&)));
193
    connect(m_people, SIGNAL(composeIM(const QString&)),
194
            this, SLOT(composeIM(const QString&)));
195
    connect(m_people, SIGNAL(composeEmail(const QString&)),
196
            this, SLOT(composeEmail(const QString&)));
197
198
    m_mainPage->appear();
199
200
    initSlider();
201
    initSearch();
202
    repositionOverlays();
203
}
204
205
void PeopleApplication::menuFilterSelected(QAction* filter){ 
206
  filter->setChecked(true);
207
  /*Hack for "font().setBold" not working BMC#??? */
208
  (m_actionAll->isChecked())    ? m_actionAll->setText(QObject::tr("<b>Show All</b>","Menu filter to show all contacts"))  : m_actionAll->setText(QObject::tr("Show All","Menu filter to show all contacts"));
209
  (m_actionRecent->isChecked()) ? m_actionRecent->setText(QObject::tr("<b>Show Recent</b>","Menu filter to show all contacts with recent communications")): m_actionRecent->setText(QObject::tr("Show Recent","Menu filter to show all contacts with recent communications"));
210
  (m_actionFav->isChecked())    ? m_actionFav->setText(QObject::tr("<b>Show Favorites</b>", "Menu filter to show all contacts marked as favorites"))    : m_actionFav->setText(QObject::tr("Show Favorites", "Menu filter to show all contacts marked as favorites"));
211
}
212
213
void PeopleApplication::createDetailPage(const QModelIndex &index)
214
{
215
    if (m_detailPage)
216
        return;
217
218
    if (!index.isValid())
219
        return;
220
221
    searchCancel();
222
223
    m_currentIndex = index;
224
225
    m_currentPerson = new SeasidePerson(index);
226
    m_currentPerson->setViewType("personDetail");
227
228
    connect(m_currentPerson, SIGNAL(callNumber(const QString&)),
229
            this, SLOT(callNumber(const QString&)));
230
    connect(m_currentPerson, SIGNAL(composeIM(const QString&)),
231
            this, SLOT(composeIM(const QString&)));
232
    connect(m_currentPerson, SIGNAL(composeSMS(const QString&)),
233
            this, SLOT(composeSMS(const QString&)));
234
    connect(m_currentPerson, SIGNAL(composeEmail(const QString&)),
235
            this, SLOT(composeEmail(const QString&)));
236
    connect(m_currentPerson, SIGNAL(viewRequest(qreal,qreal)),
237
            this, SLOT(scrollIntoView(qreal,qreal)));
238
239
    m_detailPage = new MApplicationPage;
240
    m_detailPage->setTitle(QObject::tr("Contact Detail","Title for detail view"));
241
    m_detailPage->setCentralWidget(m_currentPerson);
242
243
    MAction *action = new MAction(QObject::tr("<b>Edit</b>","Edit toolbar button to edit contact details"), this);
244
    action->setLocation(MAction::ApplicationMenuLocation);
245
    m_detailPage->addAction(action);
246
    connect(action, SIGNAL(triggered()), this, SLOT(editCurrent()));
247
248
    connect(m_detailPage, SIGNAL(backButtonClicked()), this, SLOT(detailBack()));
249
250
    m_detailPage->appear(MApplicationPage::DestroyWhenDismissed);
251
}
252
253
void PeopleApplication::createCommPage(SeasidePersonModel *pm, CommCat type)
254
{
255
    if (m_commPage)
256
        return;
257
258
    searchCancel();
259
260
    m_commPage = new PersonCommsPage(pm, type);
261
262
    connect(m_commPage, SIGNAL(backButtonClicked()),
263
            this, SLOT(commBack()));
264
265
    switch (type) {
266
    case CatCall:
267
        connect(m_commPage, SIGNAL(destSelected(QString)),
268
                this, SLOT(callNumber(QString)));
269
        break;
270
271
    case CatSMS:
272
        connect(m_commPage, SIGNAL(destSelected(QString)),
273
                this, SLOT(composeSMS(QString)));
274
        break;
275
276
    case CatIM:
277
      connect(m_commPage, SIGNAL(destSelectedIM(QString)),
278
              this, SLOT(composeIM(QString)));
279
      break;
280
281
    case CatEmail:
282
        connect(m_commPage, SIGNAL(destSelected(QString)),
283
                this, SLOT(composeEmail(QString)));
284
        break;
285
    }
286
    connect(m_commPage, SIGNAL(destSelected(QString)),
287
            this, SLOT(commBack()));
288
289
    m_commPage->appear(MApplicationPage::DestroyWhenDismissed);
290
}
291
292
void PeopleApplication::initSlider()
293
{
294
    QString alphabet = QObject::tr("A B C D E F G H I J K L M N O P Q R S T U V W X Y Z","Capital letter alphabet");
295
296
    m_sliderH = new SeasideSlider(M::Landscape);
297
    m_sliderH->setObjectName("SeasideSliderLandscape");
298
    m_sliderH->setStops(alphabet.split(QChar(' ')));
299
    m_sliderH->setParentItem(m_mainPage);
300
    m_sliderH->setZValue(1);
301
    m_sliderH->setPreferredWidth(m_window->width());
302
303
    m_sliderV = new SeasideSlider(M::Portrait);
304
    m_sliderV->setObjectName("SeasideSliderPortrait");
305
    m_sliderV->setStops(alphabet.split(QChar(' ')));
306
    m_sliderV->setParentItem(m_mainPage);
307
    m_sliderV->setZValue(1);
308
309
    connect(m_sliderH, SIGNAL(stopActivated(int,QString)),
310
            this, SLOT(sliderActivated(int,QString)));
311
    connect(m_sliderV, SIGNAL(stopActivated(int,QString)),
312
            this, SLOT(sliderActivated(int,QString)));
313
    connect(m_people, SIGNAL(scrollRequest(qreal)),
314
            this, SLOT(scrollTo(qreal)));
315
    connect(m_mainPage, SIGNAL(exposedContentRectChanged()),
316
            this, SLOT(repositionOverlays()));
317
}
318
319
void PeopleApplication::initSearch()
320
{
321
    m_searchWidget = new MWidgetController;
322
    m_searchWidget->setViewType("background");
323
    m_searchWidget->setObjectName("PeopleSearch");
324
    m_searchWidget->setParentItem(m_mainPage);
325
    m_searchWidget->setZValue(1);
326
    m_searchWidget->hide();
327
328
    QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Horizontal, m_searchWidget);
329
330
    m_searchEdit = new MTextEdit;
331
    m_searchEdit->setObjectName("PeopleSearchEdit");
332
    m_searchEdit->setPrompt(QObject::tr("Tap to start searching people","Prompt for search bar text edit field"));
333
    layout->addItem(m_searchEdit);
334
    layout->setAlignment(m_searchEdit, Qt::AlignVCenter);
335
    connect(m_searchEdit, SIGNAL(returnPressed()), this, SLOT(searchCommit()));
336
337
    // uncomment this line to enable dynamic search
338
    //connect(m_searchEdit, SIGNAL(textChanged()), this, SLOT(searchChanged()));
339
340
    MButton *button = new MButton();
341
    button->setIconID("icon-m-framework-close-alt");
342
    button->setObjectName("PeopleSearchButton");
343
    layout->addItem(button);
344
    layout->setAlignment(button, Qt::AlignVCenter);
345
    connect(button, SIGNAL(clicked()), this, SLOT(searchClear()));
346
347
    button = new MButton(QObject::tr("<b>Search</b>","Toolbar button to launch search widget"));
348
    button->setObjectName("PeopleSearchButton");
349
    layout->addItem(button);
350
    layout->setAlignment(button, Qt::AlignVCenter);
351
    connect(button, SIGNAL(clicked()), this, SLOT(searchCommit()));
352
}
353
354
void PeopleApplication::searchClicked()
355
{
356
    m_searchWidget->show();
357
    //force keyboard to pop-up
358
    m_searchEdit->setFocus(Qt::TabFocusReason);
359
    emit QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier);
360
    m_bottomSpacer->setPreferredHeight(m_searchWidget->size().height());
361
}
362
363
void PeopleApplication::searchClear()
364
{
365
    if (m_searchEdit) {
366
        m_searchEdit->clear();
367
        m_searchEdit->setFocus();
368
    }
369
}
370
371
void PeopleApplication::searchChanged()
372
{
373
    if (m_searchEdit)
374
        m_people->filterSearch(m_searchEdit->text());
375
}
376
377
void PeopleApplication::searchCancel()
378
{
379
    if (m_searchEdit)
380
        m_searchEdit->clearFocus();
381
382
    if (m_searchWidget) {
383
        m_searchWidget->hide();
384
        m_bottomSpacer->setPreferredHeight(0);
385
    }
386
}
387
388
void PeopleApplication::searchCommit()
389
{
390
    searchChanged();
391
    searchCancel();
392
}
393
394
void PeopleApplication::addNewContact()
395
{
396
    // there should be no current index or person set, but just in case...
397
    m_currentIndex = QModelIndex();
398
    m_currentPerson = NULL;
399
    createEditPage(m_currentIndex, QObject::tr("Add Contact","Page title for Edit Screen"));
400
}
401
402
void PeopleApplication::detailBack()
403
{
404
    m_currentIndex = QModelIndex();
405
    m_currentPerson = NULL;
406
    if (m_detailPage) {
407
        m_detailPage->dismiss();
408
        m_detailPage = NULL;
409
    }
410
}
411
412
void PeopleApplication::commBack()
413
{
414
    if (m_commPage) {
415
        m_commPage->dismiss();
416
        m_commPage = NULL;
417
    }
418
}
419
420
421
void PeopleApplication::editCurrent()
422
{
423
    createEditPage(m_currentIndex);
424
}
425
426
void PeopleApplication::createEditPage(const QModelIndex &index, const QString& title)
427
{
428
    if (m_editPage)
429
        return;
430
431
    QModelIndex useIndex;
432
433
    if (index.isValid())
434
        useIndex = index;
435
    else
436
        useIndex = m_currentIndex;
437
438
    if (useIndex.isValid())
439
        m_editModel = SeasideSyncModel::createPersonModel(useIndex);
440
    else  // create empty edit model to add new contact
441
        m_editModel = new SeasidePersonModel;
442
    MWidgetController *person = new MWidgetController(m_editModel);
443
    person->setViewType("personEdit");
444
445
    m_editModelModified = false;
446
    connect(m_editModel, SIGNAL(modified(QList<const char*>)),
447
            this, SLOT(editModified()));
448
449
    m_editPage = new MApplicationPage;
450
    if (title.isNull())
451
        m_editPage->setTitle(QObject::tr("Edit Contact","Title for edit screen"));
452
    else
453
        m_editPage->setTitle(title);
454
    m_editPage->setCentralWidget(person);
455
456
    MAction *action = new MAction(QObject::tr("<b>Save</b>","Save toolbar button for edit screen"), this);
457
    action->setLocation(MAction::ApplicationMenuLocation);
458
    m_editPage->addAction(action);
459
    connect(action, SIGNAL(triggered()), this, SLOT(editSave()));
460
461
    connect(m_editPage, SIGNAL(backButtonClicked()), this, SLOT(editBack()));
462
463
    m_editPage->appear(MApplicationPage::DestroyWhenDismissed);
464
}
465
466
void PeopleApplication::editModified()
467
{
468
    m_editModelModified = true;
469
}
470
471
void PeopleApplication::editSave()
472
{
473
    if (m_editModel && m_editModelModified && !m_editModel->isEmpty()) {
474
        m_realModel->updatePerson(m_editModel);
475
        if (m_currentPerson)
476
            m_currentPerson->setModel(m_realModel->createPersonModel(m_editModel->uuid()));
477
        m_editPage->dismiss();
478
        m_editPage = NULL;
479
    }
480
}
481
482
void PeopleApplication::editBack()
483
{
484
    if (m_editPage) {
485
        m_editPage->dismiss();
486
        m_editPage = NULL;
487
    }
488
}
489
490
void PeopleApplication::showDetailsPage(const QContactLocalId& id){
491
  qDebug() << "PeopleApplication::showDetailsPage id" << id;
492
    QModelIndex index = m_realModel->getModelIndex(id);   
493
  qDebug() << "PeopleApplication::showDetailsPage index" << index;
494
    createDetailPage(index);
495
}
496
497
void PeopleApplication::setThumbnailPath(const QUuid& id, const QString& path){
498
    qDebug() << "PeopleApplication::setThumbnailPath id" << id << " path " << path;
499
    m_realModel->setAvatar(id, path);
500
}
501
502
void PeopleApplication::callNumber(const QString& number)
503
{
504
    qDebug() << "PeopleApplication::callNumber attempting call to:" << number;
505
506
    if(QDBusConnection::sessionBus().interface()->isServiceRegistered("com.meego.dialer")){
507
      qDebug() << "PeopleApplication::callNumber dialer is registered";
508
	callNumberToActiveService(number);	    
509
	return;
510
    }else{
511
      qDebug() << "PeopleApplication::callNumber dialer is NOT registered";
512
      QDBusReply<void> reply = QDBusConnection::sessionBus().interface()->startService("com.meego.dialer");
513
      if (!reply.isValid()){
514
	qWarning() << "Starting Dialer failed:" << reply.error().message();  
515
      }else{
516
      qDebug() << "PeopleApplication::callNumber saving number to call on registration";
517
	m_callPending = true;
518
	m_number = number;
519
      }           
520
    }
521
}
522
523
void PeopleApplication::handleDialerRegistered(){
524
      qDebug() << "PeopleApplication::handleDialerRegistered dialer is registered";
525
  if(m_callPending){
526
    qDebug() << "PeopleApplication::handleDialerRegistered call is pending so make call";
527
    m_callPending = false;
528
    callNumberToActiveService(m_number);	    
529
    m_number = "";
530
  }
531
}
532
533
void PeopleApplication::callNumberToActiveService(const QString& number){
534
535
  // hard-coded details of the MeeGo Dialer application
536
  QDBusInterface dialer("com.meego.dialer", "/com/meego/dialer",
537
			"com.meego.dialer");
538
  if (!dialer.isValid()) {
539
    qWarning() << "Dialing" << number << "- could not find dialer app";
540
    return;
541
  }
542
543
  QDBusReply<void> reply = dialer.call(QDBus::BlockWithGui, "call", number);
544
  if (!reply.isValid())
545
    qWarning() << "Dialing" << number << "failed:" <<
546
      reply.error().message();        
547
}
548
549
void PeopleApplication::composeSMS(const QString& number)
550
{
551
  qDebug() << "Attempting to compose SMS to" << number;
552
553
  if(QDBusConnection::sessionBus().interface()->isServiceRegistered("com.meego.sms")){
554
    qDebug() << "PeopleApplication::composeSMS SMS is registered";
555
    smsNumberToActiveService(number);	    
556
    return;
557
  }else{
558
    qDebug() << "PeopleApplication::composeSMS SMS is NOT registered";
559
    QDBusReply<void> reply = QDBusConnection::sessionBus().interface()->startService("com.meego.sms");
560
    if (!reply.isValid()){
561
      qWarning() << "Starting SMS failed:" << reply.error().message();  
562
    }else{
563
      qDebug() << "PeopleApplication::composeSMS saving number to text on registration";
564
      m_smsPending = true;
565
      m_smsNumber = number;
566
    }           
567
  }
568
}
569
570
void PeopleApplication::handleSMSRegistered(){
571
  qDebug() << "PeopleApplication::handleSMSRegistered sms is registered";
572
  if(m_smsPending){
573
    qDebug() << "PeopleApplication::handleSMSRegistered text is pending so compose msg";
574
    m_smsPending = false;
575
    smsNumberToActiveService(m_smsNumber);	    
576
    m_smsNumber = "";
577
  }
578
}
579
580
void PeopleApplication::smsNumberToActiveService(const QString& number){
581
   // hard-coded details of the MeeGo SMS application
582
    QDBusInterface sms("com.meego.sms", "/", "com.meego.sms");
583
    if (!sms.isValid()) {
584
        qWarning() << "Composing SMS to" << number << "- could not find SMS app";
585
        return;
586
    }
587
588
    QDBusReply<void> reply = sms.call(QDBus::BlockWithGui, "showdialogpage", number);
589
    if (!reply.isValid())
590
        qWarning() << "Composing SMS to" << number << "failed:" <<
591
                reply.error().message();
592
}
593
594
void PeopleApplication::composeIM(const QString& accountString)
595
{
596
    qDebug() << "called composeIM" << accountString;
597
    QStringList list = accountString.split(":");
598
    if(list.count() != 3){
599
        qDebug() << "PeopleApplication::composeIM had invalid accountname";
600
        return;
601
    }
602
603
    QString accountPath = list.at(2);
604
    QString accountUri = list.at(0);
605
    //index=1 is nickname, not used here
606
607
    qDebug() << "Attempting to compose IM to accountPath: " << accountPath <<" accountUri: " << accountUri;
608
609
  if(QDBusConnection::sessionBus().interface()->isServiceRegistered("com.meego.meego_handset_chat")){
610
    qDebug() << "PeopleApplication::composeIM IM is registered";
611
    imToActiveService(accountString);
612
    return;
613
  }else{
614
    qDebug() << "PeopleApplication::composeIM IM is NOT registered";
615
    QDBusReply<void> reply = QDBusConnection::sessionBus().interface()->startService("com.meego.meego_handset_chat");
616
    if (!reply.isValid()){
617
      qWarning() << "Starting IM failed:" << reply.error().message();  
618
    }else{
619
      qDebug() << "PeopleApplication::composeIM saving info to IM on registration";
620
      m_imPending = true;
621
      m_imAccount = accountString;
622
    }           
623
  }
624
}
625
626
void PeopleApplication::handleIMRegistered(){
627
  qDebug() << "PeopleApplication::handleIMRegistered IM is registered";
628
  if(m_imPending){
629
    qDebug() << "PeopleApplication::handleIMRegistered im is pending so compose im";
630
    m_imPending = false;
631
    imToActiveService(m_imAccount);	    
632
    m_imAccount = "";
633
  }
634
}
635
636
void PeopleApplication::imToActiveService(const QString& account){
637
  QStringList list = account.split(":");
638
  if(list.count() != 3)
639
    return;
640
641
  QString accountPath = list.at(2);
642
  QString accountUri = list.at(0);
643
  //index=1 is nickname, not used here
644
645
  // hard-coded details of the MeeGo IM application
646
  QDBusInterface im("com.meego.meego_handset_chat", "/com/meego/meego_handset_chat", "com.meego.meego_handset_chat");
647
  if (!im.isValid()) {
648
    qWarning() << "Composing IM to path: " <<accountPath << " accountUri: " << accountUri << "- could not find IM app";
649
    return;
650
  }
651
652
  QDBusReply<void> reply = im.call(QDBus::BlockWithGui, "showDialogPageForContact", accountPath , accountUri);
653
  if (!reply.isValid())
654
    qWarning() << "Composing IM to path: " <<accountPath << " accountUri: " << accountUri << "failed:" ;
655
  reply.error().message();
656
}
657
658
void PeopleApplication::composeEmail(const QString& address) 
659
{
660
    qDebug() << "PeopleApplication::composeEmail attempting email:" << address;
661
662
    if(QDBusConnection::sessionBus().interface()->isServiceRegistered("com.meego.email")){
663
      qDebug() << "PeopleApplication::composeEmail email is registered";
664
	emailToActiveService(address);	    
665
	return;
666
    }else{
667
      qDebug() << "PeopleApplication::composeEmail email is NOT registered";
668
      QDBusReply<void> reply = QDBusConnection::sessionBus().interface()->startService("com.meego.email");
669
      if (!reply.isValid()){
670
	qWarning() << "Starting Email failed:" << reply.error().message();  
671
      }else{
672
      qDebug() << "PeopleApplication::composeEmail saving address to email on registration";
673
	m_emailPending = true;
674
	m_email = address;
675
      }           
676
    }
677
}
678
679
void PeopleApplication::handleEmailRegistered(){
680
      qDebug() << "PeopleApplication::handleEmailRegistered email is registered";
681
  if(m_emailPending){
682
    qDebug() << "PeopleApplication::handleEmailRegistered email is pending so compose msg  ";
683
    m_emailPending = false;
684
    emailToActiveService(m_email);	    
685
    m_email = "";
686
  }
687
}
688
689
void PeopleApplication::emailToActiveService(const QString& address){
690
    qDebug() << "Attempting to compose Email to" << address;
691
692
    // hard-coded details of the MeeGo Email application
693
    QDBusInterface email("com.meego.email", "/", "com.meego.email");
694
    if (!email.isValid()) {
695
        qWarning() << "Composing Email to" << address << "- could not find Email app";
696
        return;
697
    }
698
699
    QDBusReply<void> reply = email.call(QDBus::BlockWithGui, "showComposePage", address);
700
    if (!reply.isValid())
701
        qWarning() << "Composing Email to" << address << "failed:" <<
702
                reply.error().message();
703
}
704
705
void PeopleApplication::sliderActivated(int index, const QString& stop)
706
{
707
    Q_UNUSED(index)
708
    m_people->scrollTo(stop);
709
}
710
711
void PeopleApplication::repositionOverlays()
712
{
713
    QRectF exposed = m_mainPage->exposedContentRect();
714
715
    if (m_window->orientation() == M::Landscape) {
716
        m_sliderH->setPos(0, exposed.y());
717
        m_sliderH->show();
718
        m_sliderV->hide();
719
        m_topSpacer->setPreferredHeight(m_sliderH->preferredHeight());
720
        m_mainPage->layout()->setContentsMargins(0, 0, 0, 0);
721
    }
722
    else {
723
       int width = m_sliderV->preferredWidth();
724
       m_sliderV->setPos(exposed.width() - width, exposed.y());
725
        m_sliderV->setPreferredHeight(m_sliderH->preferredWidth()-exposed.y());
726
        m_sliderH->hide();
727
        m_sliderV->show();
728
        m_topSpacer->setPreferredHeight(0);
729
        m_mainPage->layout()->setContentsMargins(0, 0, m_sliderV->preferredWidth(), 0);
730
    }
731
732
    if (m_searchWidget)
733
        m_searchWidget->setPos(0, exposed.bottom() - m_searchWidget->preferredHeight());
734
}
735
736
void PeopleApplication::scrollTo(qreal pos)
737
{
738
    // effects: scrolls to the given vertical position, up to the maximum
739
740
    MApplicationPage *page = activeApplicationWindow()->currentPage();
741
    QGraphicsWidget *widget = page->centralWidget();
742
    MPannableWidget *viewport = page->pannableViewport();
743
    if (!widget || !viewport)
744
        return;
745
746
    QRectF exposed = page->exposedContentRect();
747
    int max = widget->size().height() - exposed.height();
748
    if (pos > max)
749
        pos = max;
750
751
    viewport->physics()->stop();
752
    viewport->physics()->setPosition(QPointF(0, pos));
753
}
754
755
void PeopleApplication::scrollIntoView(qreal ypos, qreal height)
756
{
757
    // effects: scrolls the defined vertical area into view, or as much as possible
758
759
    MApplicationPage *page = activeApplicationWindow()->currentPage();
760
    QGraphicsWidget *widget = page->centralWidget();
761
    MPannableWidget *viewport = page->pannableViewport();
762
    if (!widget || !viewport)
763
        return;
764
765
    QRectF exposed = page->exposedContentRect();
766
    int viewportHeight = exposed.height();
767
768
    qreal scrollpos = viewport->physics()->position().y();
769
770
    // check to see if it's already fully visible
771
    if (scrollpos < ypos && scrollpos + viewportHeight > ypos + height)
772
        return;
773
774
    // if bottom end is off-screen, scroll up until bottom is visible
775
    qreal scrollto = scrollpos;
776
    if (scrollpos + viewportHeight < ypos + height)
777
        scrollto += ypos + height - scrollpos - viewportHeight;
778
779
    // if top end is off-screen, scroll down until top is visible
780
    if (scrollto > ypos)
781
        scrollto = ypos;
782
783
    viewport->physics()->stop();
784
    viewport->physics()->setPosition(QPointF(0, scrollto));
785
}