Commit 43f3c1e4 authored by Edric Milaret's avatar Edric Milaret

contact: implement add to contact feature

- Add right click on history item
	- Copy number to clipboard
	- Add to new Contact
	- Add to existing contact


Issue: #77711
Issue: #77862
Issue: #77859

Change-Id: Ia249707e51c5208abbd67eeb3b04e6ca835bcd75
parent 53971615
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
QT += core gui QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets svg greaterThan(QT_MAJOR_VERSION, 4): QT += widgets svg xml
VERSION = 0.3.0 VERSION = 0.3.0
GIT_VERSION = $$system(git --git-dir $$PWD/.git --work-tree $$PWD describe --always --tags) GIT_VERSION = $$system(git --git-dir $$PWD/.git --work-tree $$PWD describe --always --tags)
...@@ -47,7 +47,9 @@ SOURCES += main.cpp\ ...@@ -47,7 +47,9 @@ SOURCES += main.cpp\
accountstatedelegate.cpp \ accountstatedelegate.cpp \
videoview.cpp \ videoview.cpp \
videooverlay.cpp \ videooverlay.cpp \
imdelegate.cpp imdelegate.cpp \
contactdialog.cpp \
contactpicker.cpp
HEADERS += mainwindow.h \ HEADERS += mainwindow.h \
callwidget.h \ callwidget.h \
...@@ -70,7 +72,9 @@ HEADERS += mainwindow.h \ ...@@ -70,7 +72,9 @@ HEADERS += mainwindow.h \
accountstatedelegate.h \ accountstatedelegate.h \
videoview.h \ videoview.h \
videooverlay.h \ videooverlay.h \
imdelegate.h imdelegate.h \
contactdialog.h \
contactpicker.h
FORMS += mainwindow.ui \ FORMS += mainwindow.ui \
callwidget.ui \ callwidget.ui \
...@@ -83,7 +87,9 @@ FORMS += mainwindow.ui \ ...@@ -83,7 +87,9 @@ FORMS += mainwindow.ui \
wizarddialog.ui \ wizarddialog.ui \
instantmessagingwidget.ui \ instantmessagingwidget.ui \
videoview.ui \ videoview.ui \
videooverlay.ui videooverlay.ui \
contactdialog.ui \
contactpicker.ui
win32: LIBS += -lole32 -luuid -lshlwapi win32: LIBS += -lole32 -luuid -lshlwapi
...@@ -118,7 +124,8 @@ win32 { ...@@ -118,7 +124,8 @@ win32 {
RUNTIME.path = $$OUT_PWD/release RUNTIME.path = $$OUT_PWD/release
QTRUNTIME.files = $$RUNTIMEDIR/Qt5Core.dll $$RUNTIMEDIR/Qt5Widgets.dll \ QTRUNTIME.files = $$RUNTIMEDIR/Qt5Core.dll $$RUNTIMEDIR/Qt5Widgets.dll \
$$RUNTIMEDIR/Qt5Gui.dll $$RUNTIMEDIR/Qt5Svg.dll $$RUNTIMEDIR/Qt5Gui.dll $$RUNTIMEDIR/Qt5Svg.dll \
$$RUNTIMEDIR/Qt5Xml.dll
QTRUNTIME.path = $$OUT_PWD/release QTRUNTIME.path = $$OUT_PWD/release
QTDEPSRUNTIME.files = $$RUNTIMEDIR/zlib1.dll $$RUNTIMEDIR/iconv.dll \ QTDEPSRUNTIME.files = $$RUNTIMEDIR/zlib1.dll $$RUNTIMEDIR/iconv.dll \
......
...@@ -19,10 +19,17 @@ ...@@ -19,10 +19,17 @@
#include "callwidget.h" #include "callwidget.h"
#include "ui_callwidget.h" #include "ui_callwidget.h"
#include <QClipboard>
#include <memory> #include <memory>
//ERROR is defined in windows.h
#include "utils.h"
#undef ERROR
#include "audio/settings.h" #include "audio/settings.h"
#include "personmodel.h" #include "personmodel.h"
#include "person.h"
#include "fallbackpersoncollection.h" #include "fallbackpersoncollection.h"
#include "categorizedcontactmodel.h" #include "categorizedcontactmodel.h"
#include "localhistorycollection.h" #include "localhistorycollection.h"
...@@ -32,6 +39,8 @@ ...@@ -32,6 +39,8 @@
#include "wizarddialog.h" #include "wizarddialog.h"
#include "windowscontactbackend.h" #include "windowscontactbackend.h"
#include "contactdialog.h"
#include "contactpicker.h"
CallWidget::CallWidget(QWidget *parent) : CallWidget::CallWidget(QWidget *parent) :
NavWidget(Main ,parent), NavWidget(Main ,parent),
...@@ -78,14 +87,17 @@ CallWidget::CallWidget(QWidget *parent) : ...@@ -78,14 +87,17 @@ CallWidget::CallWidget(QWidget *parent) :
ui->callList->setModel(callModel_); ui->callList->setModel(callModel_);
ui->callList->setSelectionModel(callModel_->selectionModel()); ui->callList->setSelectionModel(callModel_->selectionModel());
CategorizedHistoryModel::instance()-> auto personCollection = PersonModel::instance()->
addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED); addCollection<WindowsContactBackend>(LoadOptions::FORCE_ENABLED);
PersonModel::instance()-> CategorizedContactModel::instance()->setSortAlphabetical(false);
addCollection<FallbackPersonCollection>(LoadOptions::FORCE_ENABLED); CategorizedContactModel::instance()->setUnreachableHidden(true);
ui->contactView->setModel(CategorizedContactModel::instance());
contactDelegate_ = new ContactDelegate();
ui->contactView->setItemDelegate(contactDelegate_);
PersonModel::instance()-> CategorizedHistoryModel::instance()->
addCollection<WindowsContactBackend>(LoadOptions::FORCE_ENABLED); addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED);
ui->historyList->setModel(CategorizedHistoryModel::SortedProxy::instance()->model()); ui->historyList->setModel(CategorizedHistoryModel::SortedProxy::instance()->model());
CategorizedHistoryModel::SortedProxy::instance()->model()->sort(0, Qt::DescendingOrder); CategorizedHistoryModel::SortedProxy::instance()->model()->sort(0, Qt::DescendingOrder);
...@@ -99,14 +111,63 @@ CallWidget::CallWidget(QWidget *parent) : ...@@ -99,14 +111,63 @@ CallWidget::CallWidget(QWidget *parent) :
ui->historyList->setExpanded(idx, true); ui->historyList->setExpanded(idx, true);
}); });
ui->historyList->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->historyList, &QListView::customContextMenuRequested, [=](const QPoint& pos){
if (ui->historyList->currentIndex().parent().isValid()) {
QPoint globalPos = ui->historyList->mapToGlobal(pos);
QMenu menu;
ContactMethod* contactMethod = ui->historyList->currentIndex()
.data(static_cast<int>(Call::Role::ContactMethod)).value<ContactMethod*>();
auto copyAction = new QAction("Copy number", this);
menu.addAction(copyAction);
connect(copyAction, &QAction::triggered, [=]() {
QApplication::clipboard()->setText(contactMethod->uri());
});
if (not contactMethod->contact()) {
auto addNew = new QAction("Add to new contact", this);
menu.addAction(addNew);
connect(addNew, &QAction::triggered, [=]() {
ContactDialog dialog(contactMethod->uri());
auto ret = dialog.exec();
if (!ret || dialog.getName().isEmpty())
return;
auto *newPerson = new Person();
newPerson->setFormattedName(dialog.getName());
Person::ContactMethods cM;
cM.append(contactMethod);
newPerson->setContactMethods(cM);
newPerson->setUid(Utils::GenGUID().toLocal8Bit());
PersonModel::instance()->addNewPerson(newPerson, personCollection);
});
auto addExisting = new QAction("Add to existing contact", this);
menu.addAction(addExisting);
connect(addExisting, &QAction::triggered, [=]() {
/* Force LRC to update contact model as adding a number
to a contact without one didn't render him reachable */
CategorizedContactModel::instance()->setUnreachableHidden(false);
ContactPicker contactPicker;
contactPicker.move(globalPos.x(), globalPos.y() - (contactPicker.height()/2));
auto ret = contactPicker.exec();
if (!ret)
return;
auto p = contactPicker.getPersonSelected();
Person::ContactMethods cM (p->phoneNumbers());
cM.append(contactMethod);
p->setContactMethods(cM);
p->save();
CategorizedContactModel::instance()->setUnreachableHidden(true);
});
}
menu.exec(globalPos);
}
});
ui->sortComboBox->setModel(CategorizedHistoryModel::SortedProxy::instance()->categoryModel()); ui->sortComboBox->setModel(CategorizedHistoryModel::SortedProxy::instance()->categoryModel());
CategorizedContactModel::instance()->setSortAlphabetical(false);
ui->contactView->setModel(CategorizedContactModel::instance());
contactDelegate_ = new ContactDelegate();
ui->contactView->setItemDelegate(contactDelegate_);
findRingAccount(); findRingAccount();
} catch (...) { } catch (...) {
...@@ -250,7 +311,8 @@ CallWidget::on_refuseButton_clicked() ...@@ -250,7 +311,8 @@ CallWidget::on_refuseButton_clicked()
} }
void void
CallWidget::addedCall(Call* call, Call* parent) { CallWidget::addedCall(Call* call, Call* parent)
{
Q_UNUSED(parent); Q_UNUSED(parent);
if (call->direction() == Call::Direction::OUTGOING) { if (call->direction() == Call::Direction::OUTGOING) {
displaySpinner(true); displaySpinner(true);
...@@ -300,28 +362,32 @@ CallWidget::on_callList_activated(const QModelIndex &index) ...@@ -300,28 +362,32 @@ CallWidget::on_callList_activated(const QModelIndex &index)
} }
void void
CallWidget::atExit() { CallWidget::atExit()
{
} }
void void
CallWidget::on_contactView_doubleClicked(const QModelIndex &index) CallWidget::on_contactView_doubleClicked(const QModelIndex &index)
{ {
QString uri; if (not index.isValid())
return;
ContactMethod* uri;
auto var = index.child(0,0).data( auto var = index.child(0,0).data(
static_cast<int>(Person::Role::Object)); static_cast<int>(Person::Role::Object));
if (var.isValid()) { if (var.isValid()) {
Person* person = var.value<Person*>(); Person* person = var.value<Person*>();
if (person->phoneNumbers().size() > 0) { if (person->phoneNumbers().size() > 0) {
uri = person->phoneNumbers().at(0)->uri(); uri = person->phoneNumbers().at(0); // FIXME: A person can have multiple contact method
if (uri) {
auto outCall = CallModel::instance()->dialingCall(person->formattedName());
outCall->setDialNumber(uri);
outCall->performAction(Call::Action::ACCEPT);
}
} }
} }
if (not uri.isEmpty()) {
auto outCall = CallModel::instance()->dialingCall(uri);
outCall->setDialNumber(uri);
outCall->performAction(Call::Action::ACCEPT);
}
} }
void void
...@@ -330,9 +396,9 @@ CallWidget::on_historyList_doubleClicked(const QModelIndex &index) ...@@ -330,9 +396,9 @@ CallWidget::on_historyList_doubleClicked(const QModelIndex &index)
if (not index.isValid()) if (not index.isValid())
return; return;
QString number = index.model()->data(index, static_cast<int>(Call::Role::Number)).toString(); auto number = index.data(static_cast<int>(Call::Role::ContactMethod)).value<ContactMethod*>();
if (not number.isEmpty()) { if (number) {
auto outCall = CallModel::instance()->dialingCall(number); auto outCall = CallModel::instance()->dialingCall();
outCall->setDialNumber(number); outCall->setDialNumber(number);
outCall->performAction(Call::Action::ACCEPT); outCall->performAction(Call::Action::ACCEPT);
} }
......
...@@ -35,7 +35,6 @@ ContactDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, ...@@ -35,7 +35,6 @@ ContactDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
initStyleOption(&opt, index); initStyleOption(&opt, index);
if (index.column() == 0) { if (index.column() == 0) {
QString name = index.model()->data(index, Qt::DisplayRole).toString();
opt.text = ""; opt.text = "";
QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget);
...@@ -46,14 +45,13 @@ ContactDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, ...@@ -46,14 +45,13 @@ ContactDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
cg = QPalette::Inactive; cg = QPalette::Inactive;
painter->setPen(opt.palette.color(cg, QPalette::Text)); painter->setPen(opt.palette.color(cg, QPalette::Text));
painter->setOpacity(1.0); painter->setOpacity(1.0);
painter->drawText(QRect(rect.left()+sizeImage_+5, rect.top(),
rect.width(), rect.height()/2),
opt.displayAlignment, name);
QVariant var_c = index.child(0,0).data( QVariant var_c = index.child(0,0).data(
static_cast<int>(Person::Role::Object)); static_cast<int>(Person::Role::Object));
if (var_c.isValid()) { if (var_c.isValid()) {
Person *c = var_c.value<Person *>(); Person *c = var_c.value<Person *>();
painter->drawText(QRect(rect.left()+sizeImage_+5, rect.top(),
rect.width(), rect.height()/2),
opt.displayAlignment, c->formattedName());
QVariant var_p = c->photo(); QVariant var_p = c->photo();
painter->drawRect(QRect(rect.left(), rect.top(), painter->drawRect(QRect(rect.left(), rect.top(),
sizeImage_+1, sizeImage_+1)); sizeImage_+1, sizeImage_+1));
......
/***************************************************************************
* Copyright (C) 2015 by Savoir-faire Linux *
* Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/
#include "contactdialog.h"
#include "ui_contactdialog.h"
ContactDialog::ContactDialog(const QString &number, QWidget *parent) :
QDialog(parent),
ui(new Ui::ContactDialog)
{
ui->setupUi(this);
ui->numberLineEdit->setText(number);
}
ContactDialog::~ContactDialog()
{
delete ui;
}
const QString&
ContactDialog::getName()
{
return contactName_;
}
void
ContactDialog::on_nameLineEdit_textChanged(const QString &arg1)
{
contactName_ = arg1;
}
/***************************************************************************
* Copyright (C) 2015 by Savoir-faire Linux *
* Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/
#ifndef CONTACTDIALOG_H
#define CONTACTDIALOG_H
#include <QDialog>
namespace Ui {
class ContactDialog;
}
class ContactDialog : public QDialog
{
Q_OBJECT
public:
explicit ContactDialog(const QString& number, QWidget *parent = 0);
~ContactDialog();
const QString &getName();
private slots:
void on_nameLineEdit_textChanged(const QString &arg1);
private:
Ui::ContactDialog *ui;
QString contactName_;
};
#endif // CONTACTDIALOG_H
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ContactDialog</class>
<widget class="QDialog" name="ContactDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>398</width>
<height>154</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>New Contact</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="nameLineEdit">
<property name="placeholderText">
<string>Enter a name...</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="numberLineEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ContactDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ContactDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
/***************************************************************************
* Copyright (C) 2015 by Savoir-faire Linux *
* Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/
#include "contactpicker.h"
#include "ui_contactpicker.h"
#include "categorizedcontactmodel.h"
ContactPicker::ContactPicker(QWidget *parent) :
QDialog(parent),
ui(new Ui::ContactPicker),
personSelected_(nullptr)
{
ui->setupUi(this);
this->setWindowFlags(Qt::CustomizeWindowHint);
this->setWindowFlags(Qt::FramelessWindowHint);
auto personModel = PersonModel::instance();
ui->contactView->setModel(personModel);
}
ContactPicker::~ContactPicker()
{
delete ui;
}
void
ContactPicker::on_contactView_doubleClicked(const QModelIndex &index)
{
personSelected_ = index.data(static_cast<int>(Person::Role::Object)).value<Person*>();
this->accept();
}
Person*
ContactPicker::getPersonSelected()
{
return personSelected_;
}
void
ContactPicker::on_cancelButton_clicked()
{
this->reject();
}
/***************************************************************************
* Copyright (C) 2015 by Savoir-faire Linux *
* Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/
#ifndef CONTACTPICKER_H
#define CONTACTPICKER_H
#include <QDialog>
#include "personmodel.h"
namespace Ui {
class ContactPicker;
}
class ContactPicker : public QDialog
{
Q_OBJECT
public:
explicit ContactPicker(QWidget *parent = 0);
~ContactPicker();
Person *getPersonSelected();
//UI SLOTS
private slots:
void on_contactView_doubleClicked(const QModelIndex &index);
void on_cancelButton_clicked();
private:
Ui::ContactPicker *ui;
Person *personSelected_;
};
#endif // CONTACTPICKER_H
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ContactPicker</class>
<widget class="QDialog" name="ContactPicker">