blob: 6910ec7cd7d9e4cc57c1301919965e3391980eaa [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"
42#import "views/RingOutlineView.h"
Alexandre Lision4e280d62015-09-09 15:56:30 -040043#import "views/ContextualTableCellView.h"
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040044
Alexandre Lision61db3552015-10-22 19:12:52 -040045@interface SmartViewVC () <NSOutlineViewDelegate, NSPopoverDelegate, ContextMenuDelegate, ContactLinkedDelegate, KeyboardShortcutDelegate> {
Alexandre Lision0f66bd32016-01-18 11:30:45 -050046
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040047 QNSTreeController *treeController;
Alexandre Lision61db3552015-10-22 19:12:52 -040048 NSPopover* addToContactPopover;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040049
50 //UI elements
Alexandre Lision61db3552015-10-22 19:12:52 -040051 __unsafe_unretained IBOutlet RingOutlineView* smartView;
52 __unsafe_unretained IBOutlet NSSearchField* searchField;
Alexandre Lision61db3552015-10-22 19:12:52 -040053 __unsafe_unretained IBOutlet NSTabView* tabbar;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040054}
55
56@end
57
58@implementation SmartViewVC
59
60// Tags for views
61NSInteger const IMAGE_TAG = 100;
62NSInteger const DISPLAYNAME_TAG = 200;
63NSInteger const DETAILS_TAG = 300;
64NSInteger const CALL_BUTTON_TAG = 400;
65NSInteger const TXT_BUTTON_TAG = 500;
66
67- (void)awakeFromNib
68{
69 NSLog(@"INIT SmartView VC");
70
Alexandre Lision0f66bd32016-01-18 11:30:45 -050071 RecentModel::instance().peopleProxy()->setFilterRole((int)Ring::Role::Name);
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040072 treeController = [[QNSTreeController alloc] initWithQModel:RecentModel::instance().peopleProxy()];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040073 [treeController setAvoidsEmptySelection:NO];
74 [treeController setChildrenKeyPath:@"children"];
75
76 [smartView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil];
77 [smartView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil];
78 [smartView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];
79 [smartView setTarget:self];
Alexandre Lision89edc6a2015-11-09 11:30:47 -050080 [smartView setAction:@selector(selectRow:)];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040081 [smartView setDoubleAction:@selector(placeCall:)];
82
Alexandre Lision61db3552015-10-22 19:12:52 -040083 [smartView setContextMenuDelegate:self];
84 [smartView setShortcutsDelegate:self];
85
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040086 QObject::connect(RecentModel::instance().peopleProxy(),
Alexandre Lisionee098462015-10-22 17:22:50 -040087 &QAbstractItemModel::dataChanged,
88 [self](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
89 for(int row = topLeft.row() ; row <= bottomRight.row() ; ++row)
90 {
91 [smartView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:row]
92 columnIndexes:[NSIndexSet indexSetWithIndex:0]];
93 }
94 });
95
Alexandre Lision89edc6a2015-11-09 11:30:47 -050096 QObject::connect(RecentModel::instance().selectionModel(),
97 &QItemSelectionModel::currentChanged,
98 [=](const QModelIndex &current, const QModelIndex &previous) {
Alexandre Lision01cf5e32016-01-21 15:54:30 -050099 if(!current.isValid()) {
100 [smartView deselectAll:nil];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500101 return;
Alexandre Lision01cf5e32016-01-21 15:54:30 -0500102 }
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500103
104 auto proxyIdx = RecentModel::instance().peopleProxy()->mapFromSource(current);
105 if (proxyIdx.isValid()) {
106 [treeController setSelectionQModelIndex:proxyIdx];
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500107 [tabbar selectTabViewItemAtIndex:0];
108 [smartView scrollRowToVisible:proxyIdx.row()];
109 }
110 });
111
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400112 [self.view setWantsLayer:YES];
113 [self.view setLayer:[CALayer layer]];
114 [self.view.layer setBackgroundColor:[NSColor whiteColor].CGColor];
115
116 [searchField setWantsLayer:YES];
117 [searchField setLayer:[CALayer layer]];
118 [searchField.layer setBackgroundColor:[NSColor colorWithCalibratedRed:0.949 green:0.949 blue:0.949 alpha:0.9].CGColor];
119}
120
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500121-(void) selectRow:(id)sender
122{
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500123 if ([treeController selectedNodes].count == 0) {
124 RecentModel::instance().selectionModel()->clearCurrentIndex();
125 return;
126 }
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500127 auto qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
128 auto proxyIdx = RecentModel::instance().peopleProxy()->mapToSource(qIdx);
129 RecentModel::instance().selectionModel()->setCurrentIndex(proxyIdx, QItemSelectionModel::ClearAndSelect);
130}
131
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400132- (void)placeCall:(id)sender
133{
134 QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
135 ContactMethod* m = nil;
136
137 // Double click on an ongoing call
138 if (qIdx.parent().isValid()) {
139 return;
140 }
141
142 if([[treeController selectedNodes] count] > 0) {
143 QVariant var = qIdx.data((int)Call::Role::ContactMethod);
144 m = qvariant_cast<ContactMethod*>(var);
145 if (!m) {
146 // test if it is a person
147 QVariant var = qIdx.data((int)Person::Role::Object);
148 if (var.isValid()) {
149 Person *c = var.value<Person*>();
150 if (c->phoneNumbers().size() > 0) {
151 m = c->phoneNumbers().first();
152 }
153 }
154 }
155 }
156
157 // Before calling check if we properly extracted a contact method and that
158 // there is NOT already an ongoing call for this index (e.g: no children for this node)
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400159 if(m && !RecentModel::instance().peopleProxy()->index(0, 0, qIdx).isValid()){
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500160 auto c = CallModel::instance().dialingCall();
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400161 c->setPeerContactMethod(m);
162 c << Call::Action::ACCEPT;
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500163 CallModel::instance().selectCall(c);
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400164 }
165}
166
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500167- (IBAction)showHistory:(NSButton*)sender
168{
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500169 [tabbar selectTabViewItemAtIndex:1];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400170}
171
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500172- (IBAction)showContacts:(NSButton*)sender
173{
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500174 [tabbar selectTabViewItemAtIndex:2];
175}
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500176
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500177- (IBAction)showSmartlist:(NSButton*)sender
178{
179 [tabbar selectTabViewItemAtIndex:0];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400180}
181
182#pragma mark - NSOutlineViewDelegate methods
183
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400184- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item;
185{
186 return YES;
187}
188
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400189- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
190{
191 return NO;
192}
193
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400194- (void)outlineViewSelectionDidChange:(NSNotification *)notification
195{
196 if ([treeController selectedNodes].count <= 0) {
Alexandre Lision89edc6a2015-11-09 11:30:47 -0500197 RecentModel::instance().selectionModel()->clearCurrentIndex();
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400198 return;
199 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400200}
201
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400202- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item
203{
204 QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
205 NSTableCellView *result;
206 if (!qIdx.parent().isValid()) {
207 result = [outlineView makeViewWithIdentifier:@"MainCell" owner:outlineView];
208 NSTextField* details = [result viewWithTag:DETAILS_TAG];
209
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500210 NSMutableArray* controls = [NSMutableArray arrayWithObject:[result viewWithTag:CALL_BUTTON_TAG]];
211 [((ContextualTableCellView*) result) setContextualsControls:controls];
Alexandre Lision4e280d62015-09-09 15:56:30 -0400212
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400213 if (auto call = RecentModel::instance().getActiveCall(RecentModel::instance().peopleProxy()->mapToSource(qIdx))) {
Alexandre Lisiond14bda32015-10-13 11:34:29 -0400214 [details setStringValue:call->roleData((int)Ring::Role::FormattedState).toString().toNSString()];
Alexandre Lision21666f32015-09-22 17:04:36 -0400215 [((ContextualTableCellView*) result) setActiveState:YES];
216 } else {
Alexandre Lisiond14bda32015-10-13 11:34:29 -0400217 [details setStringValue:qIdx.data((int)Ring::Role::FormattedLastUsed).toString().toNSString()];
Alexandre Lision21666f32015-09-22 17:04:36 -0400218 [((ContextualTableCellView*) result) setActiveState:NO];
219 }
220
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500221 NSTextField* unreadCount = [result viewWithTag:TXT_BUTTON_TAG];
222 int unread = qIdx.data((int)Ring::Role::UnreadTextMessageCount).toInt();
223 [unreadCount setHidden:(unread == 0)];
224 [unreadCount.layer setCornerRadius:5.0f];
225 [unreadCount setStringValue:qIdx.data((int)Ring::Role::UnreadTextMessageCount).toString().toNSString()];
226
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400227 } else {
228 result = [outlineView makeViewWithIdentifier:@"CallCell" owner:outlineView];
229 NSTextField* details = [result viewWithTag:DETAILS_TAG];
230
231 [details setStringValue:qIdx.data((int)Call::Role::HumanStateName).toString().toNSString()];
232 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400233
234 NSTextField* displayName = [result viewWithTag:DISPLAYNAME_TAG];
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500235 [displayName setStringValue:qIdx.data((int)Ring::Role::Name).toString().toNSString()];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400236 NSImageView* photoView = [result viewWithTag:IMAGE_TAG];
237 Person* p = qvariant_cast<Person*>(qIdx.data((int)Person::Role::Object));
Alexandre Lisiond5229f32015-11-16 11:17:41 -0500238 QVariant photo = GlobalInstances::pixmapManipulator().contactPhoto(p, QSize(50,50));
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400239 [photoView setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(photo))];
240 return result;
241}
242
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500243- (void)outlineView:(NSOutlineView *)outlineView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row
244{
245 [outlineView scrollRowToVisible:0];
246}
247
248- (NSTableRowView *)outlineView:(NSOutlineView *)outlineView rowViewForItem:(id)item
249{
250 return [outlineView makeViewWithIdentifier:@"HoverRowView" owner:nil];
251}
252
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400253- (IBAction)callClickedAtRow:(id)sender {
254 NSInteger row = [smartView rowForView:sender];
255 [smartView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
256 [self placeCall:nil];
257}
258
259- (IBAction)hangUpClickedAtRow:(id)sender {
260 NSInteger row = [smartView rowForView:sender];
261 [smartView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400262 CallModel::instance().getCall(CallModel::instance().selectionModel()->currentIndex()) << Call::Action::REFUSE;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400263}
264
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400265- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
266{
267 QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
268 return (((NSTreeNode*)item).indexPath.length == 1) ? 60.0 : 45.0;
269}
270
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500271- (IBAction)placeCallFromSearchField:(id)sender
272{
273 if ([searchField stringValue].length == 0) {
274 return;
275 }
276 auto cm = PhoneDirectoryModel::instance().getNumber(QString::fromNSString([searchField stringValue]));
277 auto c = CallModel::instance().dialingCall();
278 [searchField setStringValue:@""];
279 RecentModel::instance().peopleProxy()->setFilterWildcard(QString::fromNSString([searchField stringValue]));
280 c->setPeerContactMethod(cm);
281 c << Call::Action::ACCEPT;
282 CallModel::instance().selectCall(c);
283}
284
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500285- (void) startConversationFromSearchField
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400286{
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500287 auto cm = PhoneDirectoryModel::instance().getNumber(QString::fromNSString([searchField stringValue]));
288 time_t currentTime;
289 ::time(&currentTime);
290 cm->setLastUsed(currentTime);
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500291 [searchField setStringValue:@""];
292 RecentModel::instance().peopleProxy()->setFilterWildcard(QString::fromNSString([searchField stringValue]));
293 auto proxyIdx = RecentModel::instance().peopleProxy()->mapToSource(RecentModel::instance().peopleProxy()->index(0, 0));
294 RecentModel::instance().selectionModel()->setCurrentIndex(proxyIdx, QItemSelectionModel::ClearAndSelect);
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400295}
296
Alexandre Lision61db3552015-10-22 19:12:52 -0400297- (void) addToContact
298{
299 if ([treeController selectedNodes].count == 0)
300 return;
301
302 auto qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
303 auto originIdx = RecentModel::instance().peopleProxy()->mapToSource(qIdx);
304 auto contactmethod = RecentModel::instance().getContactMethods(originIdx);
305 if (contactmethod.isEmpty())
306 return;
307
308 if (addToContactPopover != nullptr) {
309 [addToContactPopover performClose:self];
310 addToContactPopover = NULL;
311 } else if (contactmethod.first()) {
312 auto* editorVC = [[PersonLinkerVC alloc] initWithNibName:@"PersonLinker" bundle:nil];
313 [editorVC setMethodToLink:contactmethod.first()];
314 [editorVC setContactLinkedDelegate:self];
315 addToContactPopover = [[NSPopover alloc] init];
316 [addToContactPopover setContentSize:editorVC.view.frame.size];
317 [addToContactPopover setContentViewController:editorVC];
318 [addToContactPopover setAnimates:YES];
319 [addToContactPopover setBehavior:NSPopoverBehaviorTransient];
320 [addToContactPopover setDelegate:self];
321
322 [addToContactPopover showRelativeToRect:[smartView frameOfCellAtColumn:0 row:[smartView selectedRow]]
323 ofView:smartView preferredEdge:NSMaxXEdge];
324 }
325}
326
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400327- (void) copyNumberToPasteboard:(id) sender
328{
329 NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
330 [pasteBoard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
331 [pasteBoard setString:[sender representedObject] forType:NSStringPboardType];
332}
333
334- (void) callNumber:(id) sender
335{
336 Call* c = CallModel::instance().dialingCall();
337 c->setDialNumber(QString::fromNSString([sender representedObject]));
338 c << Call::Action::ACCEPT;
339}
340
Alexandre Lisionbf0385e2015-10-22 17:36:28 -0400341#pragma NSTextFieldDelegate
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400342
343- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector
344{
345 if (commandSelector == @selector(insertNewline:)) {
346 if([[searchField stringValue] isNotEqualTo:@""]) {
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500347 [self startConversationFromSearchField];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400348 return YES;
349 }
350 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400351 return NO;
352}
353
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500354- (void)controlTextDidChange:(NSNotification *) notification
355{
356 BOOL empty = [[searchField stringValue] isEqualTo:@""];
357 RecentModel::instance().peopleProxy()->setFilterWildcard(QString::fromNSString([searchField stringValue]));
358}
359
Alexandre Lision61db3552015-10-22 19:12:52 -0400360#pragma mark - NSPopOverDelegate
361
362- (void)popoverDidClose:(NSNotification *)notification
363{
364 if (addToContactPopover != nullptr) {
365 [addToContactPopover performClose:self];
366 addToContactPopover = NULL;
367 }
368}
369
Alexandre Lisionbf0385e2015-10-22 17:36:28 -0400370
Alexandre Lision61db3552015-10-22 19:12:52 -0400371#pragma mark - ContactLinkedDelegate
372
373- (void)contactLinked
374{
375 if (addToContactPopover != nullptr) {
376 [addToContactPopover performClose:self];
377 addToContactPopover = NULL;
378 }
379}
380
381#pragma mark - KeyboardShortcutDelegate
382
383- (void) onAddShortcut
384{
385 auto qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
386 auto originIdx = RecentModel::instance().peopleProxy()->mapToSource(qIdx);
387 auto contactmethods = RecentModel::instance().getContactMethods(originIdx);
388 if (contactmethods.isEmpty())
389 return;
390
391 auto contactmethod = contactmethods.first();
392 if (contactmethod && (!contactmethod->contact() || contactmethod->contact()->isPlaceHolder())) {
393 [self addToContact];
394 }
395}
396
397#pragma mark - ContextMenuDelegate
398
399- (NSMenu*) contextualMenuForIndex:(NSIndexPath*) path
400{
401 auto qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
402 auto originIdx = RecentModel::instance().peopleProxy()->mapToSource(qIdx);
403 auto contactmethods = RecentModel::instance().getContactMethods(originIdx);
404 if (contactmethods.isEmpty())
405 return nil;
406
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400407 NSMenu *theMenu = [[NSMenu alloc] initWithTitle:@""];
408
409 if (contactmethods.size() == 1
410 && !contactmethods.first()->contact()
411 || contactmethods.first()->contact()->isPlaceHolder()) {
412
Alexandre Lision61db3552015-10-22 19:12:52 -0400413 [theMenu insertItemWithTitle:NSLocalizedString(@"Add to contacts", @"Contextual menu action")
414 action:@selector(addToContact)
415 keyEquivalent:@"a"
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400416 atIndex:theMenu.itemArray.count];
Alexandre Lision61db3552015-10-22 19:12:52 -0400417 }
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400418
419 NSMenu* copySubmenu = [[NSMenu alloc] init];
420 NSMenu* callSubmenu = [[NSMenu alloc] init];
421
422 for(auto cm : contactmethods) {
423 NSMenuItem* tmpCopyItem = [[NSMenuItem alloc] initWithTitle:cm->uri().toNSString()
424 action:@selector(copyNumberToPasteboard:)
425 keyEquivalent:@""];
426
427 [tmpCopyItem setRepresentedObject:cm->uri().toNSString()];
428 [copySubmenu addItem:tmpCopyItem];
429
430 NSMenuItem* tmpCallItem = [[NSMenuItem alloc] initWithTitle:cm->uri().toNSString()
431 action:@selector(callNumber:)
432 keyEquivalent:@""];
433 [tmpCallItem setRepresentedObject:cm->uri().toNSString()];
434 [callSubmenu addItem:tmpCallItem];
435 }
436
437 NSMenuItem* copyItems = [[NSMenuItem alloc] init];
438 [copyItems setTitle:NSLocalizedString(@"Copy number", @"Contextual menu action")];
439 [copyItems setSubmenu:copySubmenu];
440
441 NSMenuItem* callItems = [[NSMenuItem alloc] init];
442 [callItems setTitle:NSLocalizedString(@"Call number", @"Contextual menu action")];
443 [callItems setSubmenu:callSubmenu];
444
445 [theMenu insertItem:copyItems atIndex:theMenu.itemArray.count];
446 [theMenu insertItem:[NSMenuItem separatorItem] atIndex:theMenu.itemArray.count];
447 [theMenu insertItem:callItems atIndex:theMenu.itemArray.count];
448
449 return theMenu;
Alexandre Lision61db3552015-10-22 19:12:52 -0400450}
451
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400452@end