Commit 2db8f477 authored by Alexandre Lision's avatar Alexandre Lision Committed by Guillaume Roguez

contacts: create or update contacts

Add ability to create a new contact with an unknow uri, or link it to an
existing contact.
This is presented in a popover, either from an history entry, or during
a call with an unknown URI.

Issue: #78236
Change-Id: I22fa416b9f5c7a6eceb6f2ea47bb30aa251cda54
parent bb5c2466
......@@ -109,7 +109,9 @@ SET(ringclient_CONTROLLERS
src/BitrateVC.mm
src/BitrateVC.h
src/ChatVC.mm
src/ChatVC.h)
src/ChatVC.h
src/PersonLinkerVC.mm
src/PersonLinkerVC.h)
SET(ringclient_BACKENDS
src/backends/AddressBookBackend.mm
......@@ -121,7 +123,9 @@ SET(ringclient_VIEWS
src/views/ITProgressIndicator.mm
src/views/ITProgressIndicator.h
src/views/PersonCell.mm
src/views/PersonCell.h)
src/views/PersonCell.h
src/views/RingOutlineView.mm
src/views/RingOutlineView.h)
SET(ringclient_OTHERS
src/main.mm
......@@ -147,7 +151,8 @@ SET(ringclient_XIBS
VideoPrefs
PreferencesScreen
RingWizard
CertificateWindow)
CertificateWindow
PersonLinker)
# Icons
# This part tells CMake where to find and install the file itself
......@@ -168,6 +173,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_action_search.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_action_quality.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ancrage.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/audio.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_person_add.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/general.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/video.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_action_video.png)
......
......@@ -41,9 +41,11 @@
#import <video/previewmanager.h>
#import <video/renderer.h>
#import <media/text.h>
#import <person.h>
#import "views/ITProgressIndicator.h"
#import "views/CallView.h"
#import "PersonLinkerVC.h"
@interface RendererConnectionsHolder : NSObject
......@@ -57,7 +59,7 @@
@end
@interface CurrentCallVC ()
@interface CurrentCallVC () <NSPopoverDelegate, ContactLinkedDelegate>
@property (unsafe_unretained) IBOutlet NSTextField *personLabel;
@property (unsafe_unretained) IBOutlet NSTextField *stateLabel;
......@@ -67,6 +69,7 @@
@property (unsafe_unretained) IBOutlet NSButton *pickUpButton;
@property (unsafe_unretained) IBOutlet NSButton *muteAudioButton;
@property (unsafe_unretained) IBOutlet NSButton *muteVideoButton;
@property (unsafe_unretained) IBOutlet NSButton *addContactButton;
@property (unsafe_unretained) IBOutlet ITProgressIndicator *loadingIndicator;
......@@ -76,6 +79,7 @@
@property (unsafe_unretained) IBOutlet NSButton *chatButton;
@property (strong) IBOutlet NSPopover *qualityPopOver;
@property (strong) NSPopover* addToContactPopover;
@property QHash<int, NSButton*> actionHash;
......@@ -132,9 +136,16 @@
-(void) updateCall
{
QModelIndex callIdx = CallModel::instance()->selectionModel()->currentIndex();
if (!callIdx.isValid()) {
return;
}
[personLabel setStringValue:callIdx.data(Qt::DisplayRole).toString().toNSString()];
[timeSpentLabel setStringValue:callIdx.data((int)Call::Role::Length).toString().toNSString()];
auto contactmethod = qvariant_cast<Call*>(callIdx.data(static_cast<int>(Call::Role::Object)))->peerContactMethod();
BOOL shouldShow = (!contactmethod->contact() || contactmethod->contact()->isPlaceHolder());
[self.addContactButton setHidden:!shouldShow];
Call::State state = callIdx.data((int)Call::Role::State).value<Call::State>();
[loadingIndicator setHidden:YES];
[stateLabel setStringValue:callIdx.data((int)Call::Role::HumanStateName).toString().toNSString()];
......@@ -525,6 +536,27 @@
#pragma mark - Button methods
- (IBAction)addToContact:(NSButton*) sender {
auto contactmethod = CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex())->peerContactMethod();
if (self.addToContactPopover != nullptr) {
[self.addToContactPopover performClose:self];
self.addToContactPopover = NULL;
} else if (!contactmethod->contact() || contactmethod->contact()->isPlaceHolder()) {
auto* editorVC = [[PersonLinkerVC alloc] initWithNibName:@"PersonLinker" bundle:nil];
[editorVC setMethodToLink:contactmethod];
[editorVC setContactLinkedDelegate:self];
self.addToContactPopover = [[NSPopover alloc] init];
[self.addToContactPopover setContentSize:editorVC.view.frame.size];
[self.addToContactPopover setContentViewController:editorVC];
[self.addToContactPopover setAnimates:YES];
[self.addToContactPopover setBehavior:NSPopoverBehaviorTransient];
[self.addToContactPopover setDelegate:self];
[self.addToContactPopover showRelativeToRect:sender.bounds ofView:sender preferredEdge:NSMaxXEdge];
}
}
- (IBAction)hangUp:(id)sender {
CallModel::instance()->getCall(CallModel::instance()->selectionModel()->currentIndex()) << Call::Action::REFUSE;
}
......@@ -568,6 +600,26 @@
[self.qualityPopOver showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxXEdge];
}
#pragma mark - NSPopOverDelegate
- (void)popoverDidClose:(NSNotification *)notification
{
if (self.addToContactPopover != nullptr) {
[self.addToContactPopover performClose:self];
self.addToContactPopover = NULL;
}
}
#pragma mark - ContactLinkedDelegate
- (void)contactLinked
{
if (self.addToContactPopover != nullptr) {
[self.addToContactPopover performClose:self];
self.addToContactPopover = NULL;
}
}
#pragma mark - NSSplitViewDelegate
/* Return YES if the subview should be collapsed because the user has double-clicked on an adjacent divider. If a split view has a delegate, and the delegate responds to this message, it will be sent once for the subview before a divider when the user double-clicks on that divider, and again for the subview after the divider, but only if the delegate returned YES when sent -splitView:canCollapseSubview: for the subview in question. When the delegate indicates that both subviews should be collapsed NSSplitView's behavior is undefined.
......
......@@ -31,8 +31,9 @@
#define HISTORYVIEWCONTROLLER_H
#import <Cocoa/Cocoa.h>
#import "views/RingOutlineView.h"
@interface HistoryVC : NSViewController <NSOutlineViewDelegate> {
@interface HistoryVC : NSViewController <NSOutlineViewDelegate, ContextMenuDelegate> {
}
......
......@@ -33,20 +33,24 @@
#import <QSortFilterProxyModel>
#import <callmodel.h>
#import <call.h>
#import <person.h>
#import <contactmethod.h>
#import <localhistorycollection.h>
#import "QNSTreeController.h"
#import "PersonLinkerVC.h"
#define COLUMNID_DAY @"DayColumn" // the single column name in our outline view
#define COLUMNID_CONTACTMETHOD @"ContactMethodColumn" // the single column name in our outline view
#define COLUMNID_DATE @"DateColumn" // the single column name in our outline view
@interface HistoryVC()
@interface HistoryVC() <NSPopoverDelegate, KeyboardShortcutDelegate, ContactLinkedDelegate>
@property QNSTreeController *treeController;
@property (assign) IBOutlet NSOutlineView *historyView;
@property (assign) IBOutlet RingOutlineView *historyView;
@property QSortFilterProxyModel *historyProxyModel;
@property (strong) NSPopover* addToContactPopover;
@end
@implementation HistoryVC
......@@ -58,7 +62,6 @@
{
if (self = [super initWithCoder:aDecoder]) {
NSLog(@"INIT HVC");
}
return self;
}
......@@ -79,6 +82,8 @@
[historyView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];
[historyView setTarget:self];
[historyView setDoubleAction:@selector(placeHistoryCall:)];
[historyView setContextMenuDelegate:self];
[historyView setShortcutsDelegate:self];
CategorizedHistoryModel::instance()->addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED);
}
......@@ -87,6 +92,9 @@
{
if([[treeController selectedNodes] count] > 0) {
QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
if (!qIdx.parent().isValid()) {
return;
}
QVariant var = historyProxyModel->data(qIdx, (int)Call::Role::ContactMethod);
ContactMethod* m = qvariant_cast<ContactMethod*>(var);
if(m){
......@@ -174,4 +182,98 @@
//NSLog(@"outlineViewSelectionDidChange!!");
}
#pragma mark - ContextMenuDelegate
- (NSMenu*) contextualMenuForIndex:(NSIndexPath*) path
{
if([[treeController selectedNodes] count] > 0) {
QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
const auto& var = qIdx.data(static_cast<int>(Call::Role::Object));
if (qIdx.parent().isValid() && var.isValid()) {
if (auto call = var.value<Call *>()) {
auto contactmethod = call->peerContactMethod();
if (!contactmethod->contact() || contactmethod->contact()->isPlaceHolder()) {
NSMenu *theMenu = [[NSMenu alloc]
initWithTitle:@""];
[theMenu insertItemWithTitle:@"Add to contact"
action:@selector(addToContact)
keyEquivalent:@"a"
atIndex:0];
return theMenu;
}
}
}
}
return nil;
}
- (void) addToContact
{
ContactMethod* contactmethod = nullptr;
if([[treeController selectedNodes] count] > 0) {
QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
const auto& var = qIdx.data(static_cast<int>(Call::Role::Object));
if (qIdx.parent().isValid() && var.isValid()) {
if (auto call = var.value<Call *>()) {
contactmethod = call->peerContactMethod();
}
}
}
if (self.addToContactPopover != nullptr) {
[self.addToContactPopover performClose:self];
self.addToContactPopover = NULL;
} else if (contactmethod) {
auto* editorVC = [[PersonLinkerVC alloc] initWithNibName:@"PersonEditor" bundle:nil];
[editorVC setMethodToLink:contactmethod];
[editorVC setContactLinkedDelegate:self];
self.addToContactPopover = [[NSPopover alloc] init];
[self.addToContactPopover setContentSize:editorVC.view.frame.size];
[self.addToContactPopover setContentViewController:editorVC];
[self.addToContactPopover setAnimates:YES];
[self.addToContactPopover setBehavior:NSPopoverBehaviorTransient];
[self.addToContactPopover setDelegate:self];
[self.addToContactPopover showRelativeToRect:[historyView frameOfOutlineCellAtRow:[historyView selectedRow]] ofView:historyView preferredEdge:NSMaxXEdge];
}
}
#pragma mark - NSPopOverDelegate
- (void)popoverDidClose:(NSNotification *)notification
{
if (self.addToContactPopover != nullptr) {
[self.addToContactPopover performClose:self];
self.addToContactPopover = NULL;
}
}
#pragma mark - ContactLinkedDelegate
- (void)contactLinked
{
if (self.addToContactPopover != nullptr) {
[self.addToContactPopover performClose:self];
self.addToContactPopover = NULL;
}
}
#pragma mark - KeyboardShortcutDelegate
- (void) onAddShortcut
{
if([[treeController selectedNodes] count] > 0) {
QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
const auto& var = qIdx.data(static_cast<int>(Call::Role::Object));
if (qIdx.parent().isValid() && var.isValid()) {
if (auto call = var.value<Call *>()) {
auto contactmethod = call->peerContactMethod();
if (!contactmethod->contact() || contactmethod->contact()->isPlaceHolder()) {
[self addToContact];
}
}
}
}
}
@end
/*
* Copyright (C) 2015 Savoir-faire Linux Inc.
* Author: Alexandre Lision <alexandre.lision@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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify this program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
* grants you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#import <Cocoa/Cocoa.h>
@protocol ContactLinkedDelegate;
@protocol ContactLinkedDelegate
@optional
-(void) contactLinked;
@end
class ContactMethod;
@interface PersonLinkerVC : NSViewController <NSOutlineViewDelegate>
@property ContactMethod* const methodToLink;
/*
* Delegate to inform about completion of the linking process between
* a ContactMethod and a Person.
*/
@property (nonatomic) id <ContactLinkedDelegate> contactLinkedDelegate;
@end
This diff is collapsed.
......@@ -30,15 +30,19 @@
#import "PersonsVC.h"
#import <personmodel.h>
#import <callmodel.h>
#import <categorizedcontactmodel.h>
//Qt
#import <QSortFilterProxyModel>
#import <person.h>
#import <contactmethod.h>
#import <QtMacExtras/qmacfunctions.h>
#import <QPixmap>
//LRC
#import <person.h>
#import <personmodel.h>
#import <callmodel.h>
#import <contactmethod.h>
#import <categorizedcontactmodel.h>
#import "backends/AddressBookBackend.h"
#import "QNSTreeController.h"
#import "delegates/ImageManipulationDelegate.h"
......@@ -92,8 +96,6 @@ public:
[personsView setDoubleAction:@selector(callContact:)];
CategorizedContactModel::instance()->setUnreachableHidden(YES);
PersonModel::instance()->addCollection<AddressBookBackend>(LoadOptions::FORCE_ENABLED);
}
- (IBAction)callContact:(id)sender
......@@ -227,9 +229,6 @@ public:
- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
{
QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
if(!qIdx.isValid())
return 0.0f;
if(!qIdx.parent().isValid()) {
return 20.0;
} else {
......@@ -237,5 +236,4 @@ public:
}
}
@end
......@@ -35,14 +35,12 @@
@interface QNSTreeController : NSTreeController {
QAbstractItemModel *privateQModel;
NSMutableArray* topNodes;
QAbstractItemModel *privateQModel;
}
- (void*)connect;
- (id) initWithQModel:(QAbstractItemModel*) model;
- (QModelIndex) toQIdx:(NSTreeNode*) node;
- (QModelIndex) indexPathtoQIdx:(NSIndexPath*) path;
@end
......
......@@ -29,6 +29,8 @@
*/
#import "QNSTreeController.h"
#import <QDebug>
@interface Node : NSObject {
NSMutableArray *children;
}
......@@ -43,9 +45,14 @@
return self;
}
- (void) addChild:(Node*) child
- (void) addChild:(Node*) child AtIndex:(NSUInteger) idx
{
[children addObject:child];
[children insertObject:child atIndex:idx];
}
- (NSMutableArray*) children
{
return children;
}
@end
......@@ -58,18 +65,33 @@
self = [super init];
self->privateQModel = model;
topNodes = [[NSMutableArray alloc] init];
NSMutableArray* nodes = [[NSMutableArray alloc] init];
[self connect];
[self populate];
[self populate:nodes];
return [self initWithContent:nodes];
}
return [self initWithContent:topNodes];
-(void) populate:(NSMutableArray*) nodes
{
for (int i = 0 ; i < self->privateQModel->rowCount() ; ++i) {
Node* n = [[Node alloc] init];
//qDebug() << "POUPL TOP:"<< self->privateQModel->index(i, 0) ;
[self populateChild:[n children] withParent:self->privateQModel->index(i, 0)];
[nodes insertObject:n atIndex:i];
}
}
-(void) populate
- (void) populateChild:(NSMutableArray*) nodes withParent:(QModelIndex)qIdx
{
for (int i =0 ; i < self->privateQModel->rowCount() ; ++i){
[topNodes insertObject:[[Node alloc] init] atIndex:i];
if (!qIdx.isValid())
return;
for (int i = 0 ; i < self->privateQModel->rowCount(qIdx) ; ++i) {
Node* n = [[Node alloc] init];
//qDebug() << "POPUL CHILD:"<< self->privateQModel->index(i, 0, qIdx) ;
[self populateChild:[n children] withParent:self->privateQModel->index(i, 0, qIdx)];
[nodes insertObject:n atIndex:i];
}
}
......@@ -78,24 +100,26 @@
return self->privateQModel->flags(self->privateQModel->index(0, 0)) | Qt::ItemIsEditable;
}
- (QModelIndex) toQIdx:(NSTreeNode*) node
- (QModelIndex) indexPathtoQIdx:(NSIndexPath*) path
{
NSIndexPath* idx = node.indexPath;
NSUInteger myArray[[idx length]];
[idx getIndexes:myArray];
NSUInteger myArray[[path length]];
[path getIndexes:myArray];
QModelIndex toReturn;
for (int i = 0; i < idx.length; ++i) {
for (int i = 0; i < path.length; ++i) {
toReturn = self->privateQModel->index(myArray[i], 0, toReturn);
}
return toReturn;
}
- (void) insertChildAtQIndex:(QModelIndex) qIdx
- (QModelIndex) toQIdx:(NSTreeNode*) node
{
Node* child = [[Node alloc] init];
return [self indexPathtoQIdx:node.indexPath];
}
- (NSIndexPath*) qIdxToNSIndexPath:(QModelIndex) qIdx
{
QModelIndex tmp = qIdx.parent();
NSMutableArray* allIndexes = [NSMutableArray array];
while (tmp.isValid()) {
......@@ -108,7 +132,27 @@
for (int i = 0 ; i < allIndexes.count ; ++i) {
indexes[i] = [[allIndexes objectAtIndex:i] intValue];
}
[self insertObject:child atArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndexes:indexes length:allIndexes.count]];
return [[NSIndexPath alloc] initWithIndexes:indexes length:allIndexes.count];
}
- (void) insertNodeAtQIndex:(QModelIndex) qIdx
{
NSIndexPath* path = [self qIdxToNSIndexPath:qIdx];
//qDebug() << "insertNodeAt" << qIdx;
//NSLog(@"insertNodeAt index: %@", path);
if (path.length == 1 && [path indexAtPosition:0] <= [[self arrangedObjects] count])
[self insertObject:[[Node alloc] init] atArrangedObjectIndexPath:path];
else if (path.length > 1)
[self insertObject:[[Node alloc] init] atArrangedObjectIndexPath:path];
}
- (void) removeNodeAtQIndex:(QModelIndex) qIdx
{
NSIndexPath* path = [self qIdxToNSIndexPath:qIdx];
if ([self.arrangedObjects descendantNodeAtIndexPath:path]) {
//NSLog(@"removeNodeAt index: %@", path);
[self removeObjectAtArrangedObjectIndexPath:path];
}
}
- (void)connect
......@@ -116,17 +160,14 @@
QObject::connect(self->privateQModel,
&QAbstractItemModel::rowsInserted,
[=](const QModelIndex & parent, int first, int last) {
for( int row = first; row <= last; row++) {
if(!parent.isValid()) {
//Inserting topnode
Node* n = [[Node alloc] init];
[self insertObject:n atArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndex:row]];
} else {
[self insertChildAtQIndex:self->privateQModel->index(row, 0, parent)];
}
for( int row = first; row <= last; ++row) {
//qDebug() << "INSERTING:"<< self->privateQModel->index(row, 0, parent) ;
if(!self->privateQModel->index(row, 0, parent).isValid())
continue;
[self insertNodeAtQIndex:self->privateQModel->index(row, 0, parent)];
}
}
);
});
QObject::connect(self->privateQModel,
&QAbstractItemModel::rowsAboutToBeMoved,
......@@ -137,8 +178,7 @@
for( int row = sourceStart; row <= sourceEnd; row++) {
//TODO
}
}
);
});
QObject::connect(self->privateQModel,
&QAbstractItemModel::rowsMoved,
......@@ -149,45 +189,37 @@
for( int row = sourceStart; row <= sourceEnd; row++) {
//TODO
}
}
);
[self rearrangeObjects];
});
QObject::connect(self->privateQModel,
&QAbstractItemModel::rowsAboutToBeRemoved,
[=](const QModelIndex & parent, int first, int last) {
NSLog(@"rows about to be removed");
}
);
[self](const QModelIndex & parent, int first, int last) {
for( int row = first; row <= last; row++) {
//qDebug() << "REMOVING:"<< self->privateQModel->index(row, 0, parent) ;
if (!self->privateQModel->index(row, 0, parent).isValid())
continue;
[self removeNodeAtQIndex:self->privateQModel->index(row, 0, parent)];
}
});
QObject::connect(self->privateQModel,
&QAbstractItemModel::rowsRemoved,
[=](const QModelIndex & parent, int first, int last) {
//NSLog(@"rows removed");
for( int row = first; row <= last; row++) {
if(parent.isValid())
{
//Removing leaf
NSUInteger indexes[] = { (NSUInteger)parent.row(), (NSUInteger)row};
[self removeObjectAtArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndexes:indexes length:2]];
} else
{
[self removeObjectAtArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndex:row]];
}
}
}
);
[self](const QModelIndex& parent, int first, int last) {
});
QObject::connect(self->privateQModel,
&QAbstractItemModel::layoutChanged,
[=]() {
[self]() {
//NSLog(@"layout changed");
}
);
[self rearrangeObjects];
});
QObject::connect(self->privateQModel,
&QAbstractItemModel::dataChanged,
[=](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
//NSLog(@"data changed");
[self](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
for(int row = topLeft.row() ; row <= bottomRight.row() ; ++row)
{
QModelIndex tmpIdx = self->privateQModel->index(row, 0);
......@@ -197,6 +229,7 @@
[self insertObject:n atArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndex:row]];
}
}
[self rearrangeObjects];
});
}
......
......@@ -34,11 +34,14 @@
#import <callmodel.h>
#import <account.h>
#import <call.h>
#import <personmodel.h>
#import "AppDelegate.h"
#import "Constants.h"
#import "CurrentCallVC.h"
#import "backends/AddressBookBackend.h"
@interface RingWindowController ()
@property NSSearchField* callField;
......@@ -67,6 +70,8 @@ static NSString* const kCallButtonIdentifer = @"CallButtonIdentifier";
[callView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[[currentVC view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
PersonModel::instance()->addCollection<AddressBookBackend>(LoadOptions::FORCE_ENABLED);
[callView addSubview:[self.currentVC view]];
[currentVC initFrame];
......
/*
* Copyright (C) 2004-2015 Savoir-Faire Linux Inc.
* Copyright (C) 2015 Savoir-faire Linux Inc.
* Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
......@@ -27,13 +27,14 @@
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#ifndef ADDRESSBOOKBACKEND_H
#define ADDRESSBOOKBACKEND_H
#include <collectioninterface.h>
#include <collectioneditor.h>
class Person;
@class ABPerson;
@class NSMutableArray;
@class NSNotification;
template<typename T> class CollectionMediator;
......@@ -53,10 +54,15 @@ public:
virtual QByteArray id () const override;
virtual FlagPack<SupportedFeatures> supportedFeatures() const override;
bool addNewPerson(Person *item);
bool removePerson(NSString* uid);
private:
CollectionMediator<Person>* m_pMediator;
NSMutableArray* observers;
void asyncLoad(int startingPoint);
};
void handleNotification(NSNotification* ns);
Person* abPersonToPerson(ABPerson* ab);
#endif // ADDRESSBOOKBACKEND_H
void asyncLoad(int startingPoint);
};
\ No newline at end of file
/*
* Copyright (C) 2004-2015 Savoir-Faire Linux Inc.
* Copyright (C) 2015 Savoir-faire Linux Inc.
* Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
......@@ -29,6 +29,7 @@
*/
#import "AddressBookBackend.h"
//Cocoa
#import <AddressBook/AddressBook.h>
//Qt
......@@ -46,6 +47,7 @@
#import <account.h>
#import <person.h>
#import <contactmethod.h>
#import <personmodel.h>
/**
*
......@@ -81,7 +83,7 @@ public:
virtual bool save ( const Person* item ) override;
virtual bool remove ( const Person* item ) override;
virtual bool edit ( Person* item ) override;
virtual bool addNew ( const Person* item ) override;
virtual bool addNew ( Person* item ) override;
virtual bool addExisting( const Person* item ) override;
private:
......@@ -105,40 +107,95 @@ CollectionEditor<Person>(m),m_pCollection(parent)
AddressBookBackend::AddressBookBackend(CollectionMediator<Person>* mediator) :
CollectionInterface(new AddressBookEditor(mediator,this)),m_pMediator(mediator)
{
::id addressBookObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kABDatabaseChangedNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
handleNotification(note);
}];
::id externalAddressBookObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kABDatabaseChangedExternallyNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
handleNotification(note);
}];
observers = [[NSArray alloc] initWithObjects:addressBookObserver, externalAddressBookObserver, nil];
}
void AddressBookBackend::handleNotification(NSNotification* ns)