blob: f445f52f06c9ab15b95c9e82c13ed0fa8759fefb [file] [log] [blame]
Alexandre Lision4dfcafc2015-08-20 12:43:23 -04001/*
Alexandre Lision9fe374b2016-01-06 10:17:31 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Alexandre Lision4dfcafc2015-08-20 12:43:23 -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.
18 */
19
20#import "SmartViewVC.h"
21
22//Qt
23#import <QtMacExtras/qmacfunctions.h>
24#import <QPixmap>
25#import <QIdentityProxyModel>
26#import <QItemSelectionModel>
27
28//LRC
29#import <recentmodel.h>
30#import <callmodel.h>
31#import <call.h>
Alexandre Lisiond14bda32015-10-13 11:34:29 -040032#import <itemdataroles.h>
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040033#import <person.h>
34#import <contactmethod.h>
35#import <globalinstances.h>
Alexandre Lision0f66bd32016-01-18 11:30:45 -050036#import <phonedirectorymodel.h>
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040037
38#import "QNSTreeController.h"
39#import "delegates/ImageManipulationDelegate.h"
Alexandre Lision4e280d62015-09-09 15:56:30 -040040#import "views/HoverTableRowView.h"
Alexandre Lision61db3552015-10-22 19:12:52 -040041#import "PersonLinkerVC.h"
Alexandre Lision4baba4c2016-02-11 13:00:57 -050042#import "views/IconButton.h"
Alexandre Lision61db3552015-10-22 19:12:52 -040043#import "views/RingOutlineView.h"
Alexandre Lision4e280d62015-09-09 15:56:30 -040044#import "views/ContextualTableCellView.h"
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040045
Alexandre Lision61db3552015-10-22 19:12:52 -040046@interface SmartViewVC () <NSOutlineViewDelegate, NSPopoverDelegate, ContextMenuDelegate, ContactLinkedDelegate, KeyboardShortcutDelegate> {
Alexandre Lision0f66bd32016-01-18 11:30:45 -050047
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040048 QNSTreeController *treeController;
Alexandre Lision61db3552015-10-22 19:12:52 -040049 NSPopover* addToContactPopover;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040050
51 //UI elements
Alexandre Lision61db3552015-10-22 19:12:52 -040052 __unsafe_unretained IBOutlet RingOutlineView* smartView;
53 __unsafe_unretained IBOutlet NSSearchField* searchField;
Alexandre Lision61db3552015-10-22 19:12:52 -040054 __unsafe_unretained IBOutlet NSTabView* tabbar;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040055}
56
57@end
58
59@implementation SmartViewVC
60
61// Tags for views
Alexandre Lision57914fa2016-02-10 14:52:24 -050062NSInteger const IMAGE_TAG = 100;
63NSInteger const DISPLAYNAME_TAG = 200;
64NSInteger const DETAILS_TAG = 300;
65NSInteger const CALL_BUTTON_TAG = 400;
66NSInteger const TXT_BUTTON_TAG = 500;
67NSInteger const CANCEL_BUTTON_TAG = 600;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040068
69- (void)awakeFromNib
70{
71 NSLog(@"INIT SmartView VC");
72
Alexandre Lision0f66bd32016-01-18 11:30:45 -050073 RecentModel::instance().peopleProxy()->setFilterRole((int)Ring::Role::Name);
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040074 treeController = [[QNSTreeController alloc] initWithQModel:RecentModel::instance().peopleProxy()];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040075 [treeController setAvoidsEmptySelection:NO];
76 [treeController setChildrenKeyPath:@"children"];
77
78 [smartView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil];
79 [smartView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil];
80 [smartView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];
81 [smartView setTarget:self];
Alexandre Lision89edc6a2015-11-09 11:30:47 -050082 [smartView setAction:@selector(selectRow:)];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040083 [smartView setDoubleAction:@selector(placeCall:)];
84
Alexandre Lision61db3552015-10-22 19:12:52 -040085 [smartView setContextMenuDelegate:self];
86 [smartView setShortcutsDelegate:self];
87
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040088 QObject::connect(RecentModel::instance().peopleProxy(),
Alexandre Lisionee098462015-10-22 17:22:50 -040089 &QAbstractItemModel::dataChanged,
90 [self](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
91 for(int row = topLeft.row() ; row <= bottomRight.row() ; ++row)
92 {
93 [smartView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:row]
94 columnIndexes:[NSIndexSet indexSetWithIndex:0]];
95 }
96 });
97
Alexandre Lision89edc6a2015-11-09 11:30:47 -050098 QObject::connect(RecentModel::instance().selectionModel(),
99 &QItemSelectionModel::currentChanged,
100 [=](const QModelIndex &current, const QModelIndex &previous) {
Alexandre Lision01cf5e32016-01-21 15:54:30 -0500101 if(!current.isValid()) {
102 [smartView deselectAll:nil];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500103 return;
Alexandre Lision01cf5e32016-01-21 15:54:30 -0500104 }
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500105
106 auto proxyIdx = RecentModel::instance().peopleProxy()->mapFromSource(current);
107 if (proxyIdx.isValid()) {
108 [treeController setSelectionQModelIndex:proxyIdx];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500109 [tabbar selectTabViewItemAtIndex:0];
110 [smartView scrollRowToVisible:proxyIdx.row()];
111 }
112 });
113
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400114 [self.view setWantsLayer:YES];
115 [self.view setLayer:[CALayer layer]];
116 [self.view.layer setBackgroundColor:[NSColor whiteColor].CGColor];
117
118 [searchField setWantsLayer:YES];
119 [searchField setLayer:[CALayer layer]];
120 [searchField.layer setBackgroundColor:[NSColor colorWithCalibratedRed:0.949 green:0.949 blue:0.949 alpha:0.9].CGColor];
121}
122
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500123-(void) selectRow:(id)sender
124{
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500125 if ([treeController selectedNodes].count == 0) {
126 RecentModel::instance().selectionModel()->clearCurrentIndex();
127 return;
128 }
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500129 auto qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
130 auto proxyIdx = RecentModel::instance().peopleProxy()->mapToSource(qIdx);
131 RecentModel::instance().selectionModel()->setCurrentIndex(proxyIdx, QItemSelectionModel::ClearAndSelect);
132}
133
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400134- (void)placeCall:(id)sender
135{
136 QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
137 ContactMethod* m = nil;
138
139 // Double click on an ongoing call
140 if (qIdx.parent().isValid()) {
141 return;
142 }
143
144 if([[treeController selectedNodes] count] > 0) {
145 QVariant var = qIdx.data((int)Call::Role::ContactMethod);
146 m = qvariant_cast<ContactMethod*>(var);
147 if (!m) {
148 // test if it is a person
149 QVariant var = qIdx.data((int)Person::Role::Object);
150 if (var.isValid()) {
151 Person *c = var.value<Person*>();
152 if (c->phoneNumbers().size() > 0) {
153 m = c->phoneNumbers().first();
154 }
155 }
156 }
157 }
158
159 // Before calling check if we properly extracted a contact method and that
160 // there is NOT already an ongoing call for this index (e.g: no children for this node)
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400161 if(m && !RecentModel::instance().peopleProxy()->index(0, 0, qIdx).isValid()){
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500162 auto c = CallModel::instance().dialingCall();
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400163 c->setPeerContactMethod(m);
164 c << Call::Action::ACCEPT;
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500165 CallModel::instance().selectCall(c);
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400166 }
167}
168
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500169- (IBAction)showHistory:(NSButton*)sender
170{
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500171 [tabbar selectTabViewItemAtIndex:1];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400172}
173
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500174- (IBAction)showContacts:(NSButton*)sender
175{
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500176 [tabbar selectTabViewItemAtIndex:2];
177}
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500178
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500179- (IBAction)showSmartlist:(NSButton*)sender
180{
181 [tabbar selectTabViewItemAtIndex:0];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400182}
183
184#pragma mark - NSOutlineViewDelegate methods
185
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400186- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item;
187{
188 return YES;
189}
190
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400191- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
192{
193 return NO;
194}
195
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400196- (void)outlineViewSelectionDidChange:(NSNotification *)notification
197{
198 if ([treeController selectedNodes].count <= 0) {
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500199 RecentModel::instance().selectionModel()->clearCurrentIndex();
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400200 return;
201 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400202}
203
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400204- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item
205{
Alexandre Lisiona4bb0512016-04-19 18:04:31 -0400206 QModelIndex proxyIdx = [treeController toQIdx:((NSTreeNode*)item)];
207 QModelIndex qIdx = RecentModel::instance().peopleProxy()->mapToSource(proxyIdx);
208
209 NSTableCellView* result;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400210 if (!qIdx.parent().isValid()) {
211 result = [outlineView makeViewWithIdentifier:@"MainCell" owner:outlineView];
212 NSTextField* details = [result viewWithTag:DETAILS_TAG];
213
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500214 NSMutableArray* controls = [NSMutableArray arrayWithObject:[result viewWithTag:CALL_BUTTON_TAG]];
215 [((ContextualTableCellView*) result) setContextualsControls:controls];
Alexandre Lision4e280d62015-09-09 15:56:30 -0400216
Alexandre Lisiona4bb0512016-04-19 18:04:31 -0400217 if (auto call = RecentModel::instance().getActiveCall(qIdx)) {
Alexandre Lisiond14bda32015-10-13 11:34:29 -0400218 [details setStringValue:call->roleData((int)Ring::Role::FormattedState).toString().toNSString()];
Alexandre Lision21666f32015-09-22 17:04:36 -0400219 [((ContextualTableCellView*) result) setActiveState:YES];
220 } else {
Alexandre Lisiond14bda32015-10-13 11:34:29 -0400221 [details setStringValue:qIdx.data((int)Ring::Role::FormattedLastUsed).toString().toNSString()];
Alexandre Lision21666f32015-09-22 17:04:36 -0400222 [((ContextualTableCellView*) result) setActiveState:NO];
223 }
224
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500225 NSTextField* unreadCount = [result viewWithTag:TXT_BUTTON_TAG];
226 int unread = qIdx.data((int)Ring::Role::UnreadTextMessageCount).toInt();
227 [unreadCount setHidden:(unread == 0)];
228 [unreadCount.layer setCornerRadius:5.0f];
229 [unreadCount setStringValue:qIdx.data((int)Ring::Role::UnreadTextMessageCount).toString().toNSString()];
230
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400231 } else {
232 result = [outlineView makeViewWithIdentifier:@"CallCell" owner:outlineView];
Alexandre Lision57914fa2016-02-10 14:52:24 -0500233 NSMutableArray* controls = [NSMutableArray arrayWithObject:[result viewWithTag:CANCEL_BUTTON_TAG]];
234 [((ContextualTableCellView*) result) setContextualsControls:controls];
235 [((ContextualTableCellView*) result) setActiveState:NO];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400236 NSTextField* details = [result viewWithTag:DETAILS_TAG];
237
238 [details setStringValue:qIdx.data((int)Call::Role::HumanStateName).toString().toNSString()];
239 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400240
241 NSTextField* displayName = [result viewWithTag:DISPLAYNAME_TAG];
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500242 [displayName setStringValue:qIdx.data((int)Ring::Role::Name).toString().toNSString()];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400243 NSImageView* photoView = [result viewWithTag:IMAGE_TAG];
244 Person* p = qvariant_cast<Person*>(qIdx.data((int)Person::Role::Object));
Alexandre Lisiond5229f32015-11-16 11:17:41 -0500245 QVariant photo = GlobalInstances::pixmapManipulator().contactPhoto(p, QSize(50,50));
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400246 [photoView setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
247 return result;
248}
249
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500250- (void)outlineView:(NSOutlineView *)outlineView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row
251{
252 [outlineView scrollRowToVisible:0];
253}
254
255- (NSTableRowView *)outlineView:(NSOutlineView *)outlineView rowViewForItem:(id)item
256{
257 return [outlineView makeViewWithIdentifier:@"HoverRowView" owner:nil];
258}
259
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400260- (IBAction)callClickedAtRow:(id)sender {
261 NSInteger row = [smartView rowForView:sender];
262 [smartView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
263 [self placeCall:nil];
264}
265
266- (IBAction)hangUpClickedAtRow:(id)sender {
267 NSInteger row = [smartView rowForView:sender];
Alexandre Lision57914fa2016-02-10 14:52:24 -0500268 id callNode = [smartView itemAtRow:row];
269 auto callIdx = [treeController toQIdx:((NSTreeNode*)callNode)];
270
271 if (callIdx.isValid()) {
272 auto call = RecentModel::instance().getActiveCall(RecentModel::instance().peopleProxy()->mapToSource(callIdx));
273 call << Call::Action::REFUSE;
274 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400275}
276
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400277- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
278{
279 QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
Alexandre Lision57914fa2016-02-10 14:52:24 -0500280 return (((NSTreeNode*)item).indexPath.length == 1) ? 60.0 : 50.0;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400281}
282
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500283- (IBAction)placeCallFromSearchField:(id)sender
284{
285 if ([searchField stringValue].length == 0) {
286 return;
287 }
288 auto cm = PhoneDirectoryModel::instance().getNumber(QString::fromNSString([searchField stringValue]));
289 auto c = CallModel::instance().dialingCall();
290 [searchField setStringValue:@""];
291 RecentModel::instance().peopleProxy()->setFilterWildcard(QString::fromNSString([searchField stringValue]));
292 c->setPeerContactMethod(cm);
293 c << Call::Action::ACCEPT;
294 CallModel::instance().selectCall(c);
295}
296
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500297- (void) startConversationFromSearchField
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400298{
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500299 auto cm = PhoneDirectoryModel::instance().getNumber(QString::fromNSString([searchField stringValue]));
300 time_t currentTime;
301 ::time(&currentTime);
302 cm->setLastUsed(currentTime);
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500303 [searchField setStringValue:@""];
304 RecentModel::instance().peopleProxy()->setFilterWildcard(QString::fromNSString([searchField stringValue]));
305 auto proxyIdx = RecentModel::instance().peopleProxy()->mapToSource(RecentModel::instance().peopleProxy()->index(0, 0));
306 RecentModel::instance().selectionModel()->setCurrentIndex(proxyIdx, QItemSelectionModel::ClearAndSelect);
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400307}
308
Alexandre Lision61db3552015-10-22 19:12:52 -0400309- (void) addToContact
310{
311 if ([treeController selectedNodes].count == 0)
312 return;
313
314 auto qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
315 auto originIdx = RecentModel::instance().peopleProxy()->mapToSource(qIdx);
316 auto contactmethod = RecentModel::instance().getContactMethods(originIdx);
317 if (contactmethod.isEmpty())
318 return;
319
320 if (addToContactPopover != nullptr) {
321 [addToContactPopover performClose:self];
322 addToContactPopover = NULL;
323 } else if (contactmethod.first()) {
324 auto* editorVC = [[PersonLinkerVC alloc] initWithNibName:@"PersonLinker" bundle:nil];
325 [editorVC setMethodToLink:contactmethod.first()];
326 [editorVC setContactLinkedDelegate:self];
327 addToContactPopover = [[NSPopover alloc] init];
328 [addToContactPopover setContentSize:editorVC.view.frame.size];
329 [addToContactPopover setContentViewController:editorVC];
330 [addToContactPopover setAnimates:YES];
331 [addToContactPopover setBehavior:NSPopoverBehaviorTransient];
332 [addToContactPopover setDelegate:self];
333
334 [addToContactPopover showRelativeToRect:[smartView frameOfCellAtColumn:0 row:[smartView selectedRow]]
335 ofView:smartView preferredEdge:NSMaxXEdge];
336 }
337}
338
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400339- (void) copyNumberToPasteboard:(id) sender
340{
341 NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
342 [pasteBoard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
343 [pasteBoard setString:[sender representedObject] forType:NSStringPboardType];
344}
345
346- (void) callNumber:(id) sender
347{
348 Call* c = CallModel::instance().dialingCall();
349 c->setDialNumber(QString::fromNSString([sender representedObject]));
350 c << Call::Action::ACCEPT;
351}
352
Alexandre Lisionbf0385e2015-10-22 17:36:28 -0400353#pragma NSTextFieldDelegate
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400354
355- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector
356{
357 if (commandSelector == @selector(insertNewline:)) {
358 if([[searchField stringValue] isNotEqualTo:@""]) {
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500359 [self startConversationFromSearchField];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400360 return YES;
361 }
362 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400363 return NO;
364}
365
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500366- (void)controlTextDidChange:(NSNotification *) notification
367{
368 BOOL empty = [[searchField stringValue] isEqualTo:@""];
369 RecentModel::instance().peopleProxy()->setFilterWildcard(QString::fromNSString([searchField stringValue]));
370}
371
Alexandre Lision61db3552015-10-22 19:12:52 -0400372#pragma mark - NSPopOverDelegate
373
374- (void)popoverDidClose:(NSNotification *)notification
375{
376 if (addToContactPopover != nullptr) {
377 [addToContactPopover performClose:self];
378 addToContactPopover = NULL;
379 }
380}
381
Alexandre Lisionbf0385e2015-10-22 17:36:28 -0400382
Alexandre Lision61db3552015-10-22 19:12:52 -0400383#pragma mark - ContactLinkedDelegate
384
385- (void)contactLinked
386{
387 if (addToContactPopover != nullptr) {
388 [addToContactPopover performClose:self];
389 addToContactPopover = NULL;
390 }
391}
392
393#pragma mark - KeyboardShortcutDelegate
394
395- (void) onAddShortcut
396{
397 auto qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
398 auto originIdx = RecentModel::instance().peopleProxy()->mapToSource(qIdx);
399 auto contactmethods = RecentModel::instance().getContactMethods(originIdx);
400 if (contactmethods.isEmpty())
401 return;
402
403 auto contactmethod = contactmethods.first();
404 if (contactmethod && (!contactmethod->contact() || contactmethod->contact()->isPlaceHolder())) {
405 [self addToContact];
406 }
407}
408
409#pragma mark - ContextMenuDelegate
410
Alexandre Lision12946a72016-03-08 13:39:34 -0500411- (NSMenu*) contextualMenuForIndex:(NSTreeNode*) item
Alexandre Lision61db3552015-10-22 19:12:52 -0400412{
Alexandre Lision12946a72016-03-08 13:39:34 -0500413 auto qIdx = [treeController toQIdx:item];
414
415 if (!qIdx.isValid()) {
416 return nil;
417 }
418
Alexandre Lision61db3552015-10-22 19:12:52 -0400419 auto originIdx = RecentModel::instance().peopleProxy()->mapToSource(qIdx);
420 auto contactmethods = RecentModel::instance().getContactMethods(originIdx);
421 if (contactmethods.isEmpty())
422 return nil;
423
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400424 NSMenu *theMenu = [[NSMenu alloc] initWithTitle:@""];
425
426 if (contactmethods.size() == 1
427 && !contactmethods.first()->contact()
428 || contactmethods.first()->contact()->isPlaceHolder()) {
429
Alexandre Lision61db3552015-10-22 19:12:52 -0400430 [theMenu insertItemWithTitle:NSLocalizedString(@"Add to contacts", @"Contextual menu action")
431 action:@selector(addToContact)
432 keyEquivalent:@"a"
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400433 atIndex:theMenu.itemArray.count];
Alexandre Lision61db3552015-10-22 19:12:52 -0400434 }
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400435
436 NSMenu* copySubmenu = [[NSMenu alloc] init];
437 NSMenu* callSubmenu = [[NSMenu alloc] init];
438
439 for(auto cm : contactmethods) {
440 NSMenuItem* tmpCopyItem = [[NSMenuItem alloc] initWithTitle:cm->uri().toNSString()
441 action:@selector(copyNumberToPasteboard:)
442 keyEquivalent:@""];
443
444 [tmpCopyItem setRepresentedObject:cm->uri().toNSString()];
445 [copySubmenu addItem:tmpCopyItem];
446
447 NSMenuItem* tmpCallItem = [[NSMenuItem alloc] initWithTitle:cm->uri().toNSString()
448 action:@selector(callNumber:)
449 keyEquivalent:@""];
450 [tmpCallItem setRepresentedObject:cm->uri().toNSString()];
451 [callSubmenu addItem:tmpCallItem];
452 }
453
454 NSMenuItem* copyItems = [[NSMenuItem alloc] init];
455 [copyItems setTitle:NSLocalizedString(@"Copy number", @"Contextual menu action")];
456 [copyItems setSubmenu:copySubmenu];
457
458 NSMenuItem* callItems = [[NSMenuItem alloc] init];
459 [callItems setTitle:NSLocalizedString(@"Call number", @"Contextual menu action")];
460 [callItems setSubmenu:callSubmenu];
461
462 [theMenu insertItem:copyItems atIndex:theMenu.itemArray.count];
463 [theMenu insertItem:[NSMenuItem separatorItem] atIndex:theMenu.itemArray.count];
464 [theMenu insertItem:callItems atIndex:theMenu.itemArray.count];
465
466 return theMenu;
Alexandre Lision61db3552015-10-22 19:12:52 -0400467}
468
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400469@end