-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathCouchDBXApplicationController.m
304 lines (258 loc) · 8.75 KB
/
CouchDBXApplicationController.m
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
/*
* Author: Jan Lehnardt <[email protected]>
* This is Apache 2.0 licensed free software
*/
#import "CouchDBXApplicationController.h"
#import "Sparkle/Sparkle.h"
#import "SUUpdaterDelegate.h"
@implementation CouchDBXApplicationController
-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app
{
return YES;
}
-(void)applicationWillTerminate:(NSNotification *)notification
{
[self ensureFullCommit];
}
- (void)windowWillClose:(NSNotification *)aNotification
{
[self stop];
}
-(void)applicationWillFinishLaunching:(NSNotification *)notification
{
SUUpdater *updater = [SUUpdater sharedUpdater];
SUUpdaterDelegate *updaterDelegate = [[SUUpdaterDelegate alloc] init];
[updater setDelegate: updaterDelegate];
}
-(void)ensureFullCommit
{
// find couch.uri file
NSMutableString *urifile = [[NSMutableString alloc] init];
[urifile appendString: [task currentDirectoryPath]]; // couchdbx-core
[urifile appendString: @"/couchdb/var/lib/couchdb/couch.uri"];
// get couch uri
NSString *uri = [NSString stringWithContentsOfFile:urifile encoding:NSUTF8StringEncoding error:NULL];
// TODO: maybe parse out \n
// get database dir
NSString *databaseDir = [self applicationSupportFolder];
// get ensure_full_commit.sh
NSMutableString *ensure_full_commit_script = [[NSMutableString alloc] init];
[ensure_full_commit_script appendString: [[NSBundle mainBundle] resourcePath]];
[ensure_full_commit_script appendString: @"/ensure_full_commit.sh"];
// exec ensure_full_commit.sh database_dir couch.uri
NSArray *args = [[NSArray alloc] initWithObjects:databaseDir, uri, nil];
NSTask *commitTask = [[NSTask alloc] init];
[commitTask setArguments: args];
[commitTask launch];
[commitTask waitUntilExit];
// yay!
}
-(void)awakeFromNib
{
[browse setEnabled:NO];
NSLayoutManager *lm;
lm = [outputView layoutManager];
[lm setDelegate:self];
[webView setUIDelegate:self];
[self launchCouchDB];
}
-(IBAction)start:(id)sender
{
if([task isRunning]) {
[self stop];
return;
}
[self launchCouchDB];
}
-(void)stop
{
NSFileHandle *writer;
writer = [in fileHandleForWriting];
[writer writeData:[@"q().\n" dataUsingEncoding:NSASCIIStringEncoding]];
[writer closeFile];
[browse setEnabled:NO];
[start setImage:[NSImage imageNamed:@"start.png"]];
[start setLabel:@"start"];
}
/* found at http://www.cocoadev.com/index.pl?ApplicationSupportFolder */
- (NSString *)applicationSupportFolder {
NSString *applicationSupportFolder = nil;
FSRef foundRef;
OSErr err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, kDontCreateFolder, &foundRef);
if (err == noErr) {
unsigned char path[PATH_MAX];
OSStatus validPath = FSRefMakePath(&foundRef, path, sizeof(path));
if (validPath == noErr)
{
applicationSupportFolder = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:path length:(NSUInteger)strlen((char*)path)];
}
}
applicationSupportFolder = [applicationSupportFolder stringByAppendingPathComponent:@"CouchDBX"];
return applicationSupportFolder;
}
-(void)maybeSetDataDirs
{
// determine data dir
NSString *dataDir = [self applicationSupportFolder];
// create if it doesn't exist
if(![[NSFileManager defaultManager] fileExistsAtPath:dataDir]) {
[[NSFileManager defaultManager] createDirectoryAtPath:dataDir withIntermediateDirectories:YES attributes:nil error:NULL];
}
// if data dirs are not set in local.ini
NSMutableString *iniFile = [[NSMutableString alloc] init];
[iniFile appendString:[[NSBundle mainBundle] resourcePath]];
[iniFile appendString:@"/couchdbx-core/couchdb/etc/couchdb/local.ini"];
NSString *ini = [NSString stringWithContentsOfFile:iniFile encoding:NSUTF8StringEncoding error:NULL];
NSRange found = [ini rangeOfString:dataDir];
if(found.length == 0) {
// set them
NSMutableString *newIni = [[NSMutableString alloc] init];
[newIni appendString: ini];
[newIni appendString:@"[couchdb]\ndatabase_dir = "];
[newIni appendString:dataDir];
[newIni appendString:@"\nview_index_dir = "];
[newIni appendString:dataDir];
[newIni appendString:@"\n\n"];
[newIni writeToFile:iniFile atomically:YES encoding:NSUTF8StringEncoding error:NULL];
[newIni release];
}
[iniFile release];
// done
}
-(void)launchCouchDB
{
[self maybeSetDataDirs];
[browse setEnabled:YES];
[start setImage:[NSImage imageNamed:@"stop.png"]];
[start setLabel:@"stop"];
in = [[NSPipe alloc] init];
out = [[NSPipe alloc] init];
task = [[NSTask alloc] init];
NSMutableString *launchPath = [[NSMutableString alloc] init];
[launchPath appendString:[[NSBundle mainBundle] resourcePath]];
[launchPath appendString:@"/couchdbx-core"];
[task setCurrentDirectoryPath:launchPath];
[launchPath appendString:@"/couchdb/bin/couchdb"];
[task setLaunchPath:launchPath];
NSArray *args = [[NSArray alloc] initWithObjects:@"-i", nil];
[task setArguments:args];
[task setStandardInput:in];
[task setStandardOutput:out];
NSFileHandle *fh = [out fileHandleForReading];
NSNotificationCenter *nc;
nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:@selector(dataReady:)
name:NSFileHandleReadCompletionNotification
object:fh];
[nc addObserver:self
selector:@selector(taskTerminated:)
name:NSTaskDidTerminateNotification
object:task];
[task launch];
[outputView setString:@"Starting CouchDB...\n"];
[fh readInBackgroundAndNotify];
sleep(1);
[self openFuton];
}
-(void)taskTerminated:(NSNotification *)note
{
[self cleanup];
}
-(void)cleanup
{
[task release];
task = nil;
[in release];
in = nil;
[out release];
out = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-(void)openFuton
{
NSDictionary *info = [[NSBundle mainBundle] infoDictionary];
NSString *homePage = [info objectForKey:@"HomePage"];
[webView setTextSizeMultiplier:1.3];
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:homePage]]];
}
-(IBAction)browse:(id)sender
{
[self openFuton];
//[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://127.0.0.1:5984/_utils/"]];
}
- (void)appendData:(NSData *)d
{
NSString *s = [[NSString alloc] initWithData: d
encoding: NSUTF8StringEncoding];
NSTextStorage *ts = [outputView textStorage];
[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withString:s];
[s release];
}
- (void)dataReady:(NSNotification *)n
{
NSData *d;
d = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem];
if ([d length]) {
[self appendData:d];
}
if (task)
[[out fileHandleForReading] readInBackgroundAndNotify];
}
- (void)layoutManager:(NSLayoutManager *)aLayoutManager didCompleteLayoutForTextContainer:(NSTextContainer *)aTextContainer atEnd:(BOOL)flag
{
if (flag) {
NSTextStorage *ts = [outputView textStorage];
[outputView scrollRangeToVisible:NSMakeRange([ts length], 0)];
}
}
- (void)webView:(WebView *)sender runOpenPanelForFileButtonWithResultListener:(id < WebOpenPanelResultListener >)resultListener
{
[self openChooseFileDialogWithListener: resultListener
allowMultipleFiles: FALSE];
}
- (void)webView:(WebView *)sender runOpenPanelForFileButtonWithResultListener:(id < WebOpenPanelResultListener >)resultListener allowMultipleFiles:(BOOL)allowMultipleFiles
{
[self openChooseFileDialogWithListener: resultListener
allowMultipleFiles: allowMultipleFiles];
}
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
#define MULTIPLE_SELECTION_POSSIBLE TRUE
#else
#define MULTIPLE_SELECTION_POSSIBLE FALSE
#endif
- (void)openChooseFileDialogWithListener: (id < WebOpenPanelResultListener >)resultListener allowMultipleFiles: (BOOL)multipleSelection
{
NSOpenPanel* openDlg = [NSOpenPanel openPanel];
[openDlg setCanChooseFiles:YES];
[openDlg setCanChooseDirectories:NO];
[openDlg setAllowsMultipleSelection: (multipleSelection && MULTIPLE_SELECTION_POSSIBLE)];
NSInteger result = [openDlg runModal];
if (result == NSFileHandlingPanelOKButton) {
NSArray* files = [openDlg URLs];
#if MULTIPLE_SELECTION_POSSIBLE
NSInteger filesNumber = [files count];
if (filesNumber == 1) {
#endif
NSURL* fileURL = [files objectAtIndex:0];
NSString* path = [fileURL path];
[resultListener chooseFilename:path ];
#if MULTIPLE_SELECTION_POSSIBLE
} else {
NSMutableArray* fileNames = [NSMutableArray arrayWithCapacity:filesNumber];
for (NSURL* fileURL in files) {
NSString* path = [fileURL path];
[fileNames addObject:path];
}
[resultListener chooseFilenames: fileNames];
}
#endif
} else {
[resultListener cancel];
}
}
- (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame
{
NSRunInformationalAlertPanel(nil, message, nil, nil, nil);
}
@end