blob: baf0560e6f041daaaffcb903ddddb1fef27d05ef [file] [log] [blame]
Alexandre Lision58cab672015-06-09 15:25:40 -04001/*
2 * Copyright (C) 2015 Savoir-Faire Linux Inc.
3 * 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 * Additional permission under GNU GPL version 3 section 7:
20 *
21 * If you modify this program, or any covered work, by linking or
22 * combining it with the OpenSSL project's OpenSSL library (or a
23 * modified version of that library), containing parts covered by the
24 * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
25 * grants you additional permission to convey the resulting work.
26 * Corresponding Source for a non-source form of such a combination
27 * shall include the source code for the parts of OpenSSL used as well
28 * as that of the covered work.
29 */
30
31#import "ChatVC.h"
32
33#import <QItemSelectionModel>
34#import <qstring.h>
35
36#import <media/media.h>
37#import <media/text.h>
38#import <media/textrecording.h>
39#import <callmodel.h>
40
41@interface MediaConnectionsHolder : NSObject
42
43@property QMetaObject::Connection newMediaAdded;
44@property QMetaObject::Connection newMessage;
45
46@end
47
48@implementation MediaConnectionsHolder
49
50@end
51
52@interface ChatVC ()
53
54@property (unsafe_unretained) IBOutlet NSTextView *chatView;
55@property (unsafe_unretained) IBOutlet NSTextField *messageField;
56@property (unsafe_unretained) IBOutlet NSButton *sendButton;
57
58@property MediaConnectionsHolder* mediaHolder;
59
60@end
61
62@implementation ChatVC
63@synthesize messageField,chatView,sendButton, mediaHolder;
64
65- (void)awakeFromNib
66{
67 NSLog(@"Init ChatVC");
68
69 [self.view setWantsLayer:YES];
70 [self.view setLayer:[CALayer layer]];
71 [self.view.layer setBackgroundColor:[NSColor blackColor].CGColor];
72
73 mediaHolder = [[MediaConnectionsHolder alloc] init];
74
75 QObject::connect(CallModel::instance()->selectionModel(),
76 &QItemSelectionModel::currentChanged,
77 [=](const QModelIndex &current, const QModelIndex &previous) {
78 [self setupChat];
79 });
Alexandre Lision98f67cd2015-06-22 14:27:34 -040080
81 // Override default style to add interline space
82 NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
83 paragraphStyle.lineSpacing = 8;
84 [chatView setDefaultParagraphStyle:paragraphStyle];
Alexandre Lision58cab672015-06-09 15:25:40 -040085}
86
Alexandre Lision16d9c0a2015-08-10 12:05:15 -040087
Alexandre Lision58cab672015-06-09 15:25:40 -040088- (void) setupChat
89{
90 QObject::disconnect(mediaHolder.newMediaAdded);
91 QObject::disconnect(mediaHolder.newMessage);
92
93 QModelIndex callIdx = CallModel::instance()->selectionModel()->currentIndex();
94
95 if (!callIdx.isValid())
96 return;
97
98 Call* call = CallModel::instance()->getCall(callIdx);
99
100 /* check if text media is already present */
101 if (call->hasMedia(Media::Media::Type::TEXT, Media::Media::Direction::IN)) {
102 Media::Text *text = call->firstMedia<Media::Text>(Media::Media::Direction::IN);
103 [self parseChatModel:text->recording()->instantMessagingModel()];
104 } else if (call->hasMedia(Media::Media::Type::TEXT, Media::Media::Direction::OUT)) {
105 Media::Text *text = call->firstMedia<Media::Text>(Media::Media::Direction::OUT);
106 [self parseChatModel:text->recording()->instantMessagingModel()];
107 } else {
108 /* monitor media for messaging text messaging */
109 mediaHolder.newMediaAdded = QObject::connect(call,
110 &Call::mediaAdded,
111 [self] (Media::Media* media) {
112 if (media->type() == Media::Media::Type::TEXT) {
113 QObject::disconnect(mediaHolder.newMediaAdded);
114 [self parseChatModel:((Media::Text*)media)->recording()->instantMessagingModel()];
115
116 }
117 });
118 }
119}
120
121- (void) parseChatModel:(QAbstractItemModel *)model
122{
123 QObject::disconnect(mediaHolder.newMessage);
124 [self.messageField setStringValue:@""];
125 self.message = @"";
126 [self.chatView.textStorage.mutableString setString:@""];
127
128 /* put all the messages in the im model into the text view */
129 for (int row = 0; row < model->rowCount(); ++row) {
130 [self appendNewMessage:model->index(row, 0)];
131 }
132
133 /* append new messages */
134 mediaHolder.newMessage = QObject::connect(model,
135 &QAbstractItemModel::rowsInserted,
136 [self, model] (const QModelIndex &parent, int first, int last) {
Alexandre Lisionb65c0272015-07-22 15:51:29 -0400137 for (int row = first; row <= last; ++row) {
138 [self appendNewMessage:model->index(row, 0, parent)];
139 }
140 });
Alexandre Lision58cab672015-06-09 15:25:40 -0400141}
142
143- (void) appendNewMessage:(const QModelIndex&) msgIdx
144{
145 if (!msgIdx.isValid())
146 return;
147
Alexandre Lision98f67cd2015-06-22 14:27:34 -0400148 NSString* message = msgIdx.data(Qt::DisplayRole).value<QString>().toNSString();
149 NSString* author = msgIdx.data((int)Media::TextRecording::Role::AuthorDisplayname).value<QString>().toNSString();
150
151 NSMutableAttributedString* attr = [[NSMutableAttributedString alloc] initWithString:
152 [NSString stringWithFormat:@"%@: %@\n",author, message]];
153
154 // put in bold type author name
155 [attr applyFontTraits:NSBoldFontMask range: NSMakeRange(0, [author length])];
156
Alexandre Lision58cab672015-06-09 15:25:40 -0400157 [[chatView textStorage] appendAttributedString:attr];
Alexandre Lision98f67cd2015-06-22 14:27:34 -0400158
159 // reapply paragraph style on all the text
160 NSRange range = NSMakeRange(0,[chatView textStorage].length);
161 [[self.chatView textStorage] addAttribute:NSParagraphStyleAttributeName
162 value:chatView.defaultParagraphStyle
163 range:range];
164
Alexandre Lision58cab672015-06-09 15:25:40 -0400165 [chatView scrollRangeToVisible:NSMakeRange([[chatView string] length], 0)];
166
167}
168
Alexandre Lision16d9c0a2015-08-10 12:05:15 -0400169- (void) takeFocus
170{
171 [self.view.window makeFirstResponder:self.messageField];
172}
173
Alexandre Lision58cab672015-06-09 15:25:40 -0400174- (IBAction)sendMessage:(id)sender {
175
176 QModelIndex callIdx = CallModel::instance()->selectionModel()->currentIndex();
177 Call* call = CallModel::instance()->getCall(callIdx);
178
179 /* make sure there is text to send */
180 NSString* text = self.message;
181 if (text && text.length > 0) {
Alexandre Lision21d20632015-07-22 15:49:44 -0400182 QMap<QString, QString> messages;
183 messages["text/plain"] = QString::fromNSString(text);
184 call->addOutgoingMedia<Media::Text>()->send(messages);
Alexandre Lision58cab672015-06-09 15:25:40 -0400185 // Empty the text after sending it
186 [self.messageField setStringValue:@""];
187 self.message = @"";
188 }
189}
190
191#pragma mark - NSTextFieldDelegate
192
193- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector
194{
195 if (commandSelector == @selector(insertNewline:) && self.message.length > 0) {
196 [self sendMessage:nil];
197 return YES;
198 }
199 return NO;
200}
201
202@end