source: trunk/Cocoa/F-Script Anywhere/Source/FSAViewAssociationController.m @ 19

Last change on this file since 19 was 19, checked in by Nicholas Riley, 18 years ago

F-Script Anywhere 1.1.6d1

File size: 11.4 KB
Line 
1//
2//  FSAViewAssociationController.m
3//  F-Script Anywhere
4//
5//  Created by Nicholas Riley on Wed Jul 17 2002.
6//  Copyright (c) 2002 Nicholas Riley. All rights reserved.
7//
8
9/*
10
11 F-Script Anywhere is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 F-Script Anywhere is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with F-Script Anywhere; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24
25*/
26
27#import "FSAViewAssociationController.h"
28#import "FSAController.h"
29#import "FSAWindowManager.h"
30#import "FSAnywhere.h"
31#import <FScript/FSInterpreter.h>
32#import <FScript/System.h>
33
34// XXX workaround for lack of identifier validation; should go away when F-Script adds (promised) direct support for this
35@interface Compiler
36+ (BOOL)isValidIndentifier:(NSString *)str;
37@end
38
39@implementation FSAViewAssociationController
40
41- (id)initWithFSAController:(FSAController *)fsa;
42{
43    self = [super initWithWindowNibName: @"FSAViewAssociationPanel"];
44
45    if (self != nil) {
46        NSImage *bullseyeImage = [[NSImage alloc] initByReferencingFile: [[NSBundle bundleForClass: [self class]] pathForResource: @"Bullseye menu cursor" ofType: @"tiff"]];
47        NSString *label = [fsa interpreterLabel];
48       
49        interpreter = [[[fsa interpreterView] interpreter] retain];
50        system = [fsa system];
51        [[self window] setResizeIncrements: NSMakeSize(1, 12)];
52        if (label != nil) [[self window] setTitle: [NSString stringWithFormat: @"%@: %@", [[self window] title], label]];
53        bullseyeCursor = [[NSCursor alloc] initWithImage: bullseyeImage hotSpot: NSMakePoint(6, 7)];
54        [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(controlTextDidChange:) name: NSControlTextDidChangeNotification object: variableNameField];
55        [[captureButton cell] setShowsStateBy: NSContentsCellMask | NSChangeGrayCellMask];
56        [captureButton setState: NSOffState];
57        [self update: nil];
58    }
59    return self;
60}
61
62- (void)dealloc;
63{
64    [viewHierarchyMenu release];
65    [selectedElement release];
66    [interpreter release];
67    [bullseyeCursor release];
68    [[NSNotificationCenter defaultCenter] removeObserver: self];
69    [super dealloc];
70}
71
72- (IBAction)update:(id)sender;
73{
74    NSString *variableName = [variableNameField stringValue];
75    BOOL canAssignToVariable = NO;
76    [browseButton setEnabled: selectedElement != nil];
77    [statusField setStringValue: @""];
78    if ([variableName length] != 0) {
79        if (![Compiler isValidIndentifier: variableName]) {
80            [statusField setStringValue: @"Invalid name: contains spaces, punctuation or non-ASCII characters"];
81        } else if (selectedElement != nil) {
82            [statusField setStringValue: @"Click ÒAssociateÓ to assign to this variable"];
83            canAssignToVariable = YES;
84        }
85    }
86    [associateButton setEnabled: canAssignToVariable];
87    [variableNameField setEnabled: [captureButton state] == NSOffState];
88}
89
90- (void)stopCapturingVoluntarily:(BOOL)voluntary;
91{
92    FSALog(@"stopping capture");
93    [[NSNotificationCenter defaultCenter] removeObserver: self name: NSMenuWillSendActionNotification object: nil];
94    [captureButton setState: NSOffState];
95    [self update: nil];
96    if (voluntary) {
97        FSALog(@"voluntary!");
98        [[self window] makeKeyAndOrderFront: self];
99        [bullseyeCursor pop];
100        [variableNameField becomeFirstResponder];       
101    }
102}
103
104- (void)_addElement:(id)element withLabel:(NSString *)label toSubmenuForItem:(NSMenuItem *)item;
105{
106    NSMenu *submenu = [item submenu];
107    NSMenuItem *subItem;
108    if (submenu == nil) {
109        id superElement = [item representedObject];
110        submenu = [[NSMenu alloc] initWithTitle: @""];
111        subItem = [submenu addItemWithTitle: NSStringFromClass([superElement class])
112                                     action: @selector(elementSelected:)
113                              keyEquivalent: @""];
114        [subItem setTarget: self];
115        [subItem setRepresentedObject: superElement];
116        [item setSubmenu: submenu];
117        [submenu release];
118    }
119    [submenu addItem: [NSMenuItem separatorItem]];
120    [submenu addItemWithTitle: label action: nil keyEquivalent: @""];
121    subItem = [submenu addItemWithTitle: [@"  "
122                stringByAppendingString: NSStringFromClass([element class])]
123                                           action: @selector(elementSelected:)
124                                    keyEquivalent: @""];
125    [subItem setTarget: self];
126    [subItem setRepresentedObject: element];
127}
128
129- (void)_addValueForSelector:(SEL)sel withLabel:(NSString *)label toSubmenuForItem:(NSMenuItem *)item;
130{
131    id obj = [item representedObject];
132    if ([obj respondsToSelector: sel]) {
133        id value = [obj performSelector: sel];
134        if (value == nil) return;
135        [self _addElement: value withLabel: label toSubmenuForItem: item];
136    }
137}
138
139- (void)_addElementToMenu:(id)element;
140{
141    NSMenuItem *item;
142    if (element == nil) return;
143    item = [viewHierarchyMenu addItemWithTitle: [@"  "
144                stringByAppendingString: NSStringFromClass([element class])]
145                                        action: @selector(elementSelected:)
146                                 keyEquivalent: @""];
147    [item setTarget: self];
148    [item setRepresentedObject: element];
149    [self _addValueForSelector: @selector(windowController) withLabel: @"Window Controller" toSubmenuForItem: item];
150    [self _addValueForSelector: @selector(delegate) withLabel: @"Delegate" toSubmenuForItem: item];
151    [self _addValueForSelector: @selector(dataSource) withLabel: @"Data Source" toSubmenuForItem: item];
152    [self _addValueForSelector: @selector(target) withLabel: @"Target" toSubmenuForItem: item];
153    [self _addValueForSelector: @selector(cell) withLabel: @"Cell" toSubmenuForItem: item];
154}
155
156- (void)captureOneView;
157{
158    NSEvent *event;
159    NSView *view, *superView = nil, *contentView;
160    NSWindow *eventWindow;
161    static unsigned captureCount = 0;
162    unsigned capture = captureCount++;
163   
164    FSALog(@"%4u>capturing one", capture);
165    [captureButton setState: NSOnState];
166    [bullseyeCursor push];
167
168captureElement:
169    [bullseyeCursor set];
170    FSALog(@"%4u waiting for event...", capture);
171    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(menuWillSendAction:) name: NSMenuWillSendActionNotification object: nil];
172    event = [NSApp nextEventMatchingMask: NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask | NSKeyUpMask | NSAppKitDefinedMask
173                               untilDate: [NSDate distantFuture]
174                                  inMode: NSEventTrackingRunLoopMode
175                                 dequeue: YES];
176    FSALog(@"%4u got %@", capture, event);
177    [[NSNotificationCenter defaultCenter] removeObserver: self name: NSMenuWillSendActionNotification object: nil];
178    if ([event type] == NSAppKitDefined) {
179        if ([event subtype] == NSApplicationDeactivatedEventType) {
180            [NSApp discardEventsMatchingMask: NSAnyEventMask beforeEvent: event];
181            [self stopCapturingVoluntarily: NO];
182            [NSApp sendEvent: event];
183            return;
184        }
185        goto captureElement;
186    }
187    if ([event type] == NSKeyUp) {
188        [NSApp discardEventsMatchingMask: NSAnyEventMask & ~NSKeyUpMask beforeEvent: event];
189        FSALog(@"%4u<stop capture [key up]", capture);
190        [self stopCapturingVoluntarily: YES];
191        return;
192    }
193    [viewHierarchyMenu release]; viewHierarchyMenu = nil;
194    viewHierarchyMenu = [[NSMenu alloc] initWithTitle: @""];
195    NS_DURING
196        eventWindow = [event window];
197        contentView = [eventWindow contentView];
198        view = [[contentView superview] hitTest: [event locationInWindow]];
199        if (view == captureButton) {
200            [NSApp discardEventsMatchingMask: NSAnyEventMask & ~NSKeyUpMask beforeEvent: event];
201            FSALog(@"%4u<stop capture [capture button]", capture);
202            [self stopCapturingVoluntarily: YES];
203            NS_VOIDRETURN;
204        }
205        if (view == nil) {
206            [self captureOneView];
207            NS_VOIDRETURN;
208        }
209        [viewHierarchyMenu addItemWithTitle: @"View" action: nil keyEquivalent: @""];
210        [self _addElementToMenu: view];
211        superView = view;
212        do {
213            superView = [superView superview];
214            if (superView == nil) break;
215            [self _addElementToMenu: superView];
216        } while (superView != contentView);
217        [viewHierarchyMenu addItem: [NSMenuItem separatorItem]];
218        [viewHierarchyMenu addItemWithTitle: @"Window" action: nil keyEquivalent: @""];
219        [self _addElementToMenu: eventWindow];
220    NS_HANDLER
221        [descriptionField setStringValue:
222            [NSString stringWithFormat: @"Çan exception occurred: %@È", localException]];
223    NS_ENDHANDLER
224    [NSMenu popUpContextMenu: viewHierarchyMenu withEvent: event forView: view];
225    if ([captureButton state] == NSOnState) goto captureElement;
226    FSALog(@"%4u<stop capture [fell through to end]", capture);
227}
228
229- (IBAction)captureView:(id)sender
230{
231    [statusField setStringValue: @"Click inside one of this applicationÕs windows to select."];
232    [selectedElement release]; selectedElement = nil;
233    [self update: nil];
234    [self captureOneView];
235}
236
237- (void)setSelectedElement:(id)element;
238{
239    FSALog(@"element selected: %@", element);
240    NS_DURING
241        [descriptionField setStringValue: [element description]];
242        [selectedElement release];
243        selectedElement = [element retain];
244        [[self window] orderFront: self];
245    NS_HANDLER
246        [descriptionField setStringValue:
247            [NSString stringWithFormat: @"Çan exception occurred: %@È", localException]];
248    NS_ENDHANDLER
249    [viewHierarchyMenu release]; viewHierarchyMenu = nil;
250}
251
252- (void)elementSelected:(NSMenuItem *)sender;
253{
254    [self setSelectedElement: [sender representedObject]];
255    [self captureOneView];
256}
257
258- (void)menuWillSendAction:(NSNotification *)notification;
259{
260    NSMenuItem *item = [[notification userInfo] objectForKey: @"MenuItem"];
261    [self setSelectedElement: item];
262    [NSApp discardEventsMatchingMask: NSAnyEventMask beforeEvent: [NSApp currentEvent]];
263    // we're already capturing, don't do it again
264}
265
266- (void)controlTextDidChange:(NSNotification *)notification;
267{
268    [self update: nil];
269}
270
271- (IBAction)defineVariable:(id)sender;
272{
273#warning this should change when F-Script supports a public API for identifier validation
274    NS_DURING
275        NSString *variableName = [variableNameField stringValue];
276        [statusField setStringValue: @"AssociatingÉ"];
277        [interpreter setObject: selectedElement forIdentifier: variableName];
278        [statusField setStringValue: [NSString stringWithFormat: @"Assigned variable Ò%@Ó", variableName]];
279    NS_HANDLER
280        [statusField setStringValue: [NSString stringWithFormat: @"Assocation failed: %@", localException]];
281    NS_ENDHANDLER
282}
283
284- (IBAction)viewInObjectBrowser:(id)sender;
285{
286    FSALog(@"system: %@", system);
287    [system browse: selectedElement];
288    [statusField setStringValue: @"Opened object browser"];
289}
290
291@end
Note: See TracBrowser for help on using the repository browser.