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

Last change on this file since 153 was 153, checked in by Nicholas Riley, 16 years ago

Integrates SCPatch and mach_inject; unfinished, buggy.

File size: 11.1 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@implementation FSAViewAssociationController
35
36- (id)initWithFSAController:(FSAController *)fsa;
37{
38    self = [super initWithWindowNibName: @"FSAViewAssociationPanel"];
39
40    if (self != nil) {
41        NSImage *bullseyeImage = [[NSImage alloc] initByReferencingFile: [[NSBundle bundleForClass: [self class]] pathForResource: @"Bullseye menu cursor" ofType: @"tiff"]];
42        NSString *label = [fsa interpreterLabel];
43       
44        interpreter = [[[fsa interpreterView] interpreter] retain];
45        system = [fsa system];
46        [[self window] setResizeIncrements: NSMakeSize(1, 12)];
47        if (label != nil) [[self window] setTitle: [NSString stringWithFormat: @"%@: %@", [[self window] title], label]];
48        bullseyeCursor = [[NSCursor alloc] initWithImage: bullseyeImage hotSpot: NSMakePoint(6, 7)];
49        [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(controlTextDidChange:) name: NSControlTextDidChangeNotification object: variableNameField];
50        [[captureButton cell] setShowsStateBy: NSContentsCellMask | NSChangeGrayCellMask];
51        [captureButton setState: NSOffState];
52        [self update: nil];
53    }
54    return self;
55}
56
57- (void)dealloc;
58{
59    [viewHierarchyMenu release];
60    [selectedElement release];
61    [interpreter release];
62    [bullseyeCursor release];
63    [[NSNotificationCenter defaultCenter] removeObserver: self];
64    [super dealloc];
65}
66
67- (IBAction)update:(id)sender;
68{
69    NSString *variableName = [variableNameField stringValue];
70    BOOL canAssignToVariable = NO;
71    [browseButton setEnabled: selectedElement != nil];
72    [statusField setStringValue: @""];
73    if ([variableName length] != 0) {
74        if (![FSInterpreter validateSyntaxForIdentifier: variableName]) {
75            [statusField setStringValue: @"Invalid name: contains spaces, punctuation or non-ASCII characters"];
76        } else if (selectedElement != nil) {
77            [statusField setStringValue: @"Click ÒAssociateÓ to assign to this variable"];
78            canAssignToVariable = YES;
79        }
80    }
81    [associateButton setEnabled: canAssignToVariable];
82    [variableNameField setEnabled: [captureButton state] == NSOffState];
83}
84
85- (void)stopCapturingVoluntarily:(BOOL)voluntary;
86{
87    FSALog(@"stopping capture");
88    [[NSNotificationCenter defaultCenter] removeObserver: self name: NSMenuWillSendActionNotification object: nil];
89    [captureButton setState: NSOffState];
90    [self update: nil];
91    if (voluntary) {
92        FSALog(@"voluntary!");
93        [[self window] makeKeyAndOrderFront: self];
94        [bullseyeCursor pop];
95        [variableNameField becomeFirstResponder];       
96    }
97}
98
99- (void)_addElement:(id)element withLabel:(NSString *)label toSubmenuForItem:(id<NSMenuItem>)item;
100{
101    NSMenu *submenu = [item submenu];
102    id<NSMenuItem> subItem;
103    if (submenu == nil) {
104        id superElement = [item representedObject];
105        submenu = [[NSMenu alloc] initWithTitle: @""];
106        subItem = [submenu addItemWithTitle: NSStringFromClass([superElement class])
107                                     action: @selector(elementSelected:)
108                              keyEquivalent: @""];
109        [subItem setTarget: self];
110        [subItem setRepresentedObject: superElement];
111        [item setSubmenu: submenu];
112        [submenu release];
113    }
114    [submenu addItem: [NSMenuItem separatorItem]];
115    [submenu addItemWithTitle: label action: nil keyEquivalent: @""];
116    subItem = [submenu addItemWithTitle: [@"  "
117                stringByAppendingString: NSStringFromClass([element class])]
118                                           action: @selector(elementSelected:)
119                                    keyEquivalent: @""];
120    [subItem setTarget: self];
121    [subItem setRepresentedObject: element];
122}
123
124- (void)_addValueForSelector:(SEL)sel withLabel:(NSString *)label toSubmenuForItem:(id<NSMenuItem>)item;
125{
126    id obj = [item representedObject];
127    if ([obj respondsToSelector: sel]) {
128        id value = [obj performSelector: sel];
129        if (value == nil) return;
130        [self _addElement: value withLabel: label toSubmenuForItem: item];
131    }
132}
133
134- (void)_addElementToMenu:(id)element;
135{
136    id<NSMenuItem> item;
137    if (element == nil) return;
138    item = [viewHierarchyMenu addItemWithTitle: [@"  "
139                stringByAppendingString: NSStringFromClass([element class])]
140                                        action: @selector(elementSelected:)
141                                 keyEquivalent: @""];
142    [item setTarget: self];
143    [item setRepresentedObject: element];
144    [self _addValueForSelector: @selector(windowController) withLabel: @"Window Controller" toSubmenuForItem: item];
145    [self _addValueForSelector: @selector(delegate) withLabel: @"Delegate" toSubmenuForItem: item];
146    [self _addValueForSelector: @selector(dataSource) withLabel: @"Data Source" toSubmenuForItem: item];
147    [self _addValueForSelector: @selector(target) withLabel: @"Target" toSubmenuForItem: item];
148    [self _addValueForSelector: @selector(cell) withLabel: @"Cell" toSubmenuForItem: item];
149}
150
151- (void)captureOneView;
152{
153    NSEvent *event;
154    NSView *view, *superView = nil, *contentView;
155    NSWindow *eventWindow;
156    static unsigned captureCount = 0;
157    unsigned capture = captureCount++;
158   
159    FSALog(@"%4u>capturing one", capture);
160    [captureButton setState: NSOnState];
161    [bullseyeCursor push];
162
163captureElement:
164    [bullseyeCursor set];
165    FSALog(@"%4u waiting for event...", capture);
166    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(menuWillSendAction:) name: NSMenuWillSendActionNotification object: nil];
167    event = [NSApp nextEventMatchingMask: NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask | NSKeyUpMask | NSAppKitDefinedMask
168                               untilDate: [NSDate distantFuture]
169                                  inMode: NSEventTrackingRunLoopMode
170                                 dequeue: YES];
171    FSALog(@"%4u got %@", capture, event);
172    [[NSNotificationCenter defaultCenter] removeObserver: self name: NSMenuWillSendActionNotification object: nil];
173    if ([event type] == NSAppKitDefined) {
174        if ([event subtype] == NSApplicationDeactivatedEventType) {
175            [NSApp discardEventsMatchingMask: NSAnyEventMask beforeEvent: event];
176            [self stopCapturingVoluntarily: NO];
177            [NSApp sendEvent: event];
178            return;
179        }
180        goto captureElement;
181    }
182    if ([event type] == NSKeyUp) {
183        [NSApp discardEventsMatchingMask: NSAnyEventMask & ~NSKeyUpMask beforeEvent: event];
184        FSALog(@"%4u<stop capture [key up]", capture);
185        [self stopCapturingVoluntarily: YES];
186        return;
187    }
188    [viewHierarchyMenu release]; viewHierarchyMenu = nil;
189    viewHierarchyMenu = [[NSMenu alloc] initWithTitle: @""];
190    NS_DURING
191        eventWindow = [event window];
192        contentView = [eventWindow contentView];
193        view = [[contentView superview] hitTest: [event locationInWindow]];
194        if (view == captureButton) {
195            [NSApp discardEventsMatchingMask: NSAnyEventMask & ~NSKeyUpMask beforeEvent: event];
196            FSALog(@"%4u<stop capture [capture button]", capture);
197            [self stopCapturingVoluntarily: YES];
198            NS_VOIDRETURN;
199        }
200        if (view == nil) {
201            [self captureOneView];
202            NS_VOIDRETURN;
203        }
204        [viewHierarchyMenu addItemWithTitle: @"View" action: nil keyEquivalent: @""];
205        [self _addElementToMenu: view];
206        superView = view;
207        do {
208            superView = [superView superview];
209            if (superView == nil) break;
210            [self _addElementToMenu: superView];
211        } while (superView != contentView);
212        [viewHierarchyMenu addItem: [NSMenuItem separatorItem]];
213        [viewHierarchyMenu addItemWithTitle: @"Window" action: nil keyEquivalent: @""];
214        [self _addElementToMenu: eventWindow];
215    NS_HANDLER
216        [descriptionField setStringValue:
217            [NSString stringWithFormat: @"Çan exception occurred: %@È", localException]];
218    NS_ENDHANDLER
219    [NSMenu popUpContextMenu: viewHierarchyMenu withEvent: event forView: view];
220    if ([captureButton state] == NSOnState) goto captureElement;
221    FSALog(@"%4u<stop capture [fell through to end]", capture);
222}
223
224- (IBAction)captureView:(id)sender
225{
226    [statusField setStringValue: @"Click inside one of this applicationÕs windows to select."];
227    [selectedElement release]; selectedElement = nil;
228    [self update: nil];
229    [self captureOneView];
230}
231
232- (void)setSelectedElement:(id)element;
233{
234    FSALog(@"element selected: %@", element);
235    NS_DURING
236        [descriptionField setStringValue: [element description]];
237        [selectedElement release];
238        selectedElement = [element retain];
239        [[self window] orderFront: self];
240    NS_HANDLER
241        [descriptionField setStringValue:
242            [NSString stringWithFormat: @"Çan exception occurred: %@È", localException]];
243    NS_ENDHANDLER
244    [viewHierarchyMenu release]; viewHierarchyMenu = nil;
245}
246
247- (void)elementSelected:(NSMenuItem *)sender;
248{
249    [self setSelectedElement: [sender representedObject]];
250    [self captureOneView];
251}
252
253- (void)menuWillSendAction:(NSNotification *)notification;
254{
255    NSMenuItem *item = [[notification userInfo] objectForKey: @"MenuItem"];
256    [self setSelectedElement: item];
257    [NSApp discardEventsMatchingMask: NSAnyEventMask beforeEvent: [NSApp currentEvent]];
258    // we're already capturing, don't do it again
259}
260
261- (void)controlTextDidChange:(NSNotification *)notification;
262{
263    [self update: nil];
264}
265
266- (IBAction)defineVariable:(id)sender;
267{
268    NS_DURING
269        NSString *variableName = [variableNameField stringValue];
270        [statusField setStringValue: @"AssociatingÉ"];
271        [interpreter setObject: selectedElement forIdentifier: variableName];
272        [statusField setStringValue: [NSString stringWithFormat: @"Assigned variable Ò%@Ó", variableName]];
273    NS_HANDLER
274        [statusField setStringValue: [NSString stringWithFormat: @"Assocation failed: %@", localException]];
275    NS_ENDHANDLER
276}
277
278- (IBAction)viewInObjectBrowser:(id)sender;
279{
280    FSALog(@"system: %@", system);
281    [system browse: selectedElement];
282    [statusField setStringValue: @"Opened object browser"];
283}
284
285@end
Note: See TracBrowser for help on using the repository browser.