blob: c3712ab4acdc59045af4e190f48b1065edb5f5f8 [file] [log] [blame]
Alexandre Lision58cab672015-06-09 15:25:40 -04001/*
Alexandre Lision9fe374b2016-01-06 10:17:31 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Alexandre Lision58cab672015-06-09 15:25:40 -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 Lision58cab672015-06-09 15:25:40 -040018 */
19
20#import "ChatVC.h"
21
22#import <QItemSelectionModel>
23#import <qstring.h>
24
25#import <media/media.h>
26#import <media/text.h>
27#import <media/textrecording.h>
28#import <callmodel.h>
29
30@interface MediaConnectionsHolder : NSObject
31
32@property QMetaObject::Connection newMediaAdded;
33@property QMetaObject::Connection newMessage;
34
35@end
36
37@implementation MediaConnectionsHolder
38
39@end
40
41@interface ChatVC ()
42
43@property (unsafe_unretained) IBOutlet NSTextView *chatView;
44@property (unsafe_unretained) IBOutlet NSTextField *messageField;
45@property (unsafe_unretained) IBOutlet NSButton *sendButton;
46
47@property MediaConnectionsHolder* mediaHolder;
48
49@end
50
51@implementation ChatVC
52@synthesize messageField,chatView,sendButton, mediaHolder;
53
54- (void)awakeFromNib
55{
56 NSLog(@"Init ChatVC");
57
58 [self.view setWantsLayer:YES];
59 [self.view setLayer:[CALayer layer]];
60 [self.view.layer setBackgroundColor:[NSColor blackColor].CGColor];
61
62 mediaHolder = [[MediaConnectionsHolder alloc] init];
63
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040064 QObject::connect(CallModel::instance().selectionModel(),
Alexandre Lision58cab672015-06-09 15:25:40 -040065 &QItemSelectionModel::currentChanged,
66 [=](const QModelIndex &current, const QModelIndex &previous) {
67 [self setupChat];
68 });
Alexandre Lision98f67cd2015-06-22 14:27:34 -040069
70 // Override default style to add interline space
71 NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
72 paragraphStyle.lineSpacing = 8;
73 [chatView setDefaultParagraphStyle:paragraphStyle];
Alexandre Lision58cab672015-06-09 15:25:40 -040074}
75
Alexandre Lision16d9c0a2015-08-10 12:05:15 -040076
Alexandre Lision58cab672015-06-09 15:25:40 -040077- (void) setupChat
78{
79 QObject::disconnect(mediaHolder.newMediaAdded);
80 QObject::disconnect(mediaHolder.newMessage);
81
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040082 QModelIndex callIdx = CallModel::instance().selectionModel()->currentIndex();
Alexandre Lision58cab672015-06-09 15:25:40 -040083
84 if (!callIdx.isValid())
85 return;
86
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040087 Call* call = CallModel::instance().getCall(callIdx);
Alexandre Lision58cab672015-06-09 15:25:40 -040088
89 /* check if text media is already present */
90 if (call->hasMedia(Media::Media::Type::TEXT, Media::Media::Direction::IN)) {
91 Media::Text *text = call->firstMedia<Media::Text>(Media::Media::Direction::IN);
92 [self parseChatModel:text->recording()->instantMessagingModel()];
93 } else if (call->hasMedia(Media::Media::Type::TEXT, Media::Media::Direction::OUT)) {
94 Media::Text *text = call->firstMedia<Media::Text>(Media::Media::Direction::OUT);
95 [self parseChatModel:text->recording()->instantMessagingModel()];
96 } else {
97 /* monitor media for messaging text messaging */
98 mediaHolder.newMediaAdded = QObject::connect(call,
99 &Call::mediaAdded,
100 [self] (Media::Media* media) {
101 if (media->type() == Media::Media::Type::TEXT) {
102 QObject::disconnect(mediaHolder.newMediaAdded);
103 [self parseChatModel:((Media::Text*)media)->recording()->instantMessagingModel()];
104
105 }
106 });
107 }
108}
109
110- (void) parseChatModel:(QAbstractItemModel *)model
111{
112 QObject::disconnect(mediaHolder.newMessage);
113 [self.messageField setStringValue:@""];
114 self.message = @"";
115 [self.chatView.textStorage.mutableString setString:@""];
116
117 /* put all the messages in the im model into the text view */
118 for (int row = 0; row < model->rowCount(); ++row) {
119 [self appendNewMessage:model->index(row, 0)];
120 }
121
122 /* append new messages */
123 mediaHolder.newMessage = QObject::connect(model,
124 &QAbstractItemModel::rowsInserted,
125 [self, model] (const QModelIndex &parent, int first, int last) {
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400126 for (int row = first; row <= last; ++row) {
127 [self appendNewMessage:model->index(row, 0, parent)];
128 }
129 });
Alexandre Lision58cab672015-06-09 15:25:40 -0400130}
131
132- (void) appendNewMessage:(const QModelIndex&) msgIdx
133{
134 if (!msgIdx.isValid())
135 return;
136
Alexandre Lision98f67cd2015-06-22 14:27:34 -0400137 NSString* message = msgIdx.data(Qt::DisplayRole).value<QString>().toNSString();
138 NSString* author = msgIdx.data((int)Media::TextRecording::Role::AuthorDisplayname).value<QString>().toNSString();
139
140 NSMutableAttributedString* attr = [[NSMutableAttributedString alloc] initWithString:
141 [NSString stringWithFormat:@"%@: %@\n",author, message]];
142
143 // put in bold type author name
144 [attr applyFontTraits:NSBoldFontMask range: NSMakeRange(0, [author length])];
145
Alexandre Lision58cab672015-06-09 15:25:40 -0400146 [[chatView textStorage] appendAttributedString:attr];
Alexandre Lision98f67cd2015-06-22 14:27:34 -0400147
148 // reapply paragraph style on all the text
149 NSRange range = NSMakeRange(0,[chatView textStorage].length);
150 [[self.chatView textStorage] addAttribute:NSParagraphStyleAttributeName
151 value:chatView.defaultParagraphStyle
152 range:range];
153
Alexandre Lision58cab672015-06-09 15:25:40 -0400154 [chatView scrollRangeToVisible:NSMakeRange([[chatView string] length], 0)];
155
156}
157
Alexandre Lision16d9c0a2015-08-10 12:05:15 -0400158- (void) takeFocus
159{
160 [self.view.window makeFirstResponder:self.messageField];
161}
162
Alexandre Lision58cab672015-06-09 15:25:40 -0400163- (IBAction)sendMessage:(id)sender {
164
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400165 QModelIndex callIdx = CallModel::instance().selectionModel()->currentIndex();
166 Call* call = CallModel::instance().getCall(callIdx);
Alexandre Lision58cab672015-06-09 15:25:40 -0400167
168 /* make sure there is text to send */
169 NSString* text = self.message;
170 if (text && text.length > 0) {
Alexandre Lision21d20632015-07-22 15:49:44 -0400171 QMap<QString, QString> messages;
172 messages["text/plain"] = QString::fromNSString(text);
173 call->addOutgoingMedia<Media::Text>()->send(messages);
Alexandre Lision58cab672015-06-09 15:25:40 -0400174 // Empty the text after sending it
175 [self.messageField setStringValue:@""];
176 self.message = @"";
177 }
178}
179
180#pragma mark - NSTextFieldDelegate
181
182- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector
183{
184 if (commandSelector == @selector(insertNewline:) && self.message.length > 0) {
185 [self sendMessage:nil];
186 return YES;
187 }
188 return NO;
189}
190
191@end