phonebook.cpp Example File
samplephonebook/phonebook.cpp
#include "phonebook.h"
#include "serialiser.h"
#include "contactdetailsform.h"
#include "maindialogform_640_480.h"
#include "maindialogform_240_320.h"
#include "groupeditdialog.h"
#include "groupdetailsdialog.h"
#include <QDesktopWidget>
#include <QtGui>
PhoneBook::PhoneBook(QWidget *parent)
: QWidget(parent), dialog(0), addingContact(false), editingContact(false)
{
QVBoxLayout *layout = new QVBoxLayout;
QDesktopWidget screenWidget;
if (QApplication::desktop()->width() > 480){
smallScreenSize = false;
mainDialogForm640By480 = new MainDialogForm640By480(this);
mainForm = mainDialogForm640By480;
detailsForm = mainForm;
layout->addWidget(mainForm);
setLayout(layout);
}else{
smallScreenSize = true;
mainDialogForm240By320 = new MainDialogForm240By320(this);
contactDetailsForm = new ContactDetailsForm(mainDialogForm240By320);
mainForm = mainDialogForm240By320;
detailsForm = contactDetailsForm;
layout->addWidget(mainForm);
setLayout(layout);
showMaximized();
}
addButton = qFindChild<QPushButton*>(mainForm, "addButton");
openButton = qFindChild<QPushButton*>(mainForm, "openButton");
removeButton = qFindChild<QPushButton*>(mainForm, "deleteButton");
findButton = qFindChild<QPushButton*>(mainForm, "findButton");
importButton = qFindChild<QPushButton*>(mainForm, "importButton");
exportButton = qFindChild<QPushButton*>(mainForm, "exportButton");
avatarButton = qFindChild<QPushButton*>(mainForm, "avatarButton");
quitButton = qFindChild<QPushButton*>(mainForm, "quitButton");
if(!avatarButton)
avatarButton = qFindChild<QPushButton*>(detailsForm, "avatarButton");
saveButton = qFindChild<QPushButton*>(mainForm, "saveButton");
if(!saveButton)
saveButton = qFindChild<QPushButton*>(detailsForm, "saveButton");
cancelButton = qFindChild<QPushButton*>(detailsForm, "cancelButton");
groupsButton = qFindChild<QPushButton*>(detailsForm, "groupsButton");
avatarButton->installEventFilter(this);
removeButton->setEnabled(false);
findButton->setEnabled(false);
saveButton->setEnabled(true);
exportButton->setEnabled(false);
nameLine = qFindChild<QLineEdit*>(detailsForm, "nameEdit");
avatarPixmapLabel = qFindChild<QLabel*>(detailsForm, "avatarPixmapLabel");
emailLine = qFindChild<QLineEdit*>(detailsForm, "emailEdit");
homePhoneLine = qFindChild<QLineEdit*>(detailsForm, "homePhoneEdit");
workPhoneLine = qFindChild<QLineEdit*>(detailsForm, "workPhoneEdit");
mobilePhoneLine = qFindChild<QLineEdit*>(detailsForm, "mobilePhoneEdit");
addressText = qFindChild<QPlainTextEdit*>(detailsForm, "addressEdit");
contactsList = qFindChild<QListWidget*>(mainForm, "contactListWidget");
currentIndexLabel = qFindChild<QLabel*>(mainForm, "contactStatusLabel");
backendCombo = qFindChild<QComboBox*>(mainForm, "contactEngineComboBox");
QStringList availableManagers = QContactManager::availableManagers();
foreach (const QString manager, availableManagers)
backendCombo->addItem(manager);
connect(backendCombo, SIGNAL(currentIndexChanged(QString)), this, SLOT(backendSelected(QString)));
if(cancelButton)
connect(cancelButton, SIGNAL(clicked()), this, SLOT(cancelContact()));
if(openButton){
connect(openButton, SIGNAL(clicked()), this, SLOT(openContact()));
openButton->setEnabled(false);
}
connect(avatarButton, SIGNAL(clicked()), this, SLOT(selectAvatar()));
connect(addButton, SIGNAL(clicked()), this, SLOT(addContact()));
connect(saveButton, SIGNAL(clicked()), this, SLOT(saveContact()));
connect(removeButton, SIGNAL(clicked()), this, SLOT(removeContact()));
connect(findButton, SIGNAL(clicked()), this, SLOT(findContact()));
connect(importButton, SIGNAL(clicked()), this, SLOT(importFromVCard()));
connect(exportButton, SIGNAL(clicked()), this, SLOT(exportAsVCard()));
if(quitButton)
connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
connect(groupsButton, SIGNAL(clicked()), this, SLOT(editGroupDetails()));
connect(contactsList, SIGNAL(currentRowChanged(int)), this, SLOT(contactSelected(int)));
if (smallScreenSize){
connect(detailsForm, SIGNAL(accepted()), this, SLOT(saveContact()));
connect(detailsForm, SIGNAL(rejected()), this, SLOT(cancelContact()));
}
setWindowTitle(tr("Sample Phone Book"));
cm = 0;
backendSelected(backendCombo->currentText());
}
PhoneBook::~PhoneBook()
{
foreach (const QContactManager* manager, managers.values())
delete manager;
}
void PhoneBook::backendChanged(const QList<QContactLocalId>& changes)
{
QContactDetailFilter contactFilter;
contactFilter.setDetailDefinitionName(QContactType::DefinitionName, QContactType::FieldType);
contactFilter.setValue(QString(QLatin1String(QContactType::TypeContact)));
QList<QContactLocalId> contactIds = cm->contacts(contactFilter);
contacts.clear();
foreach (const QContactLocalId cid, contactIds)
contacts.append(cm->contact(cid));
qDebug() << "backend changed, and now have" << contactIds.size() << "contacts which are TypeContact!";
populateList(cm->contact(changes.value(0)));
if (!contacts.isEmpty()){
displayContact();
} else {
nameLine->setText(QString());
emailLine->setText(QString());
homePhoneLine->setText(QString());
workPhoneLine->setText(QString());
mobilePhoneLine->setText(QString());
addressText->setPlainText(QString());
avatarPixmapLabel->clear();
updateButtons();
}
}
void PhoneBook::backendSelected(const QString& backend)
{
currentIndex = -1;
if (cm)
cm->disconnect();
if (managers.value(backend, 0) != 0) {
cm = managers.value(backend);
} else {
cm = new QContactManager(backend);
managers.insert(backend, cm);
}
connect(cm, SIGNAL(contactsAdded(const QList<QContactLocalId>&)), this, SLOT(backendChanged(const QList<QContactLocalId>&)));
connect(cm, SIGNAL(contactsChanged(const QList<QContactLocalId>&)), this, SLOT(backendChanged(const QList<QContactLocalId>&)));
connect(cm, SIGNAL(contactsRemoved(const QList<QContactLocalId>&)), this, SLOT(backendChanged(const QList<QContactLocalId>&)));
backendChanged(QList<QContactLocalId>());
}
bool PhoneBook::eventFilter(QObject* watched, QEvent* event)
{
if (watched == avatarButton && event->type() == QEvent::Resize) {
QResizeEvent *re = (QResizeEvent*)event;
QSize trim(20,20);
QSize newSize = re->size();
newSize -= trim;
avatarButton->setIconSize(newSize);
return true;
}
return false;
}
void PhoneBook::contactSelected(int row)
{
if (row < 0)
return;
while (currentIndex > row) {
previous();
}
while (currentIndex < row) {
next();
}
}
void PhoneBook::populateList(const QContact& currentContact)
{
QList<QContact> sorted;
if (contacts.size() > 0) {
sorted.append(contacts.at(0));
contacts.removeFirst();
}
foreach (const QContact& contact, contacts) {
bool inserted = false;
for (int i = 0; i < sorted.size(); i++) {
QContact sortedContact = sorted.at(i);
QContactDisplayLabel cdl = contact.detail(QContactDisplayLabel::DefinitionName);
QContactDisplayLabel sdl = sortedContact.detail(QContactDisplayLabel::DefinitionName);
if (cdl.label().toLower() < sdl.label().toLower()) {
sorted.insert(i, contact);
inserted = true;
break;
}
}
if (!inserted) {
sorted.append(contact);
}
}
contacts = sorted;
contactsList->clear();
foreach (const QContact& contact, contacts) {
new QListWidgetItem(contact.displayLabel(), contactsList);
}
currentIndex = 0;
for (int i = 0; i < contacts.size(); i++) {
if (contacts.at(i) == currentContact) {
currentIndex = i;
break;
}
}
contactsList->setCurrentRow(currentIndex);
}
QContact PhoneBook::buildContact() const
{
QContact c;
QContactName contactName = buildName(nameLine->text());
c.saveDetail(&contactName);
QContactEmailAddress emailAddress;
emailAddress.setEmailAddress(emailLine->text());
c.saveDetail(&emailAddress);
QContactPhoneNumber homePhone;
homePhone.setNumber(homePhoneLine->text());
homePhone.setContexts(QStringList(QContactDetail::ContextHome));
homePhone.setSubTypes(QStringList(QContactPhoneNumber::SubTypeLandline));
homePhone.setSubTypes(QStringList(QContactPhoneNumber::SubTypeVoice));
c.saveDetail(&homePhone);
QContactPhoneNumber workPhone;
workPhone.setNumber(workPhoneLine->text());
workPhone.setContexts(QStringList(QContactDetail::ContextWork));
workPhone.setSubTypes(QStringList(QContactPhoneNumber::SubTypeLandline));
workPhone.setSubTypes(QStringList(QContactPhoneNumber::SubTypeVoice));
c.saveDetail(&workPhone);
QContactPhoneNumber mobilePhone;
mobilePhone.setNumber(mobilePhoneLine->text());
mobilePhone.setSubTypes(QStringList(QContactPhoneNumber::SubTypeMobile));
c.saveDetail(&mobilePhone);
QContactAddress address;
address.setStreet(addressText->toPlainText());
address.setSubTypes(QStringList() << QContactAddress::SubTypeDomestic << QContactAddress::SubTypeParcel << QContactAddress::SubTypePostal);
if (!address.street().isEmpty())
c.saveDetail(&address);
return c;
}
QContactName PhoneBook::buildName(const QString &name) const
{
QContactName contactName;
QContactDetailDefinition nameDef = cm->detailDefinition(QContactName::DefinitionName, QContactType::TypeContact);
if(nameDef.fields().contains(QContactName::FieldCustomLabel)) {
contactName.setCustomLabel(name);
} else if(nameDef.fields().contains(QContactName::FieldFirst)) {
contactName.setFirst(name);
} else if(nameDef.fields().contains(QContactName::FieldLast)) {
contactName.setLast(name);
}
return contactName;
}
void PhoneBook::displayContact()
{
QContact c = contacts.value(currentIndex);
c = cm->contact(c.id().localId());
QContactId contactUri = c.id();
QList<QContactRelationship> relationships = cm->relationships(QContactRelationship::HasMember, contactUri);
QList<QContactLocalId> currentGroups;
foreach (const QContactRelationship& currRel, relationships) {
if (currRel.second() == contactUri) {
currentGroups.append(currRel.first().localId());
}
}
contactGroups = currentGroups;
nameLine->setText(c.displayLabel());
emailLine->setText(c.detail(QContactEmailAddress::DefinitionName).value(QContactEmailAddress::FieldEmailAddress));
QList<QContactDetail> phns = c.details(QContactPhoneNumber::DefinitionName);
bool foundHomePhone = false;
bool foundWorkPhone = false;
bool foundMobilePhone = false;
for (int i = 0; i < phns.size(); i++) {
QContactPhoneNumber current = phns.at(i);
if (current.subTypes().contains(QContactPhoneNumber::SubTypeMobile)) {
mobilePhoneLine->setText(current.number());
foundMobilePhone = true;
} else if (current.contexts().contains(QContactDetail::ContextWork)) {
workPhoneLine->setText(current.number());
foundWorkPhone = true;
} else {
homePhoneLine->setText(current.number());
foundHomePhone = true;
}
}
if (!foundHomePhone)
homePhoneLine->setText("");
if (!foundWorkPhone)
workPhoneLine->setText("");
if (!foundMobilePhone)
mobilePhoneLine->setText("");
addressText->setPlainText((QContactAddress(c.detail(QContactAddress::DefinitionName))).street());
QString avatarFile = c.detail(QContactAvatar::DefinitionName).value(QContactAvatar::FieldAvatar);
if (avatarFile.isNull() || avatarFile.isEmpty()) {
avatarPixmapLabel->clear();
} else {
QPixmap avatarPix(avatarFile);
avatarPixmapLabel->setPixmap(avatarPix.scaled(avatarPixmapLabel->size()));
}
updateButtons();
}
void PhoneBook::selectAvatar()
{
QString supportedImageFormats;
for (int formatIndex = 0; formatIndex < QImageReader::supportedImageFormats().count(); formatIndex++) {
supportedImageFormats += QLatin1String(" *.") + QImageReader::supportedImageFormats()[formatIndex];
}
QString selected = QFileDialog::getOpenFileName(detailsForm, "Select avatar image file", ".", tr("Images (%1)").arg(supportedImageFormats));
if (!selected.isNull()) {
QContact curr = contacts.at(currentIndex);
QContactAvatar av = curr.detail(QContactAvatar::DefinitionName);
av.setAvatar(selected);
curr.saveDetail(&av);
contacts.replace(currentIndex, curr);
QPixmap avatarPix;
if (avatarPix.load(selected)){
avatarPixmapLabel->setPixmap(avatarPix.scaled(avatarPixmapLabel->size()));
}else{
qWarning() << "Unable to load avatar" << selected;
qWarning() << "Supported image formats are " << supportedImageFormats << " ;" << QImageReader::supportedImageFormats();
avatarPixmapLabel->clear();
}
}
}
void PhoneBook::addContact()
{
if (addingContact)
saveContact();
QMessageBox msgBox(QMessageBox::Question, tr("Add Contact or Group"), tr("Add Contact or Group"), QMessageBox::NoButton, this);
QAbstractButton *addContactButton = msgBox.addButton(tr("Add Contact"), QMessageBox::YesRole);
(void*)msgBox.addButton(tr("Add Group"), QMessageBox::NoRole);
(void)msgBox.exec();
if(msgBox.clickedButton() == addContactButton){
addingContact = true;
lastIndex = currentIndex;
currentIndex = contacts.size();
contacts.append(QContact());
displayContact();
nameLine->setFocus();
if (smallScreenSize){
contactDetailsForm->showMaximized();
if (contactDetailsForm->exec() == QDialog::Accepted)
saveContact();
}
}else{
GroupEditDialog grpDialog(this, cm);
if (smallScreenSize)
grpDialog.showMaximized();
(void)grpDialog.exec();
}
}
void PhoneBook::saveContact()
{
if (smallScreenSize && !(addingContact || editingContact))
return;
addingContact = false;
editingContact = false;
if (smallScreenSize){
contactDetailsForm->accept();
showMaximized();
}
QContact c = buildContact();
c.setId(contacts.at(currentIndex).id());
QContactAvatar av = contacts.at(currentIndex).detail(QContactAvatar::DefinitionName);
c.saveDetail(&av);
if (!cm->saveContact(&c)) {
QString errorCode = "Unable to save the contact in the database; error code:" + QString::number(cm->error());
QMessageBox::information(this, "Save Failed", errorCode);
return;
}
}
void PhoneBook::updateButtons()
{
QString currentState = "Unsaved";
if (!contacts.count() || (contacts.at(currentIndex).id() == QContactId())) {
addButton->setEnabled(true);
findButton->setEnabled(false);
exportButton->setEnabled(false);
removeButton->setEnabled(false);
saveButton->setEnabled(addingContact || editingContact);
if(openButton)
openButton->setEnabled(false);
if (!smallScreenSize){
nameLine->setEnabled(addingContact);
emailLine->setEnabled(addingContact);
homePhoneLine->setEnabled(addingContact);
workPhoneLine->setEnabled(addingContact);
mobilePhoneLine->setEnabled(addingContact);
addressText->setEnabled(addingContact);
avatarButton->setEnabled(addingContact);
}
} else {
addButton->setEnabled(!(addingContact || editingContact));
findButton->setEnabled(true);
exportButton->setEnabled(true);
removeButton->setEnabled(true);
saveButton->setEnabled((mainForm == detailsForm) || addingContact || editingContact);
if(openButton)
openButton->setEnabled(true);
if (!smallScreenSize){
nameLine->setEnabled(true);
emailLine->setEnabled(true);
homePhoneLine->setEnabled(true);
workPhoneLine->setEnabled(true);
mobilePhoneLine->setEnabled(true);
addressText->setEnabled(true);
avatarButton->setEnabled(true);
}
currentState = "Saved";
}
importButton->setEnabled(!(addingContact || editingContact));
int contactNumber = (contacts.isEmpty() ? 0 : currentIndex + 1);
QString currentIndexLabelString = tr("Contact %1 of %2 (%3)").arg(contactNumber).arg(contacts.size()).arg(currentState);
currentIndexLabel->setText(currentIndexLabelString);
}
void PhoneBook::removeContact()
{
if (currentIndex < 0)
return;
QContact current = contacts.at(currentIndex);
QContactDisplayLabel cdl = current.detail(QContactDisplayLabel::DefinitionName);
QString contactName = cdl.label();
int button = QMessageBox::question(this,
tr("Confirm Remove"),
tr("Are you sure you want to remove \"%1\"?").arg(contactName),
QMessageBox::Yes | QMessageBox::No);
if (button == QMessageBox::Yes) {
cm->removeContact(contacts.at(currentIndex).id().localId());
QMessageBox::information(this, tr("Remove Successful"),
tr("\"%1\" has been removed from your phone book.").arg(contactName));
}
updateButtons();
}
void PhoneBook::next()
{
currentIndex += 1;
displayContact();
}
void PhoneBook::previous()
{
if (contacts.at(currentIndex).id() == QContactId()) {
contacts.removeAt(currentIndex);
}
currentIndex -= 1;
displayContact();
}
void PhoneBook::findContact()
{
dialog = new FindDialog(this);
if (smallScreenSize)
dialog->showMaximized();
if (dialog->exec() == QDialog::Accepted) {
bool found = false;
if (dialog->isSimpleFilterEnabled()){
QString contactName = dialog->getFindText();
for (int i = 0; i < contacts.size(); i++) {
QContact current = contacts.at(i);
QContactDisplayLabel cdl = current.detail(QContactDisplayLabel::DefinitionName);
if (cdl.label() == contactName) {
contactsList->setCurrentRow(i);
contactSelected(i);
found = true;
break;
}
}
if (!found) {
QMessageBox::information(this, tr("Contact Not Found"),
tr("Sorry, \"%1\" is not in your address book.").arg(contactName));
}
}else{
QList<QContactLocalId> matchedContacts = cm->contacts(dialog->getFindFilter());
if (matchedContacts.count()){
QStringList matchedContactNames;
QContact matchedContact;
contactsList->clearSelection();
for (int index = 0; index < matchedContacts.count(); index++){
matchedContact = cm->contact(matchedContacts[index]);
if (!matchedContact.isEmpty())
matchedContactNames.append("\"" + matchedContact.displayLabel() + "\"");
}
QMessageBox::information(this, tr("Contact(s) Found"), tr("Matched contact(s): %1").arg(matchedContactNames.join(",")));
}else{
QMessageBox::information(this, tr("Contact not Found"), tr("No contacts in your addressbook match filter"));
}
}
}
delete dialog;
dialog = 0;
if (smallScreenSize)
showMaximized();
}
void PhoneBook::openContact()
{
editingContact = true;
displayContact();
if (smallScreenSize){
nameLine->setFocus();
if (contactDetailsForm->exec() == QDialog::Accepted)
saveContact();
}else{
detailsForm->show();
}
}
void PhoneBook::cancelContact()
{
if (smallScreenSize && !(addingContact || editingContact))
return;
addingContact = false;
editingContact = false;
if (smallScreenSize){
contactDetailsForm->reject();
showMaximized();
}
currentIndex = lastIndex;
updateButtons();
}
void PhoneBook::importFromVCard()
{
QString importFile = QFileDialog::getOpenFileName(this, "Select vCard file to import", ".", "*.vcf");
if (importFile.isNull())
return;
QContact importedContact;
QFile file(importFile);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox::information(this, tr("Import Failed"),
tr("Sorry, unable to import \"%1\".").arg(importFile));
return;
}
QTextStream in(&file);
QStringList vcardLines;
while (!in.atEnd()) {
vcardLines << in.readLine();
}
if (vcardLines.isEmpty()) {
QMessageBox::information(this, tr("Import Failed"),
tr("Sorry, unable to import \"%1\".").arg(importFile));
return;
}
file.close();
importedContact = Serialiser::convertVcard(vcardLines);
cm->saveContact(&importedContact);
}
void PhoneBook::exportAsVCard()
{
QString newName = QFileDialog::getSaveFileName(this, "Export contact as...", ".", "*.vcf");
if (newName.isNull()) {
return;
}
if (!newName.endsWith(".vcf")) {
newName += ".vcf";
}
QContact currentContact;
if (currentIndex >= contacts.size())
currentContact = buildContact();
else
currentContact = contacts.at(currentIndex);
QStringList vcardLines = Serialiser::convertContact(currentContact);
QFile file(newName);
QContact current = contacts.at(currentIndex);
QContactDisplayLabel cdl = current.detail(QContactDisplayLabel::DefinitionName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::information(this, tr("Unable to export"),
tr("Unable to export contact \"%1\"!").arg(cdl.label()));
return;
}
QTextStream out(&file);
foreach (const QString& line, vcardLines)
out << line << "\n";
file.close();
QMessageBox::information(this, tr("Contact Exported"),
tr("Successfully exported contact \"%1\" as \"%2\"!").arg(cdl.label()).arg(newName));
}
void PhoneBook::editGroupDetails()
{
QContact c = buildContact();
c.setId(contacts.value(currentIndex).id());
GroupDetailsDialog dlg(detailsForm, cm, c);
if (smallScreenSize)
dlg.showMaximized();
if (dlg.exec() == QDialog::Accepted)
contactGroups = dlg.groups();
if (currentIndex < contacts.size())
contacts.replace(currentIndex, c);
}