blob: 07bc3f0c144a0b97031b414f3854fca8e1a77c83 [file] [log] [blame]
Alexandre Lision3b0bd332015-03-15 18:43:07 -04001/*
Alexandre Lision9fe374b2016-01-06 10:17:31 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Alexandre Lision3b0bd332015-03-15 18:43:07 -04003 * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Alexandre Lision3b0bd332015-03-15 18:43:07 -040018 */
19
20#import "PersonsVC.h"
21
Alexandre Lision2db8f472015-07-22 15:05:46 -040022
23//Qt
Alexandre Lision3b0bd332015-03-15 18:43:07 -040024#import <QSortFilterProxyModel>
Alexandre Lision3b0bd332015-03-15 18:43:07 -040025#import <QtMacExtras/qmacfunctions.h>
26#import <QPixmap>
27
Alexandre Lision2db8f472015-07-22 15:05:46 -040028//LRC
29#import <person.h>
30#import <personmodel.h>
31#import <callmodel.h>
32#import <contactmethod.h>
33#import <categorizedcontactmodel.h>
Alexandre Lision7a166e42015-09-02 15:04:43 -040034#import <globalinstances.h>
Alexandre Lision2db8f472015-07-22 15:05:46 -040035
Alexandre Lision3b0bd332015-03-15 18:43:07 -040036#import "backends/AddressBookBackend.h"
37#import "QNSTreeController.h"
38#import "delegates/ImageManipulationDelegate.h"
Alexandre Lision4e280d62015-09-09 15:56:30 -040039#import "views/HoverTableRowView.h"
Alexandre Lision6da08a82015-09-24 17:09:24 -040040#import "views/ContextualTableCellView.h"
Alexandre Lision3b0bd332015-03-15 18:43:07 -040041
42class ReachablePersonModel : public QSortFilterProxyModel
43{
44public:
45 ReachablePersonModel(QAbstractItemModel* parent) : QSortFilterProxyModel(parent)
46 {
47 setSourceModel(parent);
48 }
49 virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
50 {
51 return sourceModel()->index(source_row,0,source_parent).flags() & Qt::ItemIsEnabled;
52 }
53};
54
55
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040056@interface PersonsVC () {
Alexandre Lision3b0bd332015-03-15 18:43:07 -040057
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040058 QNSTreeController *treeController;
59 __unsafe_unretained IBOutlet NSOutlineView *personsView;
60 QSortFilterProxyModel *contactProxyModel;
61
62}
Alexandre Lision3b0bd332015-03-15 18:43:07 -040063
64@end
65
66@implementation PersonsVC
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040067
68// Tags for views
69NSInteger const IMAGE_TAG = 100;
70NSInteger const DISPLAYNAME_TAG = 200;
71NSInteger const DETAILS_TAG = 300;
72NSInteger const CALL_BUTTON_TAG = 400;
Alexandre Lision3b0bd332015-03-15 18:43:07 -040073
74-(void) awakeFromNib
75{
Alexandre Lision3b0bd332015-03-15 18:43:07 -040076 NSLog(@"INIT PersonsVC");
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040077 contactProxyModel = new ReachablePersonModel(&CategorizedContactModel::instance());
Alexandre Lision3b0bd332015-03-15 18:43:07 -040078 contactProxyModel->setSortRole(static_cast<int>(Qt::DisplayRole));
79 contactProxyModel->sort(0,Qt::AscendingOrder);
80 treeController = [[QNSTreeController alloc] initWithQModel:contactProxyModel];
81
82 [treeController setAvoidsEmptySelection:NO];
83 [treeController setChildrenKeyPath:@"children"];
84
85 [personsView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil];
86 [personsView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil];
87 [personsView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];
88 [personsView setTarget:self];
89 [personsView setDoubleAction:@selector(callContact:)];
90
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040091 CategorizedContactModel::instance().setUnreachableHidden(YES);
Alexandre Lision3b0bd332015-03-15 18:43:07 -040092}
93
Alexandre Lision54b0fae2015-08-04 15:19:01 -040094- (void) dealloc
95{
96 delete contactProxyModel;
97}
98
Alexandre Lision3b0bd332015-03-15 18:43:07 -040099- (IBAction)callContact:(id)sender
100{
101 if([[treeController selectedNodes] count] > 0) {
Alexandre Lisiond5229f32015-11-16 11:17:41 -0500102 auto item = [treeController selectedNodes][0];
103 QModelIndex qIdx = [treeController toQIdx:item];
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400104 ContactMethod* m = nil;
Alexandre Lisiond5229f32015-11-16 11:17:41 -0500105 if (!qIdx.parent().isValid()) {
106 if ([personsView isItemExpanded:item]) {
107 [[personsView animator] collapseItem:item];
108 } else
109 [[personsView animator] expandItem:item];
110 return;
111 }
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400112 if(((NSTreeNode*)[treeController selectedNodes][0]).indexPath.length == 2) {
113 // Person
114 QVariant var = qIdx.data((int)Person::Role::Object);
115 if (var.isValid()) {
116 Person *c = var.value<Person*>();
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400117 if (c->phoneNumbers().size() > 0) {
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400118 m = c->phoneNumbers().first();
119 }
120 }
121 } else if (((NSTreeNode*)[treeController selectedNodes][0]).indexPath.length == 3) {
122 //ContactMethod
123 QVariant var = qIdx.data(static_cast<int>(ContactMethod::Role::Object));
124 if (var.isValid()) {
125 m = var.value<ContactMethod *>();
126 }
127 }
128
129 if(m){
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400130 Call* c = CallModel::instance().dialingCall();
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400131 c->setPeerContactMethod(m);
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400132 c << Call::Action::ACCEPT;
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500133 CallModel::instance().selectCall(c);
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400134 }
135 }
136}
137
138#pragma mark - NSOutlineViewDelegate methods
139
140// -------------------------------------------------------------------------------
141// shouldSelectItem:item
142// -------------------------------------------------------------------------------
143- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item;
144{
145 QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
146 if(!qIdx.isValid())
147 return NO;
148
Alexandre Lisiond5229f32015-11-16 11:17:41 -0500149 return YES;
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400150}
151
152// -------------------------------------------------------------------------------
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400153// shouldEditTableColumn:tableColumn:item
154//
155// Decide to allow the edit of the given outline view "item".
156// -------------------------------------------------------------------------------
157- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
158{
159 return NO;
160}
161
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400162/* View Based OutlineView: See the delegate method -tableView:viewForTableColumn:row: in NSTableView.
163 */
164- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400165{
166 QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400167
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400168 NSTableCellView *result;
169
170 if(!qIdx.parent().isValid()) {
171 result = [outlineView makeViewWithIdentifier:@"LetterCell" owner:outlineView];
172 [result setWantsLayer:YES];
173 [result setLayer:[CALayer layer]];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400174 } else if(((NSTreeNode*)item).indexPath.length == 2) {
Alexandre Lision6da08a82015-09-24 17:09:24 -0400175 result = [outlineView makeViewWithIdentifier:@"PersonCell" owner:outlineView];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400176 NSImageView* photoView = [result viewWithTag:IMAGE_TAG];
177 Person* p = qvariant_cast<Person*>(qIdx.data((int)Person::Role::Object));
178
Alexandre Lision43e91bc2016-04-19 18:04:52 -0400179 [photoView setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(qIdx.data(Qt::DecorationRole)))];
180
Alexandre Lision6da08a82015-09-24 17:09:24 -0400181 [((ContextualTableCellView*) result) setContextualsControls:[NSMutableArray arrayWithObject:[result viewWithTag:CALL_BUTTON_TAG]]];
182
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400183 NSTextField* details = [result viewWithTag:DETAILS_TAG];
184 if (p && p->phoneNumbers().size() > 0)
185 [details setStringValue:p->phoneNumbers().first()->uri().toNSString()];
186 } else {
187 result = [outlineView makeViewWithIdentifier:@"ContactMethodCell" owner:outlineView];
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400188 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400189
190 NSTextField* displayName = [result viewWithTag:DISPLAYNAME_TAG];
191 [displayName setStringValue:qIdx.data(Qt::DisplayRole).toString().toNSString()];
192
193 return result;
194}
195
Alexandre Lision4e280d62015-09-09 15:56:30 -0400196/* View Based OutlineView: See the delegate method -tableView:rowViewForRow: in NSTableView.
197 */
198- (NSTableRowView *)outlineView:(NSOutlineView *)outlineView rowViewForItem:(id)item
199{
200 QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
Alexandre Lision4e280d62015-09-09 15:56:30 -0400201 HoverTableRowView* result = [outlineView makeViewWithIdentifier:@"HoverRowView" owner:nil];
202 if(!qIdx.parent().isValid()) {
203 [result setHighlightable:NO];
204 } else
205 [result setHighlightable:YES];
206
207 return result;
208}
209
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400210- (IBAction)callClickedAtRow:(id)sender {
211 NSInteger row = [personsView rowForView:sender];
212 [personsView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
213 [self callContact:nil];
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400214}
215
216// -------------------------------------------------------------------------------
217// outlineViewSelectionDidChange:notification
218// -------------------------------------------------------------------------------
219- (void)outlineViewSelectionDidChange:(NSNotification *)notification
220{
221
222}
223
224- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
225{
226 QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400227 return (((NSTreeNode*)item).indexPath.length == 2) ? 60.0 : 20.0;
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400228}
229
Alexandre Lision3b0bd332015-03-15 18:43:07 -0400230@end