1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2 
3 /* AbiSource Application Framework
4  * Copyright (C) 2003 Hubert Figuiere
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301 USA.
20  */
21 /*
22 	Implements the text view that supports the NSTextInput protocol
23  */
24 
25 #include "ut_assert.h"
26 #include "ut_debugmsg.h"
27 
28 #include "ev_CocoaKeyboard.h"
29 #include "ev_EditMethod.h"
30 #include "ev_NamedVirtualKey.h"
31 
32 #include "xap_App.h"
33 #import "xap_CocoaCompat.h"
34 #include "xap_CocoaTextView.h"
35 #include "xap_CocoaToolPalette.h"
36 #include "xap_Frame.h"
37 #include "xav_View.h"
38 
39 #include "fv_View.h"
40 
41 #include "pd_Document.h"
42 
43 @implementation XAP_CocoaTextView
44 
45 - (id)initWith:(XAP_Frame *)frame andFrame:(NSRect)windowFrame
46 {
47 	if (![super initWith:frame andFrame:windowFrame]) {
48 		return nil;
49 	}
50 	m_hasMarkedText = NO;
51 	return self;
52 }
53 
54 /* standard methods */
55 
56 - (BOOL)resignFirstResponder
57 {
58 	return YES;
59 }
60 
61 
62 /*!
63 	Invoke an Abi method
64  */
65 - (void)invokeEditMethod:(const char*)method
66 {
67 	EV_EditMethod* pEM;
68 	pEM = XAP_App::getApp()->getEditMethodContainer()->findEditMethodByName(method);
69 	AV_View * pView = m_pFrame->getCurrentView();
70 	EV_Keyboard * pCocoaKeyboard = m_pFrame->getKeyboard();
71 	pCocoaKeyboard->invokeKeyboardMethod(pView,pEM,0,0);
72 }
73 
74 
75 /* NSResponder methods */
76 - (void)insertNewline:(id)sender
77 {
78 	UT_UNUSED(sender);
79 	[self invokeEditMethod:"insertParagraphBreak"];
80 }
81 
82 - (void)insertTab:(id)sender
83 {
84 	UT_UNUSED(sender);
85 	[self invokeEditMethod:"insertTab"];
86 }
87 
88 - (void)deleteBackward:(id)sender
89 {
90 	UT_UNUSED(sender);
91 	[self invokeEditMethod:"delLeft"];
92 }
93 
94 - (void)deleteForward:(id)sender
95 {
96 	UT_UNUSED(sender);
97 	[self invokeEditMethod:"delRight"];
98 }
99 
100 - (void)deleteToEndOfParagraph:(id)sender
101 {
102 	UT_UNUSED(sender);
103 	[self invokeEditMethod:"delEOL"];
104 }
105 
106 - (void)moveForward:(id)sender;
107 {
108 	UT_UNUSED(sender);
109 	[self invokeEditMethod:"warpInsPtRight"];
110 }
111 
112 - (void)moveRight:(id)sender;
113 {
114 	UT_UNUSED(sender);
115 	[self invokeEditMethod:"warpInsPtRight"];
116 }
117 
118 - (void)moveBackward:(id)sender;
119 {
120 	UT_UNUSED(sender);
121 	[self invokeEditMethod:"warpInsPtLeft"];
122 }
123 
124 - (void)moveLeft:(id)sender;
125 {
126 	UT_UNUSED(sender);
127 	[self invokeEditMethod:"warpInsPtLeft"];
128 }
129 
130 - (void)moveUp:(id)sender;
131 {
132 	UT_UNUSED(sender);
133 	[self invokeEditMethod:"warpInsPtPrevLine"];
134 }
135 
136 - (void)moveDown:(id)sender;
137 {
138 	UT_UNUSED(sender);
139 	[self invokeEditMethod:"warpInsPtNextLine"];
140 }
141 - (void)moveWordForward:(id)sender
142 {
143 	UT_UNUSED(sender);
144 	[self invokeEditMethod:"warpInsPtEOW"];
145 }
146 - (void)moveWordBackward:(id)sender
147 {
148 	UT_UNUSED(sender);
149 	[self invokeEditMethod:"warpInsPtBOW"];
150 }
151 
152 - (void)moveWordRight:(id)sender
153 {
154 	UT_UNUSED(sender);
155 	[self invokeEditMethod:"warpInsPtEOW"];
156 }
157 
158 - (void)moveWordLeft:(id)sender
159 {
160 	UT_UNUSED(sender);
161 	[self invokeEditMethod:"warpInsPtBOW"];
162 }
163 
164 - (void)moveToBeginningOfLine:(id)sender
165 {
166 	UT_UNUSED(sender);
167 	[self invokeEditMethod:"warpInsPtBOL"];
168 }
169 
170 - (void)moveToEndOfLine:(id)sender
171 {
172 	UT_UNUSED(sender);
173 	[self invokeEditMethod:"warpInsPtEOL"];
174 }
175 - (void)moveToBeginningOfParagraph:(id)sender
176 {
177 	UT_UNUSED(sender);
178 	[self invokeEditMethod:"warpInsPtBOP"];
179 }
180 - (void)moveToEndOfParagraph:(id)sender
181 {
182 	UT_UNUSED(sender);
183 	[self invokeEditMethod:"warpInsPtEOP"];
184 }
185 #if 0
186 // implement the Edit method first
187 - (void)moveParagraphBackwardAndModifySelection:(id)sender
188 {
189 	UT_UNUSED(sender);
190 	[self invokeEditMethod:"extSelBOP"];
191 }
192 - (void)moveParagraphForwardAndModifySelection:(id)sender
193 {
194 	UT_UNUSED(sender);
195 	[self invokeEditMethod:"extSelEOP"];
196 }
197 #endif
198 
199 - (void)moveToEndOfDocument:(id)sender
200 {
201 	UT_UNUSED(sender);
202 	[self invokeEditMethod:"warpInsPtEOD"];
203 }
204 
205 - (void)moveToBeginningOfDocument:(id)sender
206 {
207 	UT_UNUSED(sender);
208 	[self invokeEditMethod:"warpInsPtBOD"];
209 }
210 
211 - (void)moveToEndOfDocumentAndModifySelection:(id)sender
212 {
213 	UT_UNUSED(sender);
214 	[self invokeEditMethod:"extSelEOD"];
215 }
216 - (void)moveToBeginningOfDocumentAndModifySelection:(id)sender
217 {
218 	UT_UNUSED(sender);
219 	[self invokeEditMethod:"extSelBOD"];
220 }
221 
222 - (void)pageDown:(id)sender;
223 {
224 	UT_UNUSED(sender);
225 	[self invokeEditMethod:"warpInsPtNextScreen"];
226 }
227 - (void)pageUp:(id)sender;
228 {
229 	UT_UNUSED(sender);
230 	[self invokeEditMethod:"warpInsPtPrevScreen"];
231 }
232 
233 - (void)moveLeftAndModifySelection:(id)sender
234 {
235 	UT_UNUSED(sender);
236 	[self invokeEditMethod:"extSelLeft"];
237 }
238 - (void)moveRightAndModifySelection:(id)sender
239 {
240 	UT_UNUSED(sender);
241 	[self invokeEditMethod:"extSelRight"];
242 }
243 
244 - (void)moveBackwardAndModifySelection:(id)sender
245 {
246 	UT_UNUSED(sender);
247 	[self invokeEditMethod:"extSelLeft"];
248 }
249 - (void)moveForwardAndModifySelection:(id)sender
250 {
251 	UT_UNUSED(sender);
252 	[self invokeEditMethod:"extSelRight"];
253 }
254 
255 - (void)moveWordForwardAndModifySelection:(id)sender
256 {
257 	UT_UNUSED(sender);
258 	[self invokeEditMethod:"extSelEOW"];
259 }
260 - (void)moveWordRightAndModifySelection:(id)sender
261 {
262 	UT_UNUSED(sender);
263 	[self invokeEditMethod:"extSelEOW"];
264 }
265 
266 - (void)moveWordBackwardAndModifySelection:(id)sender
267 {
268 	UT_UNUSED(sender);
269 	[self invokeEditMethod:"extSelBOW"];
270 }
271 - (void)moveWordLeftAndModifySelection:(id)sender
272 {
273 	UT_UNUSED(sender);
274 	[self invokeEditMethod:"extSelBOW"];
275 }
276 
277 - (void)moveUpAndModifySelection:(id)sender
278 {
279 	UT_UNUSED(sender);
280 	[self invokeEditMethod:"extSelPrevLine"];
281 }
282 - (void)moveDownAndModifySelection:(id)sender
283 {
284 	UT_UNUSED(sender);
285 	[self invokeEditMethod:"extSelNextLine"];
286 }
287 - (void)moveToBeginningOfLineAndModifySelection:(id)sender
288 {
289 	UT_UNUSED(sender);
290 	[self invokeEditMethod:"extSelBOL"];
291 }
292 - (void)moveToEndOfLineAndModifySelection:(id)sender
293 {
294 	UT_UNUSED(sender);
295 	[self invokeEditMethod:"extSelEOL"];
296 }
297 
298 - (void)scrollPageUp:(id)sender
299 {
300 	UT_UNUSED(sender);
301 	[self invokeEditMethod:"scrollPageUp"];
302 }
303 - (void)scrollPageDown:(id)sender
304 {
305 	UT_UNUSED(sender);
306 	[self invokeEditMethod:"scrollPageDown"];
307 }
308 - (void)scrollLineUp:(id)sender
309 {
310 	UT_UNUSED(sender);
311 	[self invokeEditMethod:"scrollLineUp"];
312 }
313 - (void)scrollLineDown:(id)sender
314 {
315 	UT_UNUSED(sender);
316 	[self invokeEditMethod:"scrollLineDown"];
317 }
318 - (void)scrollToBeginningOfDocument:(id)sender
319 {
320 	UT_UNUSED(sender);
321 	[self invokeEditMethod:"scrollToTop"];
322 }
323 - (void)scrollToEndOfDocument:(id)sender
324 {
325 	UT_UNUSED(sender);
326 	[self invokeEditMethod:"scrollToBottom"];
327 }
328 
329 
330 /* NSTextInput protocol */
331 - (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange
332 {
333 	UT_UNUSED(theRange);
334 	UT_ASSERT_NOT_REACHED();
335 	return nil;
336 }
337 
338 
339 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
340 {
341 	UT_UNUSED(thePoint);
342 	UT_ASSERT_NOT_REACHED();
343 	return NSNotFound;
344 }
345 
346 
347 - (long)conversationIdentifier
348 {
349 	return (long)self;
350 }
351 
352 - (void)doCommandBySelector:(SEL)aSelector
353 {
354 	if ([self respondsToSelector:aSelector]) {
355 		[self performSelector:aSelector withObject:self];
356 		return;
357 	}
358 	UT_DEBUGMSG(("Unrecognized selector:%s\n", [NSStringFromSelector(aSelector) UTF8String]));
359 //	UT_ASSERT_NOT_REACHED();
360 }
361 
362 
363 - (NSRect)firstRectForCharacterRange:(NSRange)theRange
364 {
365 	// UT_ASSERT_NOT_REACHED();
366 	UT_DEBUG_ONLY_ARG(theRange);
367 	UT_DEBUGMSG(("characterRange=(location=%u,length=%u)\n",theRange.location,theRange.length));
368 	return NSZeroRect;
369 }
370 
371 
372 - (BOOL)hasMarkedText
373 {
374 	UT_DEBUGMSG(("m_hasMarkedText=%s\n",m_hasMarkedText ? "YES" : "NO"));
375 	return m_hasMarkedText;
376 }
377 
378 
379 - (void)insertText:(id)aString
380 {
381 	 /* UT_DEBUGMSG(("insertText '%s' in window '%s'\n", [str UTF8String], [[[self window] title] UTF8String]));
382 	 */
383 	UT_DEBUGMSG(("insertText: length=%u\n", [(NSString *)aString length]));
384 //  	pFrame->setTimeOfLastEvent([theEvent timestamp]);
385 	AV_View * pView = m_pFrame->getCurrentView();
386 	ev_CocoaKeyboard * pCocoaKeyboard = static_cast<ev_CocoaKeyboard *>
387 		(m_pFrame->getKeyboard());
388 
389 	if (pView)
390 		pCocoaKeyboard->insertTextEvent(pView, aString);
391 
392 	[XAP_CocoaToolPalette setPreviewText:@""];
393 
394 	m_selectedRange = NSMakeRange(NSNotFound, 0);
395 	m_hasMarkedText = NO;
396 }
397 
398 
399 - (NSRange)markedRange
400 {
401 	// UT_ASSERT_NOT_REACHED();
402 	UT_DEBUGMSG(("markedRange (m_hasMarkedText=%s)\n",m_hasMarkedText ? "YES" : "NO"));
403 
404 	/* This method gets called when you delete the current character sequence to 0 length,
405 	 * so let's clear the preview...
406 	 */
407 	[XAP_CocoaToolPalette setPreviewText:@""];
408 
409 	m_selectedRange = NSMakeRange(NSNotFound, 0);
410 	m_hasMarkedText = NO;
411 
412 	return m_selectedRange;
413 }
414 
415 - (NSRange)selectedRange
416 {
417 	UT_DEBUGMSG(("selectedRange=(location=%u,length=%u)\n",m_selectedRange.location,m_selectedRange.length));
418 	return m_selectedRange;
419 }
420 
421 - (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange
422 {
423 	[XAP_CocoaToolPalette setPreviewText:aString];
424 
425 	m_selectedRange = selRange;
426 	m_hasMarkedText = (selRange.length != 0 ? YES : NO);
427 
428 	UT_DEBUGMSG(("range=(location=%u,length=%u) [aString length]=%u\n", selRange.location, selRange.length, [(NSString*)aString length]));
429 	/*
430 		Steal code from the selection handling code in XP land. We have the AV_View
431 		so everything is here.
432 	 */
433 
434 	if (FV_View * pView = static_cast<FV_View *>(m_pFrame->getCurrentView())) {
435 		NSString * str = 0;
436 
437 		if ([aString isKindOfClass:[NSString class]]) {
438 			str = (NSString *) aString;
439 		}
440 		else if ([aString isKindOfClass:[NSAttributedString class]]) {
441 			NSAttributedString * attr_str = (NSAttributedString *) aString;
442 			str = [attr_str string];
443 		}
444 		if (str) {
445 			if ([str length]) {
446 				UT_UCS4String ucs4([str UTF8String], [str length]);
447 
448 				PT_DocPosition oldPos = pView->getPoint();
449 
450 				if (!pView->isSelectionEmpty())
451 					oldPos = pView->getSelectionAnchor();
452 
453 				ev_CocoaKeyboard * pCocoaKeyboard = static_cast<ev_CocoaKeyboard *>(m_pFrame->getKeyboard());
454 				pCocoaKeyboard->insertTextEvent(pView, str);
455 
456 			//	pView->cmdCharInsert(ucs4.ucs4_str(), ucs4.length());
457 				pView->cmdSelect(oldPos, pView->getPoint());
458 			}
459 		}
460 	}
461 }
462 
463 - (void)unmarkText
464 {
465 	m_hasMarkedText = NO;
466 	UT_DEBUGMSG(("Hub TODO: handle -[XAP_CocoaTextView unmarkText]\n"));
467 }
468 
469 - (NSArray*)validAttributesForMarkedText
470 {
471 	return [NSArray array];
472 }
473 
474 @end
475