blob: b59678f3b584f025cab3540a39b79ff9d67295d1 [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>
Olivier Soldanod4311552017-11-20 15:09:53 -05004 * Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com>
5 * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com>
Alexandre Lision4dfcafc2015-08-20 12:43:23 -04006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22#import "SmartViewVC.h"
23
24//Qt
25#import <QtMacExtras/qmacfunctions.h>
26#import <QPixmap>
27#import <QIdentityProxyModel>
28#import <QItemSelectionModel>
29
30//LRC
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040031#import <globalinstances.h>
Olivier Soldanod4311552017-11-20 15:09:53 -050032#import <api/newaccountmodel.h>
33#import <api/conversationmodel.h>
34#import <api/account.h>
35#import <api/contact.h>
36#import <api/contactmodel.h>
37#import <api/newcallmodel.h>
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040038
39#import "QNSTreeController.h"
40#import "delegates/ImageManipulationDelegate.h"
Alexandre Lision4e280d62015-09-09 15:56:30 -040041#import "views/HoverTableRowView.h"
Alexandre Lision61db3552015-10-22 19:12:52 -040042#import "PersonLinkerVC.h"
Alexandre Lision4baba4c2016-02-11 13:00:57 -050043#import "views/IconButton.h"
Olivier Soldanod4311552017-11-20 15:09:53 -050044#import "views/RingTableView.h"
Alexandre Lision4e280d62015-09-09 15:56:30 -040045#import "views/ContextualTableCellView.h"
Olivier Soldanod4311552017-11-20 15:09:53 -050046#import "utils.h"
Anthony Léonardbee94cc2018-01-16 11:42:40 -050047#import "RingWindowController.h"
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040048
Olivier Soldanod4311552017-11-20 15:09:53 -050049@interface SmartViewVC () <NSTableViewDelegate, NSTableViewDataSource, NSPopoverDelegate, ContextMenuDelegate, ContactLinkedDelegate, KeyboardShortcutDelegate> {
Alexandre Lision0f66bd32016-01-18 11:30:45 -050050
Alexandre Lision61db3552015-10-22 19:12:52 -040051 NSPopover* addToContactPopover;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040052
53 //UI elements
Olivier Soldanod4311552017-11-20 15:09:53 -050054 __unsafe_unretained IBOutlet RingTableView* smartView;
Alexandre Lision61db3552015-10-22 19:12:52 -040055 __unsafe_unretained IBOutlet NSSearchField* searchField;
Anthony Léonard0a9904c2018-01-11 16:43:47 -050056 __unsafe_unretained IBOutlet NSSegmentedControl *listTypeSelector;
Alexandre Lision45c18672016-11-02 15:24:45 -040057
Anthony Léonard01634102017-12-27 16:37:16 -050058 QMetaObject::Connection modelSortedConnection_, filterChangedConnection_, newConversationConnection_, conversationRemovedConnection_;
Olivier Soldanod4311552017-11-20 15:09:53 -050059
60 lrc::api::ConversationModel* model_;
61 std::string selectedUid_;
Anthony Léonard4bfd68b2018-01-15 16:23:50 -050062 lrc::api::profile::Type currentFilterType;
Anthony Léonardbee94cc2018-01-16 11:42:40 -050063
64 __unsafe_unretained IBOutlet RingWindowController *delegate;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040065}
66
67@end
68
69@implementation SmartViewVC
70
Kateryna Kostiuk882cbac2017-07-05 17:29:00 -040071@synthesize tabbar;
72
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040073// Tags for views
Alexandre Lision57914fa2016-02-10 14:52:24 -050074NSInteger const IMAGE_TAG = 100;
75NSInteger const DISPLAYNAME_TAG = 200;
76NSInteger const DETAILS_TAG = 300;
77NSInteger const CALL_BUTTON_TAG = 400;
78NSInteger const TXT_BUTTON_TAG = 500;
79NSInteger const CANCEL_BUTTON_TAG = 600;
Kateryna Kostiuk6a536362017-05-02 14:26:12 -040080NSInteger const RING_ID_LABEL = 700;
Kateryna Kostiukd9039e92017-05-24 14:29:54 -040081NSInteger const PRESENCE_TAG = 800;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040082
Anthony Léonarde6a01fa2018-01-12 10:29:58 -050083// Segment indices for smartlist selector
84NSInteger const CONVERSATION_SEG = 0;
85NSInteger const REQUEST_SEG = 1;
86
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040087- (void)awakeFromNib
88{
89 NSLog(@"INIT SmartView VC");
Olivier Soldanod4311552017-11-20 15:09:53 -050090 //get selected account
91 //encapsulate conversationmodel in local version
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040092
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040093 [smartView setTarget:self];
94 [smartView setDoubleAction:@selector(placeCall:)];
95
Alexandre Lision61db3552015-10-22 19:12:52 -040096 [smartView setContextMenuDelegate:self];
97 [smartView setShortcutsDelegate:self];
98
Olivier Soldanod4311552017-11-20 15:09:53 -050099 [smartView setDataSource: self];
Kateryna Kostiuk1f705ab2017-04-18 12:45:59 -0400100
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400101 [self.view setWantsLayer:YES];
102 [self.view setLayer:[CALayer layer]];
103 [self.view.layer setBackgroundColor:[NSColor whiteColor].CGColor];
104
105 [searchField setWantsLayer:YES];
106 [searchField setLayer:[CALayer layer]];
107 [searchField.layer setBackgroundColor:[NSColor colorWithCalibratedRed:0.949 green:0.949 blue:0.949 alpha:0.9].CGColor];
Anthony Léonard4bfd68b2018-01-15 16:23:50 -0500108
109 currentFilterType = lrc::api::profile::Type::RING;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400110}
111
112- (void)placeCall:(id)sender
113{
Olivier Soldanod4311552017-11-20 15:09:53 -0500114 NSInteger row;
115 if (sender != nil && [sender clickedRow] != -1)
116 row = [sender clickedRow];
117 else if ([smartView selectedRow] != -1)
118 row = [smartView selectedRow];
119 else
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400120 return;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400121
Olivier Soldanod4311552017-11-20 15:09:53 -0500122 auto conv = model_->filteredConversation(row);
123 model_->placeCall(conv.uid);
124}
125
126-(void) reloadData
127{
128 [smartView deselectAll:nil];
129 [smartView reloadData];
130
Anthony Léonard4bfd68b2018-01-15 16:23:50 -0500131 if (!model_->owner.contactModel->hasPendingRequests()) {
132 if (currentFilterType == lrc::api::profile::Type::PENDING) {
133 [self selectConversationList];
134 }
135 [listTypeSelector setEnabled:NO forSegment:REQUEST_SEG];
136 } else {
137 [listTypeSelector setEnabled:YES forSegment:REQUEST_SEG];
138 }
139
Olivier Soldanod4311552017-11-20 15:09:53 -0500140 if (!selectedUid_.empty() && model_ != nil) {
Anthony Léonard6f819752018-01-05 09:53:40 -0500141 auto it = getConversationFromUid(selectedUid_, *model_);
Olivier Soldanod4311552017-11-20 15:09:53 -0500142 if (it != model_->allFilteredConversations().end()) {
143 NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:(it - model_->allFilteredConversations().begin())];
144 [smartView selectRowIndexes:indexSet byExtendingSelection:NO];
145 } else {
146 selectedUid_.clear();
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400147 }
148 }
149
Olivier Soldanod4311552017-11-20 15:09:53 -0500150 [smartView scrollToBeginningOfDocument:nil];
151}
152
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500153- (BOOL)setConversationModel:(lrc::api::ConversationModel *)conversationModel
Olivier Soldanod4311552017-11-20 15:09:53 -0500154{
155 if (model_ != conversationModel) {
156 model_ = conversationModel;
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500157 selectedUid_.clear(); // Clear selected conversation as the selected account is being changed
Olivier Soldanod4311552017-11-20 15:09:53 -0500158 [self reloadData];
159 QObject::disconnect(modelSortedConnection_);
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500160 QObject::disconnect(filterChangedConnection_);
Anthony Léonard01634102017-12-27 16:37:16 -0500161 QObject::disconnect(newConversationConnection_);
162 QObject::disconnect(conversationRemovedConnection_);
Olivier Soldanod4311552017-11-20 15:09:53 -0500163 if (model_ != nil) {
164 modelSortedConnection_ = QObject::connect(model_, &lrc::api::ConversationModel::modelSorted,
165 [self] (){
166 [self reloadData];
167 });
168 filterChangedConnection_ = QObject::connect(model_, &lrc::api::ConversationModel::filterChanged,
169 [self] (){
170 [self reloadData];
171 });
Anthony Léonard01634102017-12-27 16:37:16 -0500172 newConversationConnection_ = QObject::connect(model_, &lrc::api::ConversationModel::newConversation,
173 [self] (){
174 [self reloadData];
175 });
176 conversationRemovedConnection_ = QObject::connect(model_, &lrc::api::ConversationModel::conversationRemoved,
177 [self] (){
178 [self reloadData];
179 });
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500180 model_->setFilter(""); // Reset the filter
181 }
182 [searchField setStringValue:@""];
183 return YES;
184 }
185 return NO;
186}
187
188-(void)selectConversation:(const lrc::api::conversation::Info&)conv model:(lrc::api::ConversationModel*)model;
189{
190 auto& uid = conv.uid;
191 if (selectedUid_ == uid)
192 return;
193
194 [self setConversationModel:model];
195
196 if (model_ != nil) {
Anthony Léonard6f819752018-01-05 09:53:40 -0500197 auto it = getConversationFromUid(selectedUid_, *model_);
Anthony Léonard9bebf1d2017-12-21 14:33:51 -0500198 if (it != model_->allFilteredConversations().end()) {
199 NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:(it - model_->allFilteredConversations().begin())];
200 [smartView selectRowIndexes:indexSet byExtendingSelection:NO];
201 selectedUid_ = uid;
Olivier Soldanod4311552017-11-20 15:09:53 -0500202 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400203 }
204}
205
Anthony Léonard8585cc02017-12-28 14:03:45 -0500206-(void)deselect
207{
208 selectedUid_.clear();
209 [smartView deselectAll:nil];
210}
211
Anthony Léonard0a9904c2018-01-11 16:43:47 -0500212- (IBAction) listTypeChanged:(id)sender
213{
214 NSInteger selectedItem = [sender selectedSegment];
Anthony Léonarde6a01fa2018-01-12 10:29:58 -0500215 switch (selectedItem) {
216 case CONVERSATION_SEG:
Anthony Léonardbee94cc2018-01-16 11:42:40 -0500217 if (currentFilterType != lrc::api::profile::Type::RING) {
218 model_->setFilter(lrc::api::profile::Type::RING);
219 [delegate listTypeChanged];
220 currentFilterType = lrc::api::profile::Type::RING;
221 }
Anthony Léonarde6a01fa2018-01-12 10:29:58 -0500222 break;
223 case REQUEST_SEG:
Anthony Léonardbee94cc2018-01-16 11:42:40 -0500224 if (currentFilterType != lrc::api::profile::Type::PENDING) {
225 model_->setFilter(lrc::api::profile::Type::PENDING);
226 [delegate listTypeChanged];
227 currentFilterType = lrc::api::profile::Type::PENDING;
228 }
Anthony Léonarde6a01fa2018-01-12 10:29:58 -0500229 break;
230 default:
231 NSLog(@"Invalid item selected in list selector: %d", selectedItem);
Anthony Léonard0a9904c2018-01-11 16:43:47 -0500232 }
233}
234
235-(void) selectConversationList
236{
Anthony Léonarde6a01fa2018-01-12 10:29:58 -0500237 [listTypeSelector setSelectedSegment:CONVERSATION_SEG];
Anthony Léonard4bfd68b2018-01-15 16:23:50 -0500238
239 // Do not invert order of the next two lines or stack overflow
240 // may happen on -(void) reloadData call if filter is currently set to PENDING
241 currentFilterType = lrc::api::profile::Type::RING;
Anthony Léonard0a9904c2018-01-11 16:43:47 -0500242 model_->setFilter(lrc::api::profile::Type::RING);
Anthony Léonard4bfd68b2018-01-15 16:23:50 -0500243 model_->setFilter("");
Anthony Léonard0a9904c2018-01-11 16:43:47 -0500244}
245
Olivier Soldanod4311552017-11-20 15:09:53 -0500246#pragma mark - NSTableViewDelegate methods
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400247
Olivier Soldanod4311552017-11-20 15:09:53 -0500248- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400249{
250 return YES;
251}
252
Olivier Soldanod4311552017-11-20 15:09:53 -0500253- (BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400254{
255 return NO;
256}
257
Olivier Soldanod4311552017-11-20 15:09:53 -0500258- (void)tableViewSelectionDidChange:(NSNotification *)notification
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400259{
Olivier Soldanod4311552017-11-20 15:09:53 -0500260 NSInteger row = [notification.object selectedRow];
261
262 if (row == -1)
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400263 return;
Olivier Soldanod4311552017-11-20 15:09:53 -0500264
265 auto uid = model_->filteredConversation(row).uid;
266 if (selectedUid_ != uid) {
267 selectedUid_ = uid;
268 model_->selectConversation(uid);
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400269 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400270}
271
Olivier Soldanod4311552017-11-20 15:09:53 -0500272- (NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400273{
Olivier Soldanod4311552017-11-20 15:09:53 -0500274 return [tableView makeViewWithIdentifier:@"HoverRowView" owner:nil];
275}
Alexandre Lisiona4bb0512016-04-19 18:04:31 -0400276
Olivier Soldanod4311552017-11-20 15:09:53 -0500277- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
278{
279 if (model_ == nil)
280 return nil;
281
282 auto conversation = model_->filteredConversation(row);
Alexandre Lisiona4bb0512016-04-19 18:04:31 -0400283 NSTableCellView* result;
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400284
Olivier Soldanod4311552017-11-20 15:09:53 -0500285 result = [tableView makeViewWithIdentifier:@"MainCell" owner:tableView];
286// NSTextField* details = [result viewWithTag:DETAILS_TAG];
Alexandre Lision4e280d62015-09-09 15:56:30 -0400287
Olivier Soldanod4311552017-11-20 15:09:53 -0500288 NSMutableArray* controls = [NSMutableArray arrayWithObject:[result viewWithTag:CALL_BUTTON_TAG]];
289 [((ContextualTableCellView*) result) setContextualsControls:controls];
290 [((ContextualTableCellView*) result) setShouldBlurParentView:YES];
Alexandre Lision21666f32015-09-22 17:04:36 -0400291
Olivier Soldanod4311552017-11-20 15:09:53 -0500292// if (auto call = RecentModel::instance().getActiveCall(qIdx)) {
293// [details setStringValue:call->roleData((int)Ring::Role::FormattedState).toString().toNSString()];
294// [((ContextualTableCellView*) result) setActiveState:YES];
295// } else {
296// [details setStringValue:qIdx.data((int)Ring::Role::FormattedLastUsed).toString().toNSString()];
297// [((ContextualTableCellView*) result) setActiveState:NO];
298// }
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500299
Olivier Soldanod4311552017-11-20 15:09:53 -0500300 NSTextField* unreadCount = [result viewWithTag:TXT_BUTTON_TAG];
301 [unreadCount setHidden:(conversation.unreadMessages == 0)];
302 [unreadCount setIntValue:conversation.unreadMessages];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400303
304 NSTextField* displayName = [result viewWithTag:DISPLAYNAME_TAG];
Olivier Soldanod4311552017-11-20 15:09:53 -0500305 NSString* displayNameString = bestNameForConversation(conversation, *model_);
306 NSString* displayIDString = bestIDForConversation(conversation, *model_);
Kateryna Kostiuk6a536362017-05-02 14:26:12 -0400307 if(displayNameString.length == 0 || [displayNameString isEqualToString:displayIDString]) {
Anthony Léonard4adc3f02017-07-21 10:23:04 -0400308 NSTextField* displayRingID = [result viewWithTag:RING_ID_LABEL];
Kateryna Kostiuk6a536362017-05-02 14:26:12 -0400309 [displayName setStringValue:displayIDString];
Anthony Léonard4adc3f02017-07-21 10:23:04 -0400310 [displayRingID setHidden:YES];
Kateryna Kostiuk9d6657a2017-04-25 13:42:25 -0400311 }
Kateryna Kostiuk6a536362017-05-02 14:26:12 -0400312 else {
313 NSTextField* displayRingID = [result viewWithTag:RING_ID_LABEL];
314 [displayName setStringValue:displayNameString];
Kateryna Kostiuk6a536362017-05-02 14:26:12 -0400315 [displayRingID setStringValue:displayIDString];
Anthony Léonard4adc3f02017-07-21 10:23:04 -0400316 [displayRingID setHidden:NO];
Kateryna Kostiuk6a536362017-05-02 14:26:12 -0400317 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400318 NSImageView* photoView = [result viewWithTag:IMAGE_TAG];
Alexandre Lision43e91bc2016-04-19 18:04:52 -0400319
Olivier Soldanod4311552017-11-20 15:09:53 -0500320 auto& imageManip = reinterpret_cast<Interfaces::ImageManipulationDelegate&>(GlobalInstances::pixmapManipulator());
321 [photoView setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(imageManip.conversationPhoto(conversation, model_->owner)))];
Kateryna Kostiukd9039e92017-05-24 14:29:54 -0400322
323 NSView* presenceView = [result viewWithTag:PRESENCE_TAG];
Olivier Soldanod4311552017-11-20 15:09:53 -0500324 if (model_->owner.contactModel->getContact(conversation.participants[0]).isPresent) {
Kateryna Kostiukd9039e92017-05-24 14:29:54 -0400325 [presenceView setHidden:NO];
326 } else {
327 [presenceView setHidden:YES];
328 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400329 return result;
330}
331
Olivier Soldanod4311552017-11-20 15:09:53 -0500332- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500333{
Olivier Soldanod4311552017-11-20 15:09:53 -0500334 return 60.0;
335}
336
337#pragma mark - NSTableDataSource methods
338
339- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
340{
341 if (tableView == smartView) {
342 if (model_ != nullptr)
343 return model_->allFilteredConversations().size();
344 }
345
346 return 0;
Alexandre Lision0f66bd32016-01-18 11:30:45 -0500347}
348
Kateryna Kostiuk882cbac2017-07-05 17:29:00 -0400349- (void)startCallForRow:(id)sender {
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400350 NSInteger row = [smartView rowForView:sender];
351 [smartView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
352 [self placeCall:nil];
353}
354
355- (IBAction)hangUpClickedAtRow:(id)sender {
356 NSInteger row = [smartView rowForView:sender];
Alexandre Lision57914fa2016-02-10 14:52:24 -0500357
Olivier Soldanod4311552017-11-20 15:09:53 -0500358 if (row == -1)
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500359 return;
Alexandre Lision45c18672016-11-02 15:24:45 -0400360
Olivier Soldanod4311552017-11-20 15:09:53 -0500361 auto conv = model_->filteredConversation(row);
362 auto& callId = conv.callId;
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500363
Olivier Soldanod4311552017-11-20 15:09:53 -0500364 if (callId.empty())
365 return;
366
367 auto* callModel = model_->owner.callModel.get();
368 callModel->hangUp(callId);
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400369}
370
Alexandre Lision45c18672016-11-02 15:24:45 -0400371- (void) displayErrorModalWithTitle:(NSString*) title WithMessage:(NSString*) message
372{
373 NSAlert* alert = [NSAlert alertWithMessageText:title
374 defaultButton:@"Ok"
375 alternateButton:nil
376 otherButton:nil
377 informativeTextWithFormat:message];
378
379 [alert beginSheetModalForWindow:self.view.window modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
380}
381
Olivier Soldanod4311552017-11-20 15:09:53 -0500382- (void) processSearchFieldInput
Alexandre Lision45c18672016-11-02 15:24:45 -0400383{
Olivier Soldanod4311552017-11-20 15:09:53 -0500384 model_->setFilter(std::string([[searchField stringValue] UTF8String]));
Alexandre Lision45c18672016-11-02 15:24:45 -0400385}
386
Olivier Soldanod4311552017-11-20 15:09:53 -0500387-(const lrc::api::account::Info&) chosenAccount
Kateryna Kostiukd2f7b5d2017-06-09 15:30:49 -0400388{
Olivier Soldanod4311552017-11-20 15:09:53 -0500389 return model_->owner;
Kateryna Kostiukd2f7b5d2017-06-09 15:30:49 -0400390}
391
Alexandre Lisionf909fb12016-11-03 12:35:36 -0400392- (void) clearSearchField
393{
394 [searchField setStringValue:@""];
Olivier Soldanod4311552017-11-20 15:09:53 -0500395 [self processSearchFieldInput];
Kateryna Kostiuk9dd759c2017-07-11 12:06:55 -0400396}
397
Alexandre Lision72a669e2016-09-14 17:52:16 -0400398/**
399 Copy a NSString in the general Pasteboard
400
401 @param sender the NSObject containing the represented object to copy
402 */
403- (void) copyStringToPasteboard:(id) sender
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400404{
405 NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
406 [pasteBoard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
407 [pasteBoard setString:[sender representedObject] forType:NSStringPboardType];
408}
409
Alexandre Lisionbf0385e2015-10-22 17:36:28 -0400410#pragma NSTextFieldDelegate
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400411
412- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector
413{
414 if (commandSelector == @selector(insertNewline:)) {
415 if([[searchField stringValue] isNotEqualTo:@""]) {
Olivier Soldanod4311552017-11-20 15:09:53 -0500416 [self processSearchFieldInput];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400417 return YES;
418 }
419 }
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400420 return NO;
421}
422
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500423- (void)controlTextDidChange:(NSNotification *) notification
424{
Olivier Soldanod4311552017-11-20 15:09:53 -0500425 [self processSearchFieldInput];
Alexandre Lisionac4f5b62016-02-17 13:53:12 -0500426}
427
Alexandre Lision61db3552015-10-22 19:12:52 -0400428#pragma mark - NSPopOverDelegate
429
430- (void)popoverDidClose:(NSNotification *)notification
431{
432 if (addToContactPopover != nullptr) {
433 [addToContactPopover performClose:self];
434 addToContactPopover = NULL;
435 }
436}
437
Alexandre Lisionbf0385e2015-10-22 17:36:28 -0400438
Alexandre Lision61db3552015-10-22 19:12:52 -0400439#pragma mark - ContactLinkedDelegate
440
441- (void)contactLinked
442{
443 if (addToContactPopover != nullptr) {
444 [addToContactPopover performClose:self];
445 addToContactPopover = NULL;
446 }
447}
448
449#pragma mark - KeyboardShortcutDelegate
450
451- (void) onAddShortcut
452{
Olivier Soldanod4311552017-11-20 15:09:53 -0500453 if ([smartView selectedRow] == -1)
Alexandre Lision61db3552015-10-22 19:12:52 -0400454 return;
455
Olivier Soldanod4311552017-11-20 15:09:53 -0500456 auto uid = model_->filteredConversation([smartView selectedRow]).uid;
457 model_->makePermanent(uid);
Alexandre Lision61db3552015-10-22 19:12:52 -0400458}
459
460#pragma mark - ContextMenuDelegate
461
Olivier Soldanod4311552017-11-20 15:09:53 -0500462#if 0
463// TODO: Reimplement contextual menu with new models and behaviors
Alexandre Lision12946a72016-03-08 13:39:34 -0500464- (NSMenu*) contextualMenuForIndex:(NSTreeNode*) item
Alexandre Lision61db3552015-10-22 19:12:52 -0400465{
Alexandre Lision12946a72016-03-08 13:39:34 -0500466 auto qIdx = [treeController toQIdx:item];
467
468 if (!qIdx.isValid()) {
469 return nil;
470 }
471
Alexandre Lision61db3552015-10-22 19:12:52 -0400472 auto originIdx = RecentModel::instance().peopleProxy()->mapToSource(qIdx);
473 auto contactmethods = RecentModel::instance().getContactMethods(originIdx);
474 if (contactmethods.isEmpty())
475 return nil;
476
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400477 NSMenu *theMenu = [[NSMenu alloc] initWithTitle:@""];
478
479 if (contactmethods.size() == 1
480 && !contactmethods.first()->contact()
481 || contactmethods.first()->contact()->isPlaceHolder()) {
482
Kateryna Kostiuk9dd759c2017-07-11 12:06:55 -0400483 NSMenuItem* addContactItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Add to contacts", @"Contextual menu action")
484 action:@selector(addContactForRow:)
485 keyEquivalent:@""];
486 [addContactItem setRepresentedObject:item];
487 [theMenu addItem:addContactItem];
Alexandre Lision72a669e2016-09-14 17:52:16 -0400488 } else if (auto person = contactmethods.first()->contact()) {
489 NSMenuItem* copyNameItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Copy name", @"Contextual menu action")
490 action:@selector(copyStringToPasteboard:)
491 keyEquivalent:@""];
492
493 [copyNameItem setRepresentedObject:person->formattedName().toNSString()];
494 [theMenu addItem:copyNameItem];
Alexandre Lision61db3552015-10-22 19:12:52 -0400495 }
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400496
497 NSMenu* copySubmenu = [[NSMenu alloc] init];
498 NSMenu* callSubmenu = [[NSMenu alloc] init];
499
Alexandre Lision72a669e2016-09-14 17:52:16 -0400500 for (auto cm : contactmethods) {
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400501 NSMenuItem* tmpCopyItem = [[NSMenuItem alloc] initWithTitle:cm->uri().toNSString()
Alexandre Lision72a669e2016-09-14 17:52:16 -0400502 action:@selector(copyStringToPasteboard:)
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400503 keyEquivalent:@""];
504
505 [tmpCopyItem setRepresentedObject:cm->uri().toNSString()];
506 [copySubmenu addItem:tmpCopyItem];
507
508 NSMenuItem* tmpCallItem = [[NSMenuItem alloc] initWithTitle:cm->uri().toNSString()
509 action:@selector(callNumber:)
510 keyEquivalent:@""];
511 [tmpCallItem setRepresentedObject:cm->uri().toNSString()];
512 [callSubmenu addItem:tmpCallItem];
513 }
514
Alexandre Lision72a669e2016-09-14 17:52:16 -0400515 NSMenuItem* copyNumberItem = [[NSMenuItem alloc] init];
516 [copyNumberItem setTitle:NSLocalizedString(@"Copy number", @"Contextual menu action")];
517 [copyNumberItem setSubmenu:copySubmenu];
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400518
519 NSMenuItem* callItems = [[NSMenuItem alloc] init];
520 [callItems setTitle:NSLocalizedString(@"Call number", @"Contextual menu action")];
521 [callItems setSubmenu:callSubmenu];
522
Alexandre Lision72a669e2016-09-14 17:52:16 -0400523 [theMenu insertItem:copyNumberItem atIndex:theMenu.itemArray.count];
Alexandre Lisiond7bf2882015-10-22 22:54:32 -0400524 [theMenu insertItem:[NSMenuItem separatorItem] atIndex:theMenu.itemArray.count];
525 [theMenu insertItem:callItems atIndex:theMenu.itemArray.count];
526
527 return theMenu;
Alexandre Lision61db3552015-10-22 19:12:52 -0400528}
Olivier Soldanod4311552017-11-20 15:09:53 -0500529#endif
Alexandre Lision61db3552015-10-22 19:12:52 -0400530
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400531@end