Center the version check window (when it pops up) and the main window
[macgdbp.git] / Source / DebuggerWindowController.m
1 /*
2 * MacGDBp
3 * Copyright (c) 2007 - 2008, Blue Static <http://www.bluestatic.org>
4 *
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
10 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17 #import "DebuggerWindowController.h"
18 #import "DebuggerConnection.h"
19 #import "NSXMLElementAdditions.h"
20 #import "AppDelegate.h"
21 #import "BreakpointManager.h"
22
23 @interface DebuggerWindowController (Private)
24 - (void)updateSourceViewer;
25 @end
26
27 @implementation DebuggerWindowController
28
29 @synthesize connection, sourceViewer;
30
31 /**
32 * Initializes the window controller and sets the connection
33 */
34 - (id)initWithPort:(int)aPort session:(NSString *)aSession
35 {
36 if (self = [super initWithWindowNibName:@"Debugger"])
37 {
38 connection = [[DebuggerConnection alloc] initWithWindowController:self port:aPort session:aSession];
39 expandedRegisters = [[NSMutableSet alloc] init];
40 [[self window] makeKeyAndOrderFront:nil];
41 }
42 return self;
43 }
44
45 /**
46 * Before the display get's comfortable, set up the NSTextView to scroll horizontally
47 */
48 - (void)awakeFromNib
49 {
50 [self setStatus:@"Connecting"];
51 [[self window] setExcludedFromWindowsMenu:YES];
52 [[self window] center];
53 [sourceViewer setDelegate:self];
54 }
55
56 /**
57 * Called right before the window closes so that we can tell the socket to close down
58 */
59 - (void)windowWillClose:(NSNotification *)notif
60 {
61 [[connection socket] close];
62 }
63
64 /**
65 * Resets all the displays to be empty
66 */
67 - (void)resetDisplays
68 {
69 [registerController setContent:nil];
70 [stackController setContent:nil];
71 [[sourceViewer textView] setString:@""];
72 }
73
74 /**
75 * Sets the status and clears any error message
76 */
77 - (void)setStatus:(NSString *)aStatus
78 {
79 [errormsg setHidden:YES];
80 [statusmsg setStringValue:aStatus];
81 [[self window] setTitle:[NSString stringWithFormat:@"GDBp @ %@:%d/%@", [connection remoteHost], [connection port], [connection session]]];
82
83 [stepInButton setEnabled:NO];
84 [stepOutButton setEnabled:NO];
85 [stepOverButton setEnabled:NO];
86 [runButton setEnabled:NO];
87 [reconnectButton setEnabled:NO];
88
89 if ([connection isConnected])
90 {
91 if ([aStatus isEqualToString:@"Starting"])
92 {
93 [stepInButton setEnabled:YES];
94 [runButton setEnabled:YES];
95 }
96 }
97 else
98 {
99 [reconnectButton setEnabled:YES];
100 }
101 }
102
103 /**
104 * Sets the status to be "Error" and then displays the error message
105 */
106 - (void)setError:(NSString *)anError
107 {
108 [errormsg setStringValue:anError];
109 [self setStatus:@"Error"];
110 [errormsg setHidden:NO];
111 }
112
113 /**
114 * Sets the root node element of the stacktrace
115 */
116 - (void)setStack:(NSArray *)node
117 {
118 stack = node;
119
120 if ([stack count] > 1)
121 {
122 [stepOutButton setEnabled:YES];
123 }
124 [stepInButton setEnabled:YES];
125 [stepOverButton setEnabled:YES];
126 [runButton setEnabled:YES];
127
128 [self updateSourceViewer];
129 }
130
131 /**
132 * Sets the stack root element so that the NSOutlineView can display it
133 */
134 - (void)setRegister:(NSXMLDocument *)elm
135 {
136 // XXX: Doing anything short of this will cause bindings to crash spectacularly for no reason whatsoever, and
137 // in seemingly arbitrary places. The class that crashes is _NSKeyValueObservationInfoCreateByRemoving.
138 // http://boredzo.org/blog/archives/2006-01-29/have-you-seen-this-crash says that this means nothing is
139 // being observed, but I doubt that he was using an NSOutlineView which seems to be one f!cking piece of
140 // sh!t when used with NSTreeController. http://www.cocoadev.com/index.pl?NSTreeControllerBugOrDeveloperError
141 // was the inspiration for this fix (below) but the author says that inserting does not work too well, but
142 // that's okay for us as we just need to replace the entire thing.
143 [registerController setContent:nil];
144 [registerController setContent:[[elm rootElement] children]];
145
146 for (int i = 0; i < [registerView numberOfRows]; i++)
147 {
148 NSTreeNode *node = [registerView itemAtRow:i];
149 if ([expandedRegisters containsObject:[[node representedObject] fullname]])
150 {
151 [registerView expandItem:node];
152 }
153 }
154 }
155
156 /**
157 * Forwards the message to run script execution to the connection
158 */
159 - (IBAction)run:(id)sender
160 {
161 [connection run];
162 }
163
164 /**
165 * Tells the connection to ask the server to reconnect
166 */
167 - (IBAction)reconnect:(id)sender
168 {
169 [connection reconnect];
170 }
171
172 /**
173 * Forwards the message to "step in" to the connection
174 */
175 - (IBAction)stepIn:(id)sender
176 {
177 [connection stepIn];
178 }
179
180 /**
181 * Forwards the message to "step out" to the connection
182 */
183 - (IBAction)stepOut:(id)sender
184 {
185 [connection stepOut];
186 }
187
188 /**
189 * Forwards the message to "step over" to the connection
190 */
191 - (IBAction)stepOver:(id)sender
192 {
193 [connection stepOver];
194 }
195
196 /**
197 * NSTableView delegate method that informs the controller that the stack selection did change and that
198 * we should update the source viewer
199 */
200 - (void)tableViewSelectionDidChange:(NSNotification *)notif
201 {
202 [self updateSourceViewer];
203 }
204
205 /**
206 * Does the actual updating of the source viewer by reading in the file
207 */
208 - (void)updateSourceViewer
209 {
210 id selectedLevel = [[stackController selection] valueForKey:@"level"];
211 if (selectedLevel == NSNoSelectionMarker)
212 {
213 [[sourceViewer textView] setString:@""];
214 return;
215 }
216 int selection = [selectedLevel intValue];
217
218 if ([stack count] < 1)
219 {
220 NSLog(@"huh... we don't have a stack");
221 return;
222 }
223
224 // get the filename and then set the text
225 NSString *filename = [[stack objectAtIndex:selection] valueForKey:@"filename"];
226 filename = [[NSURL URLWithString:filename] path];
227 if ([filename isEqualToString:@""])
228 {
229 return;
230 }
231
232 [sourceViewer setFile:filename];
233
234 int line = [[[stack objectAtIndex:selection] valueForKey:@"lineno"] intValue];
235 [sourceViewer setMarkedLine:line];
236 [sourceViewer scrollToLine:line];
237
238 // make sure the font stays Monaco
239 //[sourceViewer setFont:[NSFont fontWithName:@"Monaco" size:10.0]];
240 }
241
242 /**
243 * Called whenver an item is expanded. This allows us to determine if we need to fetch deeper
244 */
245 - (void)outlineViewItemDidExpand:(NSNotification *)notif
246 {
247 NSTreeNode *node = [[notif userInfo] objectForKey:@"NSObject"];
248 [expandedRegisters addObject:[[node representedObject] fullname]];
249 }
250
251 /**
252 * Called when an item was collapsed. This allows us to remove it from the list of expanded items
253 */
254 - (void)outlineViewItemDidCollapse:(NSNotification *)notif
255 {
256 [expandedRegisters removeObject:[[[[notif userInfo] objectForKey:@"NSObject"] representedObject] fullname]];
257 }
258
259 #pragma mark BSSourceView Delegate
260
261 /**
262 * The gutter was clicked, which indicates that a breakpoint needs to be changed
263 */
264 - (void)gutterClickedAtLine:(int)line forFile:(NSString *)file
265 {
266 BreakpointManager *mngr = [BreakpointManager sharedManager];
267
268 if ([mngr hasBreakpointAt:line inFile:file])
269 {
270 [mngr removeBreakpointAt:line inFile:file];
271 }
272 else
273 {
274 Breakpoint *bp = [[Breakpoint alloc] initWithLine:line inFile:file];
275 [mngr addBreakpoint:bp];
276 }
277
278 [[sourceViewer numberView] setMarkers:[NSSet setWithArray:[mngr breakpointsForFile:file]]];
279 [[sourceViewer numberView] setNeedsDisplay:YES];
280 }
281
282 @end