blob: d501c831d9d949f23bc9866cc8ced00b2dabdd7d [file] [log] [blame]
Alexandre Lision2db8f472015-07-22 15:05:46 -04001/*
Alexandre Lision9fe374b2016-01-06 10:17:31 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Alexandre Lision2db8f472015-07-22 15:05:46 -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 Lision2db8f472015-07-22 15:05:46 -040018 */
19
20#import "PersonLinkerVC.h"
21
22//Qt
23#import <QtMacExtras/qmacfunctions.h>
24#import <QPixmap>
25
26//LRC
27#import <person.h>
28#import <personmodel.h>
29#import <contactmethod.h>
30#import <numbercategorymodel.h>
Alexandre Lision7a166e42015-09-02 15:04:43 -040031#import <globalinstances.h>
Kateryna Kostiuk516a6882017-07-12 16:16:06 -040032#import <peerprofilecollection.h>
Alexandre Lision2db8f472015-07-22 15:05:46 -040033
34#import "QNSTreeController.h"
35#import "delegates/ImageManipulationDelegate.h"
Alexandre Lision2db8f472015-07-22 15:05:46 -040036
Kateryna Kostiukb90f92a2017-07-10 12:13:12 -040037
Alexandre Lision2db8f472015-07-22 15:05:46 -040038class OnlyPersonProxyModel : public QSortFilterProxyModel
39{
40public:
41 OnlyPersonProxyModel(QAbstractItemModel* parent) : QSortFilterProxyModel(parent)
42 {
43 setSourceModel(parent);
44 }
45 virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
46 {
47 bool match = filterRegExp().indexIn(sourceModel()->index(source_row,0,source_parent).data(Qt::DisplayRole).toString()) != -1;
48 //qDebug() << "FILTERING" << sourceModel()->index(source_row,0,source_parent) << "match:" << match;
49 return match && !sourceModel()->index(source_row,0,source_parent).parent().isValid();
50 }
51};
52
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040053@interface PersonLinkerVC () <NSTextFieldDelegate, NSComboBoxDelegate, NSComboBoxDataSource> {
Alexandre Lision2db8f472015-07-22 15:05:46 -040054
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040055 __unsafe_unretained IBOutlet NSTextField *contactMethodLabel;
56 __unsafe_unretained IBOutlet NSOutlineView *personsView;
57 __unsafe_unretained IBOutlet NSTextField *firstNameField;
58 __unsafe_unretained IBOutlet NSTextField *lastNameField;
59 __unsafe_unretained IBOutlet NSButton *createNewContactButton;
60 __unsafe_unretained IBOutlet NSComboBox *categoryComboBox;
61 __unsafe_unretained IBOutlet NSView *linkToExistingSubview;
Kateryna Kostiukb90f92a2017-07-10 12:13:12 -040062 __unsafe_unretained IBOutlet NSView *addCloudContactMsg;
Alexandre Lision2db8f472015-07-22 15:05:46 -040063
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040064 QSortFilterProxyModel* contactProxyModel;
65 QNSTreeController* treeController;
66 IBOutlet NSView *createContactSubview;
67}
Alexandre Lision2db8f472015-07-22 15:05:46 -040068
69@end
70
71@implementation PersonLinkerVC
Alexandre Lision4dfcafc2015-08-20 12:43:23 -040072
73// Tags for views
74NSInteger const FIRSTNAME_TAG = 1;
75NSInteger const LASTNAME_TAG = 2;
76NSInteger const IMAGE_TAG = 100;
77NSInteger const DISPLAYNAME_TAG = 200;
78NSInteger const DETAILS_TAG = 300;
Alexandre Lision2db8f472015-07-22 15:05:46 -040079
80-(void) awakeFromNib
81{
82 NSLog(@"INIT PersonLinkerVC");
83
84 [firstNameField setTag:FIRSTNAME_TAG];
85 [lastNameField setTag:LASTNAME_TAG];
86
87 [categoryComboBox selectItemAtIndex:0];
88
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040089 contactProxyModel = new OnlyPersonProxyModel(&PersonModel::instance());
Alexandre Lision2db8f472015-07-22 15:05:46 -040090 contactProxyModel->setSortRole(static_cast<int>(Qt::DisplayRole));
91 contactProxyModel->sort(0,Qt::AscendingOrder);
92 contactProxyModel->setFilterRole(Qt::DisplayRole);
93 treeController = [[QNSTreeController alloc] initWithQModel:contactProxyModel];
94
95 [treeController setAvoidsEmptySelection:NO];
96 [treeController setChildrenKeyPath:@"children"];
97
98 [personsView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil];
99 [personsView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil];
100 [personsView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];
101 [personsView setTarget:self];
102 [personsView setDoubleAction:@selector(addToContact:)];
103
104 [contactMethodLabel setStringValue:self.methodToLink->uri().toNSString()];
105}
106
107- (IBAction)addToContact:(id)sender
108{
109 /* get the selected number category */
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400110 const auto& idx = NumberCategoryModel::instance().index([categoryComboBox indexOfSelectedItem]);
Alexandre Lision2db8f472015-07-22 15:05:46 -0400111 if (idx.isValid()) {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400112 auto category = NumberCategoryModel::instance().getCategory(idx.data().toString());
Alexandre Lision2db8f472015-07-22 15:05:46 -0400113 self.methodToLink->setCategory(category);
114 }
115
116 if([[treeController selectedNodes] count] > 0) {
117 QModelIndex qIdx = [treeController toQIdx:[treeController selectedNodes][0]];
118 ContactMethod* m = nil;
119 if(((NSTreeNode*)[treeController selectedNodes][0]).indexPath.length == 1) {
120 // Person
121 QVariant var = qIdx.data((int)Person::Role::Object);
122 if (var.isValid()) {
123 Person *p = var.value<Person*>();
124 Person::ContactMethods cms = p->phoneNumbers();
125 cms.append(self.methodToLink);
126 p->setContactMethods(cms);
127 self.methodToLink->setPerson(p);
128 p->save();
129 [self.contactLinkedDelegate contactLinked];
130 }
131 }
132 }
133}
134
135- (void) dealloc
136{
137 // No ARC for c++ pointers
138 delete contactProxyModel;
139}
140
141- (IBAction)presentNewContactForm:(id)sender {
142 [createContactSubview setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
143 //[createContactSubview setBounds:linkToExistingSubview.bounds];
Kateryna Kostiuk516a6882017-07-12 16:16:06 -0400144 [addCloudContactMsg setHidden:TRUE];
Kateryna Kostiukb90f92a2017-07-10 12:13:12 -0400145
Alexandre Lision2db8f472015-07-22 15:05:46 -0400146 [createContactSubview setFrame:linkToExistingSubview.frame];
147 [linkToExistingSubview setHidden:YES];
148 [self.view addSubview:createContactSubview];
149
150 [[[NSApplication sharedApplication] mainWindow] makeFirstResponder:firstNameField];
151 [firstNameField setNextKeyView:lastNameField];
152 [lastNameField setNextKeyView:createNewContactButton];
153 [createNewContactButton setNextKeyView:firstNameField];
154}
155
156- (IBAction)createContact:(id)sender
157{
158 /* get the selected number category */
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400159 const auto& idx = NumberCategoryModel::instance().index([categoryComboBox indexOfSelectedItem]);
Alexandre Lision2db8f472015-07-22 15:05:46 -0400160 if (idx.isValid()) {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400161 auto category = NumberCategoryModel::instance().getCategory(idx.data().toString());
Alexandre Lision2db8f472015-07-22 15:05:46 -0400162 self.methodToLink->setCategory(category);
163 }
164
165 /* create a new person */
166 Person *p = new Person();
167 p->setFirstName(QString::fromNSString(firstNameField.stringValue));
168 p->setFamilyName(QString::fromNSString(lastNameField.stringValue));
169 p->setFormattedName(QString::fromNSString([[NSString alloc] initWithFormat:@"%@ %@", firstNameField.stringValue, lastNameField.stringValue]));
170 /* associate the new person with the contact method */
171 Person::ContactMethods numbers;
172 numbers << self.methodToLink;
173 p->setContactMethods(numbers);
174 self.methodToLink->setPerson(p);
Kateryna Kostiuk516a6882017-07-12 16:16:06 -0400175 auto personCollections = PersonModel::instance().collections();
176 CollectionInterface *peerProfileCollection = nil;
177 foreach(auto collection, personCollections) {
178 if(dynamic_cast<PeerProfileCollection*>(collection))
179 peerProfileCollection = collection;
180 }
181 if(peerProfileCollection) {
182 PersonModel::instance().addNewPerson(p, peerProfileCollection);
183 }
Alexandre Lision2db8f472015-07-22 15:05:46 -0400184 [self.contactLinkedDelegate contactLinked];
185}
186
187#pragma mark - NSOutlineViewDelegate methods
188
189// -------------------------------------------------------------------------------
190// shouldSelectItem:item
191// -------------------------------------------------------------------------------
192- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item;
193{
194 QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400195 return qIdx.isValid();
Alexandre Lision2db8f472015-07-22 15:05:46 -0400196}
197
198// -------------------------------------------------------------------------------
199// shouldEditTableColumn:tableColumn:item
200//
201// Decide to allow the edit of the given outline view "item".
202// -------------------------------------------------------------------------------
203- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
204{
205 return NO;
206}
207
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400208/* View Based OutlineView: See the delegate method -tableView:viewForTableColumn:row: in NSTableView.
209 */
210- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item
Alexandre Lision2db8f472015-07-22 15:05:46 -0400211{
212 QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400213
214 NSTableCellView *result = [outlineView makeViewWithIdentifier:@"MainCell" owner:outlineView];
215 NSImageView* photoView = [result viewWithTag:IMAGE_TAG];
216 NSTextField* displayName = [result viewWithTag:DISPLAYNAME_TAG];
Alexandre Lision196545b2016-05-13 17:05:13 -0400217 [photoView setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(qIdx.data(Qt::DecorationRole)))];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400218 [displayName setStringValue:qIdx.data(Qt::DisplayRole).toString().toNSString()];
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400219 return result;
Alexandre Lision2db8f472015-07-22 15:05:46 -0400220}
221
222// -------------------------------------------------------------------------------
223// outlineViewSelectionDidChange:notification
224// -------------------------------------------------------------------------------
225
226- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
227{
Alexandre Lision4dfcafc2015-08-20 12:43:23 -0400228 return 60.0;
Alexandre Lision2db8f472015-07-22 15:05:46 -0400229}
230
231#pragma mark - NSTextFieldDelegate
232
233- (void)controlTextDidChange:(NSNotification *) notification
234{
235 if ([notification.object tag] == FIRSTNAME_TAG || [notification.object tag] == LASTNAME_TAG) {
236 NSTextView *textView = notification.userInfo[@"NSFieldEditor"];
237 BOOL enableCreate = textView.textStorage.string.length > 0;
238 [createNewContactButton setEnabled:enableCreate];
239 } else {
240 NSTextView *textView = notification.userInfo[@"NSFieldEditor"];
241 contactProxyModel->setFilterRegExp(QRegExp(QString::fromNSString(textView.textStorage.string), Qt::CaseInsensitive, QRegExp::FixedString));
242 [personsView scrollToBeginningOfDocument:nil];
243 }
244}
245
246#pragma mark - NSComboBoxDelegate
247
248- (void)comboBoxSelectionDidChange:(NSNotification*) notification
249{
250 [(NSComboBox *)[notification object] indexOfSelectedItem];
251}
252
253#pragma mark - NSComboBoxDatasource
254
255- (NSInteger)numberOfItemsInComboBox:(NSComboBox *)aComboBox
256{
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400257 return NumberCategoryModel::instance().rowCount();
Alexandre Lision2db8f472015-07-22 15:05:46 -0400258}
259
260- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(NSInteger)index
261{
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400262 return NumberCategoryModel::instance().index(index).data().toString().toNSString();
Alexandre Lision2db8f472015-07-22 15:05:46 -0400263}
264
265@end