1// ADPersonPropertyView+Events.m (this is -*- ObjC -*-)
2//
3// Authors: Bj�rn Giesler <giesler@ira.uka.de>
4//          Riccardo Mottola <rm@gnu.org>
5//
6// Address View Framework for GNUstep
7//
8
9
10/* system includes */
11/* (none) */
12
13/* my includes */
14#import "ADPersonPropertyView.h"
15#import "ADPersonView.h"
16
17@implementation ADPersonPropertyView (Events)
18- (void) mouseDown: (NSEvent*) event
19{
20  int i; id c = nil; id details; ADMutableMultiValue *mv;
21  NSPoint p;
22
23  _mouseDownOnSelf = YES;
24  _mouseDownCell = nil;
25
26  p = [self convertPoint: [event locationInWindow]
27		    fromView: nil];
28
29  for(i=0; i<[_cells count]; i++)
30    {
31      c = [_cells objectAtIndex: i];
32      if(NSPointInRect(p, [c rect]))
33	{
34	  _mouseDownCell = c;
35	  break;
36	}
37    }
38  if(i == [_cells count]) return;
39
40  details = [c details];
41
42  if([c isEditable] && ![self isEditable])
43    _propertyForDrag = [[self propertyForDragWithDetails: [c details]]
44			 retain];
45  else
46    {
47      [_propertyForDrag release];
48      _propertyForDrag = nil;
49    }
50
51  if([c isKindOfClass: [ADPersonActionCell class]])
52    {
53      ADActionType type; NSString *ident, *label;
54      NSUInteger index;
55
56      type = [c actionType];
57
58      switch(type)
59	{
60	case ADAddAction:
61	  mv = [[[ADMutableMultiValue alloc]
62		  initWithMultiValue: [_person valueForProperty: _property]]
63		 autorelease];
64	  ident = [mv addValue: [self emptyValue]
65		      withLabel: [self defaultLabel]];
66	  [_person setValue: mv forProperty: _property];
67	  [[self superview] setNeedsDisplay: YES];
68	  [self layout];
69	  break;
70
71	case ADRemoveAction:
72	  ident = [details objectForKey: @"Identifier"];
73	  label = [details objectForKey: @"Label"];
74	  if(!ident || !label)
75	    {
76	      NSLog(@"Ident %@ or label %@ are nil!\n", ident, label);
77	      return;
78	    }
79	  index = [[_person valueForProperty: _property]
80		    indexForIdentifier: ident];
81	  if(index == NSNotFound)
82	    {
83	      NSLog(@"Property %@ (%@) doesn't know identifier %@\n",
84		    _property, [_person valueForProperty: _property],
85		    ident);
86	      return;
87	    }
88
89	  mv = [[[ADMutableMultiValue alloc]
90		  initWithMultiValue: [_person valueForProperty: _property]]
91		 autorelease];
92	  [mv removeValueAndLabelAtIndex: index];
93	  [_person setValue: mv forProperty: _property];
94	  [[self superview] setNeedsDisplay: YES];
95	  [self layout];
96	  break;
97
98	case ADChangeAction:
99	  ident = [details objectForKey: @"Identifier"];
100	  label = [details objectForKey: @"Label"];
101	  if(!ident || !label)
102	    {
103	      NSLog(@"Ident %@ or label %@ are nil!\n", ident, label);
104	      return;
105	    }
106	  index = [[_person valueForProperty: _property]
107		    indexForIdentifier: ident];
108	  if(index == NSNotFound)
109	    {
110	      NSLog(@"Property %@ (%@) doesn't know identifier %@\n",
111		    _property, [_person valueForProperty: _property],
112		    ident);
113	      return;
114	    }
115	  label = [self nextLabelAfter: label];
116
117	  mv = [[[ADMutableMultiValue alloc]
118		  initWithMultiValue: [_person valueForProperty: _property]]
119		 autorelease];
120	  [mv replaceLabelAtIndex: index withLabel: label];
121	  [_person setValue: mv forProperty: _property];
122	  [self layout];
123	  break;
124
125	default:
126	  NSLog(@"Unknown action type %d\n", type);
127	}
128
129      return;
130    }
131
132  if(_editable)
133    {
134      if(_delegate)
135	[_delegate viewWillBeginEditing: self];
136      [self beginEditingInCellWithDetails: details
137	    becauseOfEvent: event];
138
139      [self setNeedsDisplay: YES];
140    }
141}
142
143- (void) mouseDragged: (NSEvent*) event
144{
145  NSPasteboard *pb;
146
147  if(!_mouseDownOnSelf || !_delegate || _editable)
148    return;
149
150  pb = [NSPasteboard pasteboardWithName: NSDragPboard];
151
152  if(_propertyForDrag &&
153     [_delegate respondsToSelector: @selector(personPropertyView:willDragValue:forProperty:)] &&
154     [_delegate personPropertyView: self
155		willDragValue: _propertyForDrag
156		forProperty: _property])
157    {
158      [pb declareTypes: [NSArray arrayWithObject: NSStringPboardType]
159	  owner: self];
160      [pb setData: [_person vCardRepresentation]
161	  forType: @"NSVCardPboardType"];
162      [pb setString: _propertyForDrag forType: NSStringPboardType];
163
164      [self dragImage: [self imageForDraggedProperty: _propertyForDrag]
165	    at: NSZeroPoint
166	    offset: NSZeroSize
167	    event: event
168	    pasteboard: pb
169	    source: self
170	    slideBack: YES];
171    }
172  else if(!_propertyForDrag &&
173	  [_delegate respondsToSelector: @selector(personPropertyView:willDragPerson:)] &&
174	  [_delegate personPropertyView: self
175		     willDragPerson: _person])
176    {
177      NSString *str;
178      NSMutableDictionary *dict;
179
180      [pb declareTypes: [NSArray arrayWithObjects: @"NSVCardPboardType",
181				 @"NSFilesPromisePboardType",
182				 NSStringPboardType,
183				 ADPeoplePboardType,
184				 nil]
185	  owner: self];
186      [pb setData: [_person vCardRepresentation]
187	  forType: @"NSVCardPboardType"];
188
189      dict = [NSMutableDictionary dictionary];
190      [dict setObject: [NSString stringWithFormat: @"%d",
191				 [[NSProcessInfo processInfo]
192				   processIdentifier]]
193	    forKey: @"PID"];
194      if([_person uniqueId])
195	[dict setObject: [_person uniqueId]
196	      forKey: @"UID"];
197      if([_person addressBook])
198	[dict setObject: [[_person addressBook] addressBookDescription]
199	      forKey: @"AB"];
200      [pb setPropertyList: [NSArray arrayWithObject: dict]
201	  forType: ADPeoplePboardType];
202
203      if([[_person valueForProperty: ADEmailProperty] count])
204	str = [NSString stringWithFormat: @"%@ <%@>",
205			[_person screenNameWithFormat: ADScreenNameFirstNameFirst],
206			[[_person valueForProperty: ADEmailProperty]
207			  valueAtIndex: 0]];
208      else
209	str = [_person screenName];
210      [pb setString: str forType: NSStringPboardType];
211
212      [self dragImage: [_delegate draggingImage]
213	    at: NSZeroPoint
214	    offset: NSZeroSize
215	    event: event
216	    pasteboard: pb
217	    source: self
218	    slideBack: YES];
219    }
220
221  _mouseDownCell = nil;
222}
223
224- (void) mouseUp: (NSEvent*) event
225{
226  if(_editable)
227    return;
228
229  if(_mouseDownCell && _delegate && [_mouseDownCell isEditable] &&
230     [_delegate respondsToSelector: _clickSel])
231    [_delegate clickedOnProperty: _property
232	       withValue: [_mouseDownCell stringValue]
233	       inView: self];
234
235  [_propertyForDrag release];
236  _propertyForDrag = nil;
237
238  _mouseDownOnSelf = NO;
239  _mouseDownCell = nil;
240}
241
242- (unsigned int) draggingSourceOperationMaskForLocal: (BOOL) isLocal
243{
244  return NSDragOperationCopy|NSDragOperationLink;
245}
246
247- (void) beginEditingInCellWithDetails: (id) details
248		       becauseOfEvent: (NSEvent*) e
249{
250  ADPersonPropertyCell *c;
251  NSRect r;
252  NSText *t;
253  int i;
254
255  [[details retain] autorelease];
256  [self endEditing];
257
258  i = [self indexOfEditableCellWithDetails: details];
259
260  c =  [_cells objectAtIndex: i];
261
262  if(![c isEditable]) return;
263  _editingCellIndex = i;
264  r = [c rect];
265
266  t = [_window fieldEditor: YES forObject: c];
267  _textObject = [c setUpFieldEditorAttributes: t];
268  [_textObject setBackgroundColor: [NSColor orangeColor]];
269  [_textObject setTextColor: [NSColor blackColor]];
270  [_textObject setDrawsBackground: YES];
271  [_textObject setString: [c stringValue]];
272
273  if([[c stringValue] hasPrefix: @"["])
274    {
275      [c setStringValue: @""];
276      r.size.width = [[c font] widthOfString: @""];
277    }
278
279  r.size.width += 4; // make the cursor fit too
280
281  if(e)
282    [c editWithFrame: r
283       inView: self
284       editor: _textObject
285       delegate: self
286       event: e];
287  else
288    {
289      // HACK: We must create our own event here, since we can't
290      // pass nil as event argument to
291      // editWithFrame:inView:...
292      // REASON: In that method, the event is asked for its event
293      // type, which (for a nil event) is 0==NSLeftMouseDown. The
294      // effect is that the NSCell sits there waiting for the
295      // mouse up :-)
296      // REMEDY: Maybe fix this by checking for nil event in
297      // NSCell editWithFrame:inView:...?
298      e = [NSEvent keyEventWithType: NSKeyDown
299		   location: NSMakePoint(0, 0)
300		   modifierFlags: 0
301		   timestamp: 0
302		   windowNumber: 0
303		   context: nil
304		   characters: @"\t"
305		   charactersIgnoringModifiers: @"\t"
306		   isARepeat: NO
307		   keyCode: '\t'];
308      [c editWithFrame: r
309	 inView: self
310	 editor: _textObject
311	 delegate: self
312	 event: e];
313      [_textObject setSelectedRange: NSMakeRange(0, [[c stringValue]
314						      length])];
315    }
316
317  [c setStringValue: @""];
318
319  [self setNeedsDisplay: YES];
320}
321
322- (void) beginEditingInCellAtIndex: (NSUInteger) i
323		    becauseOfEvent: (NSEvent*) e
324{
325  id cell = [_cells objectAtIndex: i];
326  return [self beginEditingInCellWithDetails: [cell details]
327	       becauseOfEvent: e];
328}
329
330@end
331