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 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets svg
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets svg xml
VERSION = 0.3.0
GIT_VERSION = $$system(git --git-dir $$PWD/.git --work-tree $$PWD describe --always --tags)
......@@ -47,7 +47,9 @@ SOURCES += main.cpp\
accountstatedelegate.cpp \
videoview.cpp \
videooverlay.cpp \
imdelegate.cpp
imdelegate.cpp \
contactdialog.cpp \
contactpicker.cpp
HEADERS += mainwindow.h \
callwidget.h \
......@@ -70,7 +72,9 @@ HEADERS += mainwindow.h \
accountstatedelegate.h \
videoview.h \
videooverlay.h \
imdelegate.h
imdelegate.h \
contactdialog.h \
contactpicker.h
FORMS += mainwindow.ui \
callwidget.ui \
......@@ -83,7 +87,9 @@ FORMS += mainwindow.ui \
wizarddialog.ui \
instantmessagingwidget.ui \
videoview.ui \
videooverlay.ui
videooverlay.ui \
contactdialog.ui \
contactpicker.ui
win32: LIBS += -lole32 -luuid -lshlwapi
......@@ -118,7 +124,8 @@ win32 {
RUNTIME.path = $$OUT_PWD/release
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
QTDEPSRUNTIME.files = $$RUNTIMEDIR/zlib1.dll $$RUNTIMEDIR/iconv.dll \
......
......@@ -19,10 +19,17 @@
#include "callwidget.h"
#include "ui_callwidget.h"
#include <QClipboard>
#include <memory>
//ERROR is defined in windows.h
#include "utils.h"
#undef ERROR
#include "audio/settings.h"
#include "personmodel.h"
#include "person.h"
#include "fallbackpersoncollection.h"
#include "categorizedcontactmodel.h"
#include "localhistorycollection.h"
......@@ -32,6 +39,8 @@
#include "wizarddialog.h"
#include "windowscontactbackend.h"
#include "contactdialog.h"
#include "contactpicker.h"
CallWidget::CallWidget(QWidget *parent) :
NavWidget(Main ,parent),
......@@ -78,14 +87,17 @@ CallWidget::CallWidget(QWidget *parent) :
ui->callList->setModel(callModel_);
ui->callList->setSelectionModel(callModel_->selectionModel());
CategorizedHistoryModel::instance()->
addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED);
auto personCollection = PersonModel::instance()->
addCollection<WindowsContactBackend>(LoadOptions::FORCE_ENABLED);
PersonModel::instance()->
addCollection<FallbackPersonCollection>(LoadOptions::FORCE_ENABLED);
CategorizedContactModel::instance()->setSortAlphabetical(false);
CategorizedContactModel::instance()->setUnreachableHidden(true);
ui->contactView->setModel(CategorizedContactModel::instance());
contactDelegate_ = new ContactDelegate();
ui->contactView->setItemDelegate(contactDelegate_);
PersonModel::instance()->
addCollection<WindowsContactBackend>(LoadOptions::FORCE_ENABLED);
CategorizedHistoryModel::instance()->
addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED);
ui->historyList->setModel(CategorizedHistoryModel::SortedProxy::instance()->model());
CategorizedHistoryModel::SortedProxy::instance()->model()->sort(0, Qt::DescendingOrder);
......@@ -99,14 +111,63 @@ CallWidget::CallWidget(QWidget *parent) :
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());
CategorizedContactModel::instance()->setSortAlphabetical(false);
ui->contactView->setModel(CategorizedContactModel::instance());
contactDelegate_ = new ContactDelegate();
ui->contactView->setItemDelegate(contactDelegate_);
findRingAccount();
} catch (...) {
......@@ -250,7 +311,8 @@ CallWidget::on_refuseButton_clicked()
}
void
CallWidget::addedCall(Call* call, Call* parent) {
CallWidget::addedCall(Call* call, Call* parent)
{
Q_UNUSED(parent);
if (call->direction() == Call::Direction::OUTGOING) {
displaySpinner(true);
......@@ -300,28 +362,32 @@ CallWidget::on_callList_activated(const QModelIndex &index)
}
void
CallWidget::atExit() {
CallWidget::atExit()
{
}
void
CallWidget::on_contactView_doubleClicked(const QModelIndex &index)
{
QString uri;
if (not index.isValid())
return;
ContactMethod* uri;
auto var = index.child(0,0).data(
static_cast<int>(Person::Role::Object));
if (var.isValid()) {
Person* person = var.value<Person*>();
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
......@@ -330,9 +396,9 @@ CallWidget::on_historyList_doubleClicked(const QModelIndex &index)
if (not index.isValid())
return;
QString number = index.model()->data(index, static_cast<int>(Call::Role::Number)).toString();
if (not number.isEmpty()) {
auto outCall = CallModel::instance()->dialingCall(number);
auto number = index.data(static_cast<int>(Call::Role::ContactMethod)).value<ContactMethod*>();
if (number) {
auto outCall = CallModel::instance()->dialingCall();
outCall->setDialNumber(number);
outCall->performAction(Call::Action::ACCEPT);
}
......
......@@ -35,7 +35,6 @@ ContactDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
initStyleOption(&opt, index);
if (index.column() == 0) {
QString name = index.model()->data(index, Qt::DisplayRole).toString();
opt.text = "";
QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget);
......@@ -46,14 +45,13 @@ ContactDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
cg = QPalette::Inactive;
painter->setPen(opt.palette.color(cg, QPalette::Text));
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(
static_cast<int>(Person::Role::Object));
if (var_c.isValid()) {
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();
painter->drawRect(QRect(rect.left(), rect.top(),
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">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>249</width>
<height>438</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListView" name="contactView"/>
</item>
<item>
<widget class="QPushButton" name="cancelButton">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
......@@ -117,3 +117,33 @@ Utils::GetRingtonePath() {
#endif
}
QString
Utils::GenGUID() {
#ifdef Q_OS_WIN32
GUID gidReference;
wchar_t *str;
HRESULT hCreateGuid = CoCreateGuid(&gidReference);
if (hCreateGuid == S_OK) {
StringFromCLSID(gidReference, &str);
auto gStr = QString::fromWCharArray(str);
return gStr.remove("{").remove("}").toLower();
}
else
return QString("");
#else
return QString("");
#endif
}
QString
Utils::GetISODate() {
#ifdef Q_OS_WIN32
SYSTEMTIME lt;
GetSystemTime(&lt);
return QString("%1-%2-%3T%4:%5:%6Z").arg(lt.wYear).arg(lt.wMonth,2,10,QChar('0')).arg(lt.wDay,2,10,QChar('0'))
.arg(lt.wHour,2,10,QChar('0')).arg(lt.wMinute,2,10,QChar('0')).arg(lt.wSecond,2,10,QChar('0'));
#else
return QString("");
#endif
}
......@@ -39,6 +39,8 @@ public:
static bool CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszPathLink);
static bool CheckStartupLink();
static QString GetRingtonePath();
static QString GenGUID();
static QString GetISODate();
};
......
This diff is collapsed.
......@@ -25,6 +25,7 @@
#include <QXmlStreamReader>
#include <QtConcurrent/QtConcurrent>
#include <QImage>
#include <QFileSystemWatcher>
#include "person.h"
#include "collectioninterface.h"
......@@ -51,6 +52,10 @@ private:
private:
CollectionMediator<Person>* mediator_;
constexpr static int sizePhoto_ = 50;
QFileSystemWatcher* watcher_;
private:
bool getPersonFromContactFile(const QDir &contactDir, const QString& contactFileName);
};
class WindowsContactEditor : public CollectionEditor<Person>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment