Permalink
Browse files

Rewrite as Document-based app

SBJson -> JSONKit
32/64bit compatible
Save, Open, Multiple Windows
  • Loading branch information...
1 parent aa59821 commit 277c68fd7a2d76028828f97787d73cac83db4be3 @youknowone committed Jun 5, 2012
View
@@ -4,3 +4,6 @@
[submodule "IdealCocoa"]
path = IdealCocoa
url = git://github.com/youknowone/IdealCocoa.git
+[submodule "JSONKit"]
+ path = JSONKit
+ url = git://github.com/johnezang/JSONKit.git
View
@@ -4,8 +4,7 @@ Due to library dependencies, git submodule operations are required.
git clone git://github.com/youknowone/VisualJSON.git # or your repository
cd VisualJSON
- git submodule init
- git submodule update
+ git submodule update --init
OK. Dependencies are installed. Open project.
Submodule JSONKit added at 02b983
1 SBJson
Submodule SBJson deleted from 5c4d5f

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -1,19 +0,0 @@
-//
-// AppDelegate.h
-// VisualJSON
-//
-// Created by youknowone on 11. 12. 12..
-// Copyright (c) 2011 youknowone.org All rights reserved.
-//
-
-#import <Cocoa/Cocoa.h>
-
-@class VisualWindow;
-
-@interface AppDelegate : NSObject <NSApplicationDelegate>
-
-@property (assign) IBOutlet VisualWindow *window;
-
-- (IBAction)newDocument:(id)sender;
-
-@end
View
@@ -1,41 +0,0 @@
-//
-// AppDelegate.m
-// VisualJSON
-//
-// Created by youknowone on 11. 12. 12..
-// Copyright (c) 2011 youknowone.org All rights reserved.
-//
-
-#import "AppDelegate.h"
-
-#import "VisualWindow.h"
-
-@implementation AppDelegate
-
-@synthesize window = _window;
-
-- (void)newDocument:(id)sender {
- // Fake new document. VisualJSON does not support multi windows yet.
- if(self.window.isVisible) {
- [self.window newDocument:sender];
- } else {
- [self.window orderFrontRegardless];
- [self.window clearDocument:nil];
- }
-}
-
-- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
-{
- // Insert code here to initialize your application
-}
-
-- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender {
- return YES;
-}
-
-- (BOOL)applicationOpenUntitledFile:(NSApplication *)sender {
- [self.window orderFrontRegardless];
- return YES;
-}
-
-@end
View
@@ -14,7 +14,13 @@
JsonElement get parsed NSArray or NSDictionary data as JSON data.
JsonElement provides representation for data for each view type.
*/
-@interface JsonElement : NSObject
+@interface JsonElement : NSObject {
+ id _parent;
+ id _object;
+ id _key;
+ id _keys;
+ id _children;
+}
@property(assign) id parent;
@property(retain) id object;
View
@@ -109,6 +109,8 @@ - (NSString *)description {
}
- (NSString *)descriptionWithDepth:(NSInteger)depth {
+ if (self.object == nil) return @"";
+
NSMutableString *indent = [NSMutableString string];
for (NSInteger i = 0; i < depth; i++) {
[indent appendString:@"\t"];
View
@@ -0,0 +1,35 @@
+//
+// VJDocument.h
+// VisualJSON
+//
+// Created by 2012 youknowone.org on 12. 6. 4..
+// Copyright (c) 2012 youknowone.org. All rights reserved.
+//
+
+@class VJTabController;
+@class VJRequest;
+@class JsonElement;
+
+@interface VJDocument : NSPersistentDocument {
+ NSTextField *_addressTextField;
+ NSTextField *_postTextField;
+ NSTextField *_contentTextField;
+ NSOutlineView *_jsonOutlineView;
+ NSTextView *_jsonTextView;
+ JsonElement *_json;
+
+ VJRequest *_request;
+}
+
+@property(assign) IBOutlet NSTextField *addressTextField;
+@property(assign) IBOutlet NSTextField *postTextField;
+@property(assign) IBOutlet NSTextField *contentTextField;
+@property(assign) IBOutlet NSOutlineView *jsonOutlineView;
+@property(assign) IBOutlet NSTextView *jsonTextView;
+@property(retain) JsonElement *json;
+@property(retain) VJRequest *request;
+
+- (IBAction)refresh:(id)sender;
+- (IBAction)visualize:(id)sender;
+
+@end
View
@@ -0,0 +1,230 @@
+ //
+// VJDocument.m
+// VisualJSON
+//
+// Created by 2012 youknowone.org on 12. 6. 4..
+// Copyright (c) 2012 youknowone.org. All rights reserved.
+//
+
+#import "VJDocument.h"
+#import "VJRequest.h"
+#import "JSONKit.h"
+#import "JsonElement.h"
+
+@interface VJDocument()
+
+- (BOOL)setMetadataForStoreAtURL:(NSURL *)URL;
+
+@end
+
+@implementation VJDocument
+
+@synthesize addressTextField=_addressTextField, postTextField=_postTextField, contentTextField=_contentTextField;
+@synthesize jsonOutlineView=_jsonOutlineView, jsonTextView=_jsonTextView;
+@synthesize json=_json;
+
+- (NSString *)windowNibName
+{
+ // Override returning the nib file name of the document
+ // If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead.
+ return @"VJDocument";
+}
+
+- (id)initWithType:(NSString *)typeName error:(NSError **)outError {
+ self = [super initWithType:typeName error:outError];
+ if (self != nil) {
+ NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
+ self.request = [NSEntityDescription insertNewObjectForEntityForName:@"Request"
+ inManagedObjectContext:managedObjectContext];
+
+ // To avoid undo registration for this insertion, removeAllActions on the undoManager.
+ // First call processPendingChanges on the managed object context to force the undo registration
+ // for this insertion, then call removeAllActions.
+ [managedObjectContext processPendingChanges];
+ [managedObjectContext.undoManager removeAllActions];
+ [self updateChangeCount:NSChangeCleared];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ self.request = nil;
+ [super dealloc];
+}
+
+- (VJRequest *)request {
+ if (self->_request == nil) {
+ NSManagedObjectContext *context = [self managedObjectContext];
+ NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
+ NSError *fetchError = nil;
+ NSArray *fetchResults;
+
+ @try {
+ NSEntityDescription *entity = [NSEntityDescription entityForName:@"Request" inManagedObjectContext:context];
+
+ [fetchRequest setEntity:entity];
+ fetchResults = [context executeFetchRequest:fetchRequest error:&fetchError];
+ }
+ @finally {
+ [fetchRequest release];
+ }
+
+ if ((fetchResults != nil) && (fetchResults.count == 1) && (fetchError == nil)) {
+ self.request = [fetchResults objectAtIndex:0];
+ }
+ else if (fetchError != nil) {
+ [self presentError:fetchError];
+ }
+ else {
+ // should present custom error message...
+ }
+ }
+ return self->_request;
+}
+
+-(BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName forSaveOperation:(NSSaveOperationType)saveOperation originalContentsURL:(NSURL *)absoluteOriginalContentsURL error:(NSError **)error {
+ // needed -- configure not called for writing existing document
+ if (self.fileURL != nil)
+ {
+ [self setMetadataForStoreAtURL:self.fileURL];
+ }
+
+ return [super writeToURL:absoluteURL ofType:typeName
+ forSaveOperation:saveOperation
+ originalContentsURL:absoluteOriginalContentsURL
+ error:error];
+}
+
+- (BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)url ofType:(NSString *)fileType modelConfiguration:(NSString *)configuration storeOptions:(NSDictionary *)storeOptions error:(NSError **)error {
+ NSLog(@"url: %@, type: %@", url, fileType);
+ BOOL ok = [super configurePersistentStoreCoordinatorForURL:url ofType:fileType modelConfiguration:configuration storeOptions:storeOptions error:error];
+ if (ok)
+ {
+ NSPersistentStoreCoordinator *coordinator = self.managedObjectContext.persistentStoreCoordinator;
+ id pStore = [coordinator persistentStoreForURL:url];
+
+ // configurePersistentStoreCoordinatorForURL is called when document reopened
+ // Check for existing metadata to avoid overwriting unnecessarily
+
+ id existingMetadata = [[coordinator metadataForPersistentStore:pStore] objectForKey:(NSString *)kMDItemKeywords];
+ if (existingMetadata == nil)
+ {
+ ok = [self setMetadataForStoreAtURL:url];
+ }
+ }
+ return ok;
+}
+
+- (BOOL)setMetadataForStoreAtURL:(NSURL *)url
+{
+ NSPersistentStoreCoordinator *coordinator = [[self managedObjectContext] persistentStoreCoordinator];
+
+ id pStore = [coordinator persistentStoreForURL:url];
+ NSString *uniqueKey = [NSString stringWithFormat:@"%@:%@:%@", self.request.address, self.request.postdata, self.request.content];
+
+ if ((pStore != nil) && (uniqueKey != nil))
+ {
+ // metadata auto-configured with NSStoreType and NSStoreUUID
+ NSMutableDictionary *metadata = [[coordinator metadataForPersistentStore:pStore] mutableCopy];
+ [metadata setObject:[NSArray arrayWithObject:uniqueKey] forKey:(NSString *)kMDItemKeywords];
+ [coordinator setMetadata:metadata forPersistentStore:pStore];
+ return YES;
+ }
+ return NO;
+}
+
+- (void)setRequest:(VJRequest *)request {
+ [self->_request autorelease];
+ self->_request = [request retain];
+}
+
+
+- (void)windowControllerDidLoadNib:(NSWindowController *)aController
+{
+ [super windowControllerDidLoadNib:aController];
+ // Add any code here that needs to be executed once the windowController has loaded the document's window.
+
+ [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(visualize:) userInfo:nil repeats:NO];
+}
+
+- (NSPrintOperation *)printOperationWithSettings:(NSDictionary *)printSettings error:(NSError **)outError {
+ NSPrintOperation *printOperation = [NSPrintOperation printOperationWithView:self.jsonTextView];
+ return printOperation;
+}
+
+//+ (BOOL)autosavesInPlace
+//{
+// return YES;
+//}
+
+- (void)refresh:(id)sender {
+ NSString *addr = self.addressTextField.stringValue;
+ // do not touch content if address is blank.
+ if (addr.length == 0) return;
+
+ // decide local or remote
+ NSURL *URL = [addr hasPrefix:@"/"] ? addr.fileURL : addr.URL;
+ NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:URL];
+ // set mimetype
+ [req addValue:@"application/json" forHTTPHeaderField:@"Accept"];
+ [req addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
+ // set post if exists
+ if (self.postTextField.stringValue.length > 0) {
+ [req setHTTPMethod:@"POST"];
+ [req setHTTPBody:[self.postTextField.stringValue dataUsingEncoding:NSUTF8StringEncoding]];
+ }
+
+ // set content field with data
+ NSError *error = nil;
+ NSData *data = [NSData dataWithContentsOfURLRequest:req error:&error];
+ if (data != nil && error == nil) {
+ self.contentTextField.stringValue = [NSString stringWithData:data encoding:NSUTF8StringEncoding];
+ [self performSelector:@selector(visualize:) withObject:sender afterDelay:0.02];
+ } else {
+ self.contentTextField.stringValue = [NSString stringWithFormat:@"Error on getting raw JSON text: %@", error];
+ }
+
+ self.request.content = self.contentTextField.stringValue;
+}
+
+- (void)visualize:(id)sender {
+ self.json = [JsonElement elementWithObject:[self.contentTextField.stringValue objectFromJSONString]];
+ [self.jsonOutlineView performSelector:@selector(reloadData) withObject:nil afterDelay:0.02];
+ self.jsonTextView.string = self.json.description;
+}
+
+- (NSString *)title {
+ return self.addressTextField.stringValue;
+}
+
+#pragma mark - outline delegate for 'tree' view
+
+- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
+ if (item == nil) item = self.json;
+ return [[item keys] count];
+}
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
+ if (item == nil) item = self.json;
+ return [item keys] != nil;
+}
+
+- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
+ if (item == nil) item = self.json;
+ return [item childAtIndex:index];
+}
+
+- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
+ if (item == nil) item = self.json;
+ NSString *title = [tableColumn.headerCell title];
+ if ([title isEqualToString:@"node"]) {
+ return [item key];
+ } else if ([title isEqualToString:@"description"]) {
+ return [item outlineDescription];
+ } else {
+ ICAssert(NO);
+ }
+ return nil;
+}
+
+@end
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>_XCCurrentVersionName</key>
+ <string>VJDocument.xcdatamodel</string>
+</dict>
+</plist>
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1171" systemVersion="11E53" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
+ <entity name="Request" representedClassName="NSManagedObject" syncable="YES">
+ <attribute name="address" optional="YES" attributeType="String" syncable="YES"/>
+ <attribute name="content" optional="YES" attributeType="String" syncable="YES"/>
+ <attribute name="postdata" optional="YES" attributeType="String" syncable="YES"/>
+ </entity>
+ <elements>
+ <element name="Request" positionX="160" positionY="192" width="128" height="98"/>
+ </elements>
+</model>
Oops, something went wrong.

0 comments on commit 277c68f

Please sign in to comment.