Repository navigation
Expand file tree
/
Copy pathWindowController.m
More file actions
329 lines (292 loc) · 12.5 KB
/
Copy pathWindowController.m
File metadata and controls
329 lines (292 loc) · 12.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
// WindowController.m
// This file implements the WindowController class, managing the browser UI and interactions.
#import "WindowController.h"
#import "ContentView.h"
#import "NetworkFetcher.h"
#import "CredentialStore.h"
#import "CookieManager.h"
#import "BookmarkManager.h"
@implementation WindowController
// Initializes the WindowController with a window, setting up the UI.
- (id)initWithWindow:(NSWindow *)aWindow {
self = [super init];
if (self) {
window = aWindow;
// Create toolbar (10px height for minimal footprint).
NSView *toolbar = [[[NSView alloc] initWithFrame:NSMakeRect(0, 560, 800, 30)] autorelease];
[[window contentView] addSubview:toolbar];
// Back button: Small, iconic to save space.
backButton = [[[NSButton alloc] initWithFrame:NSMakeRect(5, 5, 25, 20)] autorelease];
[backButton setTitle:@"<"];
[backButton setTarget:self];
[backButton setAction:@selector(goBack:)];
[backButton setEnabled:NO];
[toolbar addSubview:backButton];
// Forward button.
forwardButton = [[[NSButton alloc] initWithFrame:NSMakeRect(35, 5, 25, 20)] autorelease];
[forwardButton setTitle:@">"];
[forwardButton setTarget:self];
[forwardButton setAction:@selector(goForward:)];
[forwardButton setEnabled:NO];
[toolbar addSubview:forwardButton];
// Refresh button.
refreshButton = [[[NSButton alloc] initWithFrame:NSMakeRect(65, 5, 25, 20)] autorelease];
[refreshButton setTitle:@"R"];
[refreshButton setTarget:self];
[refreshButton setAction:@selector(refresh:)];
[toolbar addSubview:refreshButton];
// Stop button.
stopButton = [[[NSButton alloc] initWithFrame:NSMakeRect(95, 5, 25, 20)] autorelease];
[stopButton setTitle:@"X"];
[stopButton setTarget:self];
[stopButton setAction:@selector(stop:)];
[stopButton setEnabled:NO];
[toolbar addSubview:stopButton];
// Home button.
homeButton = [[[NSButton alloc] initWithFrame:NSMakeRect(125, 5, 25, 20)] autorelease];
[homeButton setTitle:@"H"];
[homeButton setTarget:self];
[homeButton setAction:@selector(goHome:)];
[toolbar addSubview:homeButton];
// Address field: Wide for URL entry.
addressField = [[[NSTextField alloc] initWithFrame:NSMakeRect(155, 5, 500, 20)] autorelease];
[addressField setStringValue:@"https://"];
[toolbar addSubview:addressField];
// Go button.
goButton = [[[NSButton alloc] initWithFrame:NSMakeRect(660, 5, 25, 20)] autorelease];
[goButton setTitle:@"Go"];
[goButton setTarget:self];
[goButton setAction:@selector(loadURL:)];
[toolbar addSubview:goButton];
// Bookmarks button: Pop-up menu.
bookmarksButton = [[[NSPopUpButton alloc] initWithFrame:NSMakeRect(690, 5, 50, 20) pullsDown:YES] autorelease];
[bookmarksButton setTarget:self];
[bookmarksButton setAction:@selector(selectBookmark:)];
[toolbar addSubview:bookmarksButton];
// Add Credential button.
addCredentialButton = [[[NSButton alloc] initWithFrame:NSMakeRect(745, 5, 25, 20)] autorelease];
[addCredentialButton setTitle:@"C"];
[addCredentialButton setTarget:self];
[addCredentialButton setAction:@selector(addCredential:)];
[toolbar addSubview:addCredentialButton];
// Scroll view for content.
scrollView = [[[NSScrollView alloc] initWithFrame:NSMakeRect(0, 20, 800, 540)] autorelease];
[scrollView setHasVerticalScroller:YES];
[scrollView setHasHorizontalScroller:YES];
[scrollView setAutohidesScrollers:YES];
[[window contentView] addSubview:scrollView];
// Content view for HTML rendering.
contentView = [[[ContentView alloc] initWithFrame:NSMakeRect(0, 0, 800, 540)] autorelease];
[scrollView setDocumentView:contentView];
// Status bar: Displays progress and errors.
statusField = [[[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 800, 20)] autorelease];
[statusField setEditable:NO];
[statusField setStringValue:@"Ready"];
[[window contentView] addSubview:statusField];
// Initialize fetcher for HTML.
fetcher = [[NetworkFetcher alloc] initWithDelegate:self];
[fetcher setIsImageFetch:NO];
// Initialize image fetcher.
NetworkFetcher *imageFetcher = [[NetworkFetcher alloc] initWithDelegate:contentView];
[imageFetcher setIsImageFetch:YES];
[(ContentView *)contentView setImageFetcher:imageFetcher];
[imageFetcher release];
// Initialize credential store.
credentialStore = [[CredentialStore alloc] initWithFilePath:[@"~/data/credentials.dat" stringByExpandingTildeInPath]];
if (![[NSFileManager defaultManager] fileExistsAtPath:[credentialStore valueForKey:@"filePath"]]) {
masterPassword = [self promptForMasterPassword:@"Set Master Password"];
if (masterPassword) [credentialStore setupWithMasterPassword:masterPassword];
}
// Initialize cookie manager.
cookieManager = [[CookieManager alloc] initWithFilePath:[@"~/data/cookies.dat" stringByExpandingTildeInPath]];
[fetcher setCookieManager:cookieManager];
// Initialize bookmark manager.
bookmarkManager = [[BookmarkManager alloc] initWithFilePath:[@"~/data/bookmarks.dat" stringByExpandingTildeInPath]];
[self updateBookmarksMenu];
// Initialize history.
history = [[NSMutableArray alloc] init];
historyIndex = -1;
isLoading = NO;
}
return self;
}
// Deallocates memory.
- (void)dealloc {
[fetcher release];
[history release];
[credentialStore release];
[cookieManager release];
[bookmarkManager release];
[masterPassword release];
[super dealloc];
}
// Prompts for master password.
- (NSString *)promptForMasterPassword:(NSString *)title {
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
[alert setMessageText:title];
[alert addButtonWithTitle:@"OK"];
[alert addButtonWithTitle:@"Cancel"];
NSTextField *input = [[[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)] autorelease];
[input setSecureTextEntry:YES];
[alert setAccessoryView:input];
if ([alert runModal] == NSAlertFirstButtonReturn) {
return [[input stringValue] copy];
}
return nil;
}
// Loads the URL from the address field.
- (void)loadURL:(id)sender {
NSString *urlString = [addressField stringValue];
if (historyIndex < [history count] - 1) {
[history removeObjectsInRange:NSMakeRange(historyIndex + 1, [history count] - historyIndex - 1)];
}
[history addObject:urlString];
historyIndex++;
isLoading = YES;
[stopButton setEnabled:YES];
[self updateStatus:@"Loading..."];
[fetcher fetchURL:urlString];
[backButton setEnabled:(historyIndex > 0)];
[forwardButton setEnabled:(historyIndex < [history count] - 1)];
}
// Navigates back in history.
- (void)goBack:(id)sender {
if (historyIndex > 0) {
historyIndex--;
NSString *urlString = [history objectAtIndex:historyIndex];
[addressField setStringValue:urlString];
isLoading = YES;
[stopButton setEnabled:YES];
[self updateStatus:@"Loading..."];
[fetcher fetchURL:urlString];
[backButton setEnabled:(historyIndex > 0)];
[forwardButton setEnabled:(historyIndex < [history count] - 1)];
}
}
// Navigates forward in history.
- (void)goForward:(id)sender {
if (historyIndex < [history count] - 1) {
historyIndex++;
NSString *urlString = [history objectAtIndex:historyIndex];
[addressField setStringValue:urlString];
isLoading = YES;
[stopButton setEnabled:YES];
[self updateStatus:@"Loading..."];
[fetcher fetchURL:urlString];
[backButton setEnabled:(historyIndex > 0)];
[forwardButton setEnabled:(historyIndex < [history count] - 1)];
}
}
// Reloads the current page.
- (void)refresh:(id)sender {
if (historyIndex >= 0 && historyIndex < [history count]) {
NSString *urlString = [history objectAtIndex:historyIndex];
isLoading = YES;
[stopButton setEnabled:YES];
[self updateStatus:@"Loading..."];
[fetcher fetchURL:urlString];
}
}
// Stops page loading.
- (void)stop:(id)sender {
if (isLoading) {
[fetcher cancelFetch]; // Assumes a cancel method (added later).
isLoading = NO;
[stopButton setEnabled:NO];
[self updateStatus:@"Stopped"];
}
}
// Loads the home page.
- (void)goHome:(id)sender {
NSString *homeURL = @"https://www.example.com";
[addressField setStringValue:homeURL];
[self loadURL:nil];
}
// Handles bookmark selection.
- (void)selectBookmark:(id)sender {
NSPopUpButton *popup = (NSPopUpButton *)sender;
NSString *title = [[popup selectedItem] title];
if ([title isEqualToString:@"Bookmarks"]) return;
if ([title isEqualToString:@"Add Bookmark"]) {
NSString *currentURL = [addressField stringValue];
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
[alert setMessageText:@"Add Bookmark"];
[alert addButtonWithTitle:@"OK"];
[alert addButtonWithTitle:@"Cancel"];
NSTextField *titleField = [[[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)] autorelease];
[titleField setStringValue:currentURL];
[alert setAccessoryView:titleField];
if ([alert runModal] == NSAlertFirstButtonReturn) {
[bookmarkManager addBookmarkWithTitle:[titleField stringValue] url:currentURL];
[self updateBookmarksMenu];
}
} else {
NSArray *bookmarks = [bookmarkManager allBookmarks];
for (NSDictionary *bookmark in bookmarks) {
if ([[bookmark objectForKey:@"title"] isEqualToString:title]) {
[addressField setStringValue:[bookmark objectForKey:@"url"]];
[self loadURL:nil];
break;
}
}
}
}
// Prompts to add a credential.
- (void)addCredential:(id)sender {
if (!masterPassword) {
masterPassword = [self promptForMasterPassword:@"Enter Master Password"];
if (!masterPassword) return;
}
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
[alert setMessageText:@"Add Credential"];
[alert addButtonWithTitle:@"OK"];
[alert addButtonWithTitle:@"Cancel"];
NSTextField *siteField = [[[NSTextField alloc] initWithFrame:NSMakeRect(0, 60, 200, 24)] autorelease];
NSTextField *userField = [[[NSTextField alloc] initWithFrame:NSMakeRect(0, 30, 200, 24)] autorelease];
NSTextField *passField = [[[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)] autorelease];
[passField setSecureTextEntry:YES];
NSView *view = [[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 200, 90)] autorelease];
[view addSubview:siteField];
[view addSubview:userField];
[view addSubview:passField];
[alert setAccessoryView:view];
if ([alert runModal] == NSAlertFirstButtonReturn) {
NSString *site = [siteField stringValue];
NSString *username = [userField stringValue];
NSString *password = [passField stringValue];
if ([credentialStore addCredential:site username:username password:password withMasterPassword:masterPassword]) {
NSLog(@"Credential added for %@", site);
} else {
NSLog(@"Failed to add credential: Incorrect master password?");
}
}
}
// Updates the status bar.
- (void)updateStatus:(NSString *)status {
[statusField setStringValue:status];
}
// Updates the bookmarks menu.
- (void)updateBookmarksMenu {
[bookmarksButton removeAllItems];
[bookmarksButton addItemWithTitle:@"Bookmarks"];
[bookmarksButton addItemWithTitle:@"Add Bookmark"];
NSArray *bookmarks = [bookmarkManager allBookmarks];
for (NSDictionary *bookmark in bookmarks) {
[bookmarksButton addItemWithTitle:[bookmark objectForKey:@"title"]];
}
}
// Delegate method for HTML data.
- (void)didReceiveData:(NSString *)data {
isLoading = NO;
[stopButton setEnabled:NO];
[self updateStatus:@"Done"];
[(ContentView *)contentView setHTMLContent:data];
}
// Delegate method for errors.
- (void)didFailWithError:(NSString *)error {
isLoading = NO;
[stopButton setEnabled:NO];
[self updateStatus:[NSString stringWithFormat:@"Error: %@", error]];
[(ContentView *)contentView setHTMLContent:[NSString stringWithFormat:@"Error: %@", error]];
}
@end