Skip to content
Browse files

v1.0

  • Loading branch information...
0 parents commit 603dd5ab4511c1a17a485a31c78639465a5d586d Ben Williamson committed Oct 27, 2010
Showing with 23,768 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +52 −0 Classes/AboutViewController.h
  3. +225 −0 Classes/AboutViewController.m
  4. +43 −0 Classes/AboutWebViewController.h
  5. +130 −0 Classes/AboutWebViewController.m
  6. +66 −0 Classes/CalendarHelpers.h
  7. +130 −0 Classes/CalendarHelpers.m
  8. +59 −0 Classes/Chart.h
  9. +45 −0 Classes/Chart.m
  10. +47 −0 Classes/ChartDataset.h
  11. +66 −0 Classes/ChartDataset.m
  12. +42 −0 Classes/ChartLoader.h
  13. +108 −0 Classes/ChartLoader.m
  14. +69 −0 Classes/ChartParser.h
  15. +357 −0 Classes/ChartParser.m
  16. +46 −0 Classes/ChartRequest.h
  17. +106 −0 Classes/ChartRequest.m
  18. +59 −0 Classes/ChartSeries.h
  19. +67 −0 Classes/ChartSeries.m
  20. +48 −0 Classes/ChartValue.h
  21. +62 −0 Classes/ChartValue.m
  22. +92 −0 Classes/ChartViewController.h
  23. +591 −0 Classes/ChartViewController.m
  24. +91 −0 Classes/DataLoader.h
  25. +241 −0 Classes/DataLoader.m
  26. +122 −0 Classes/DataManager.h
  27. +476 −0 Classes/DataManager.m
  28. +46 −0 Classes/DataParser.h
  29. +60 −0 Classes/DataParser.m
  30. +69 −0 Classes/DataRequest.h
  31. +72 −0 Classes/DataRequest.m
  32. +38 −0 Classes/FancyLabel.h
  33. +71 −0 Classes/FancyLabel.m
  34. +50 −0 Classes/FavouriteToggleButtonController.h
  35. +117 −0 Classes/FavouriteToggleButtonController.m
  36. +51 −0 Classes/Favourites.h
  37. +158 −0 Classes/Favourites.m
  38. +43 −0 Classes/FavouritesTableViewController.h
  39. +236 −0 Classes/FavouritesTableViewController.m
  40. +51 −0 Classes/FetchedPlaceTableViewController.h
  41. +139 −0 Classes/FetchedPlaceTableViewController.m
  42. +50 −0 Classes/JSON/JSON.h
  43. +68 −0 Classes/JSON/NSObject+SBJSON.h
  44. +53 −0 Classes/JSON/NSObject+SBJSON.m
  45. +58 −0 Classes/JSON/NSString+SBJSON.h
  46. +55 −0 Classes/JSON/NSString+SBJSON.m
  47. +75 −0 Classes/JSON/SBJSON.h
  48. +212 −0 Classes/JSON/SBJSON.m
  49. +86 −0 Classes/JSON/SBJsonBase.h
  50. +78 −0 Classes/JSON/SBJsonBase.m
  51. +87 −0 Classes/JSON/SBJsonParser.h
  52. +475 −0 Classes/JSON/SBJsonParser.m
  53. +129 −0 Classes/JSON/SBJsonWriter.h
  54. +228 −0 Classes/JSON/SBJsonWriter.m
  55. +82 −0 Classes/LandscapeViewController.h
  56. +300 −0 Classes/LandscapeViewController.m
  57. +61 −0 Classes/Measurement.h
  58. +140 −0 Classes/Measurement.m
  59. +43 −0 Classes/NSDictionary+XMLStreamParserHelpers.h
  60. +49 −0 Classes/NSDictionary+XMLStreamParserHelpers.m
  61. +41 −0 Classes/NSManagedObject+StackHelpers.h
  62. +73 −0 Classes/NSManagedObject+StackHelpers.m
  63. +39 −0 Classes/NSManagedObjectContext+Helpers.h
  64. +54 −0 Classes/NSManagedObjectContext+Helpers.m
  65. +51 −0 Classes/Observation.h
  66. +58 −0 Classes/Observation.m
  67. +104 −0 Classes/Place.h
  68. +113 −0 Classes/Place.m
  69. +59 −0 Classes/PlaceCell.h
  70. +127 −0 Classes/PlaceCell.m
  71. +92 −0 Classes/PlaceDetailViewController.h
  72. +502 −0 Classes/PlaceDetailViewController.m
  73. +42 −0 Classes/PlaceLoader.h
  74. +104 −0 Classes/PlaceLoader.m
  75. +49 −0 Classes/PlaceParser.h
  76. +401 −0 Classes/PlaceParser.m
  77. +56 −0 Classes/PlaceRequest.h
  78. +128 −0 Classes/PlaceRequest.m
  79. +60 −0 Classes/PlaceTableViewController.h
  80. +110 −0 Classes/PlaceTableViewController.m
  81. +53 −0 Classes/PlaceType.h
  82. +120 −0 Classes/PlaceType.m
  83. BIN Classes/Places.xcdatamodel/elements
  84. BIN Classes/Places.xcdatamodel/layout
  85. +92 −0 Classes/Reachability.h
  86. +280 −0 Classes/Reachability.m
  87. +44 −0 Classes/SearchViewController.h
  88. +170 −0 Classes/SearchViewController.m
  89. +44 −0 Classes/SlakeAppDelegate.h
  90. +248 −0 Classes/SlakeAppDelegate.m
  91. +105 −0 Classes/XMLStreamParser.h
  92. +274 −0 Classes/XMLStreamParser.m
  93. +173 −0 Classes/XMLStreamParser.txt
  94. +90 −0 LICENSE.txt
  95. BIN Places.sqlite
  96. +37 −0 README.md
  97. +87 −0 Release-notes.txt
  98. +42 −0 Slake-Info.plist
  99. +882 −0 Slake.xcodeproj/project.pbxproj
  100. +17 −0 Slake_Prefix.pch
  101. +28 −0 Todo.txt
  102. +25 −0 about/about.html
  103. +107 −0 about/css/style.css
  104. +34 −0 about/disclamer.html
  105. +49 −0 about/features.html
  106. BIN about/images/bg.png
  107. BIN about/images/btn-about.png
  108. BIN about/images/btn-aust.png
  109. BIN about/images/btn-fav.png
  110. BIN about/images/btn-search.png
  111. +35 −0 core-plot/.hgignore
  112. +4 −0 core-plot/.hgtags
  113. +9 −0 core-plot/License.txt
  114. +59 −0 core-plot/framework/CorePlot-CocoaTouch.h
  115. +1,120 −0 core-plot/framework/CorePlot-CocoaTouch.xcodeproj/project.pbxproj
  116. +58 −0 core-plot/framework/CorePlot.h
  117. BIN core-plot/framework/CorePlot.xcodeproj/TemplateIcon.icns
  118. +1,433 −0 core-plot/framework/CorePlot.xcodeproj/project.pbxproj
  119. +8 −0 core-plot/framework/CorePlot_CocoaTouch_Prefix.pch
  120. +13 −0 core-plot/framework/CorePlot_Prefix.pch
  121. BIN core-plot/framework/English.lproj/InfoPlist.strings
  122. +3,098 −0 core-plot/framework/English.lproj/MainMenu.xib
  123. +30 −0 core-plot/framework/Info-CocoaTouch.plist
  124. +26 −0 core-plot/framework/Info.plist
  125. +9 −0 core-plot/framework/MacOnly/CPDecimalNumberValueTransformer.h
  126. +28 −0 core-plot/framework/MacOnly/CPDecimalNumberValueTransformer.m
  127. +12 −0 core-plot/framework/MacOnly/CPLayerHostingView.h
  128. +76 −0 core-plot/framework/MacOnly/CPLayerHostingView.m
  129. +25 −0 core-plot/framework/MacOnly/CPPlatformSpecificCategories.h
  130. +47 −0 core-plot/framework/MacOnly/CPPlatformSpecificCategories.m
  131. +14 −0 core-plot/framework/MacOnly/CPPlatformSpecificDefines.h
  132. 0 core-plot/framework/MacOnly/CPPlatformSpecificDefines.m
  133. +23 −0 core-plot/framework/MacOnly/CPPlatformSpecificFunctions.h
  134. +87 −0 core-plot/framework/MacOnly/CPPlatformSpecificFunctions.m
  135. +2 −0 core-plot/framework/MacOnly/CPTextStylePlatformSpecific.h
  136. +57 −0 core-plot/framework/MacOnly/CPTextStylePlatformSpecific.m
  137. +26 −0 core-plot/framework/SDKBuild/README.txt
  138. +28 −0 core-plot/framework/SDKBuild/build.sh
  139. +3 −0 core-plot/framework/SDKBuild/cp.sed
  140. +51 −0 core-plot/framework/SDKBuild/iphoneos-SDKSettings.plist
  141. +37 −0 core-plot/framework/SDKBuild/iphonesimulator-SDKSettings.plist
  142. +46 −0 core-plot/framework/Source/CPAnimation.h
  143. +101 −0 core-plot/framework/Source/CPAnimation.m
  144. +17 −0 core-plot/framework/Source/CPAnimationKeyFrame.h
  145. +56 −0 core-plot/framework/Source/CPAnimationKeyFrame.m
  146. +35 −0 core-plot/framework/Source/CPAnimationTransition.h
  147. +87 −0 core-plot/framework/Source/CPAnimationTransition.m
  148. +29 −0 core-plot/framework/Source/CPAnnotation.h
  149. +102 −0 core-plot/framework/Source/CPAnnotation.m
  150. +15 −0 core-plot/framework/Source/CPAnnotationHostLayer.h
  151. +82 −0 core-plot/framework/Source/CPAnnotationHostLayer.m
  152. +210 −0 core-plot/framework/Source/CPAxis.h
  153. +1,331 −0 core-plot/framework/Source/CPAxis.m
  154. +36 −0 core-plot/framework/Source/CPAxisLabel.h
  155. +204 −0 core-plot/framework/Source/CPAxisLabel.m
  156. +8 −0 core-plot/framework/Source/CPAxisLabelGroup.h
  157. +23 −0 core-plot/framework/Source/CPAxisLabelGroup.m
  158. +8 −0 core-plot/framework/Source/CPAxisLabelTests.h
  159. +138 −0 core-plot/framework/Source/CPAxisLabelTests.m
  160. +17 −0 core-plot/framework/Source/CPAxisSet.h
  161. +96 −0 core-plot/framework/Source/CPAxisSet.m
  162. +10 −0 core-plot/framework/Source/CPAxisTitle.h
  163. +62 −0 core-plot/framework/Source/CPAxisTitle.m
  164. +89 −0 core-plot/framework/Source/CPBarPlot.h
  165. +688 −0 core-plot/framework/Source/CPBarPlot.m
  166. +16 −0 core-plot/framework/Source/CPBorderedLayer.h
  167. +163 −0 core-plot/framework/Source/CPBorderedLayer.m
  168. +42 −0 core-plot/framework/Source/CPColor.h
  169. +395 −0 core-plot/framework/Source/CPColor.m
  170. +16 −0 core-plot/framework/Source/CPColorSpace.h
  171. +93 −0 core-plot/framework/Source/CPColorSpace.m
  172. +31 −0 core-plot/framework/Source/CPConstrainedPosition.h
  173. +135 −0 core-plot/framework/Source/CPConstrainedPosition.m
  174. +8 −0 core-plot/framework/Source/CPDarkGradientTheme.h
  175. +97 −0 core-plot/framework/Source/CPDarkGradientTheme.m
  176. +6 −0 core-plot/framework/Source/CPDarkGradientThemeTests.h
  177. +36 −0 core-plot/framework/Source/CPDarkGradientThemeTests.m
  178. +28 −0 core-plot/framework/Source/CPDataSourceTestCase.h
  179. +137 −0 core-plot/framework/Source/CPDataSourceTestCase.m
  180. +106 −0 core-plot/framework/Source/CPDefinitions.h
  181. +10 −0 core-plot/framework/Source/CPDefinitions.m
  182. +7 −0 core-plot/framework/Source/CPDerivedXYGraph.h
  183. +7 −0 core-plot/framework/Source/CPDerivedXYGraph.m
  184. +10 −0 core-plot/framework/Source/CPExceptions.h
  185. +5 −0 core-plot/framework/Source/CPExceptions.m
  186. +40 −0 core-plot/framework/Source/CPFill.h
  187. +136 −0 core-plot/framework/Source/CPFill.m
  188. +98 −0 core-plot/framework/Source/CPGradient.h
Sorry, we could not display the entire diff because too many files (350) changed.
4 .gitignore
@@ -0,0 +1,4 @@
+*.mode1v3
+*.pbxuser
+build
+.DS_Store
52 Classes/AboutViewController.h
@@ -0,0 +1,52 @@
+//
+// AboutViewController.h
+// Slake
+//
+// Created by Ben Williamson on 8/04/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import <UIKit/UIKit.h>
+
+
+@interface AboutViewController : UIViewController <UIActionSheetDelegate, MFMailComposeViewControllerDelegate> {
+ UIView* credits;
+ UILabel* versionLabel;
+ BOOL creditsVisible;
+ UISegmentedControl* segmentedButton;
+}
+
+@property (nonatomic, retain) IBOutlet UIView* credits;
+@property (nonatomic, retain) IBOutlet UILabel* versionLabel;
+@property (nonatomic, retain) IBOutlet UISegmentedControl* segmentedButton;
+
+- (IBAction)showWebsite;
+- (IBAction)sendFeedback;
+- (IBAction)showCredits;
+- (IBAction)hideCredits;
+- (IBAction)segmentedButtonValueChanged;
+
+@end
225 Classes/AboutViewController.m
@@ -0,0 +1,225 @@
+//
+// AboutViewController.m
+// Slake
+//
+// Created by Ben Williamson on 8/04/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import "AboutViewController.h"
+#import "AboutWebViewController.h"
+
+@interface AboutViewController () // private
+
+@property (nonatomic) BOOL creditsVisible;
+
+- (void)showActionSheet;
+
+@end
+
+static float kCreditsPositionHidden = 400.0f;
+static float kCreditsPositionVisible = 245.0f;
+
+struct AboutPage {
+ NSString* title;
+ NSString* url;
+};
+
+// These are in the same order as the segmentedButton segments:
+static const struct AboutPage pages[] = {
+ { @"Features", @"about/features.html" },
+ { @"Copyright", @"http://www.bom.gov.au/water/waterstorage/iphone/copyright.php" },
+ { @"Disclaimer", @"about/disclamer.html" }
+};
+
+static const int kNumberOfPages = sizeof pages / sizeof pages[0];
+
+@implementation AboutViewController
+
+@synthesize credits;
+@synthesize versionLabel;
+@synthesize creditsVisible;
+@synthesize segmentedButton;
+
+
+- (void)dealloc
+{
+ [credits release];
+ [versionLabel release];
+ [segmentedButton release];
+ [super dealloc];
+}
+
+// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+ NSString* version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleGetInfoString"];
+ self.versionLabel.text = [NSString stringWithFormat:@"Water Storage %@", version];
+ self.segmentedButton.tintColor = [UIColor colorWithRed:20.0/255.0 green:130.0/255.0 blue:192.0/255.0 alpha:1.0];
+}
+
+- (void)didReceiveMemoryWarning
+{
+ // Releases the view if it doesn't have a superview.
+ [super didReceiveMemoryWarning];
+
+ // Release any cached data, images, etc that aren't in use.
+}
+
+- (void)viewDidUnload
+{
+ // Release any retained subviews of the main view.
+ // e.g. self.myOutlet = nil;
+ self.credits = nil;
+ self.versionLabel = nil;
+ self.segmentedButton = nil;
+
+ [super viewDidUnload];
+}
+
+- (void)showActionSheet
+{
+ UIActionSheet* sheet = [[[UIActionSheet alloc] initWithTitle:@"Water Storage at www.bom.gov.au"
+ delegate:self
+ cancelButtonTitle:@"Cancel"
+ destructiveButtonTitle:nil
+ otherButtonTitles:@"Open in Safari", @"Copy URL", nil] autorelease];
+ sheet.actionSheetStyle = UIActionSheetStyleDefault;
+ UIView* rootView = [UIApplication sharedApplication].keyWindow;
+ [sheet showInView:rootView];
+}
+
+- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
+{
+ NSString* urlString = @"http://www.bom.gov.au/water/waterstorage/iphone.shtml";
+ NSURL* url = [NSURL URLWithString:urlString];
+ switch (buttonIndex) {
+ case 0:
+ [[UIApplication sharedApplication] openURL:url];
+ break;
+ case 1:
+ [UIPasteboard generalPasteboard].string = urlString;
+ break;
+ }
+}
+
+- (IBAction)showWebsite
+{
+ [self showActionSheet];
+}
+
+- (BOOL)canBecomeFirstResponder
+{
+ return YES;
+}
+
+- (void)viewWillAppear:(BOOL)animated
+{
+ CGRect frame = self.credits.frame;
+ frame.origin.y = kCreditsPositionHidden;
+ self.credits.frame = frame;
+ self.creditsVisible = NO;
+}
+
+- (void)viewDidAppear:(BOOL)animated
+{
+ [super viewDidAppear:animated];
+ [self becomeFirstResponder];
+ self.segmentedButton.selectedSegmentIndex = -1;
+}
+
+- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
+{
+ if (motion == UIEventSubtypeMotionShake) {
+ if (self.creditsVisible) {
+ [self hideCredits];
+ } else {
+ [self showCredits];
+ }
+ }
+}
+
+- (IBAction)sendFeedback
+{
+ MFMailComposeViewController *mailViewController = [[[MFMailComposeViewController alloc] init] autorelease];
+ mailViewController.mailComposeDelegate = self;
+ [mailViewController setToRecipients:[NSArray arrayWithObject:@"waterinfo@bom.gov.au"]];
+ [mailViewController setSubject:@"Feedback on Water Storage"];
+ [self presentModalViewController:mailViewController animated:YES];
+}
+
+-(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
+{
+ [self dismissModalViewControllerAnimated:YES];
+}
+
+- (IBAction)showCredits
+{
+ [UIView beginAnimations:@"credits" context:nil];
+ [UIView setAnimationDuration:0.5f];
+ [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
+ CGRect frame = self.credits.frame;
+ frame.origin.y = kCreditsPositionVisible;
+ self.credits.frame = frame;
+ [UIView commitAnimations];
+ self.creditsVisible = YES;
+ if (UIAccessibilityIsVoiceOverRunning != nil && UIAccessibilityIsVoiceOverRunning()) {
+ UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
+ UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, @"Credits displayed");
+ }
+}
+
+- (IBAction)hideCredits
+{
+ [UIView beginAnimations:@"credits" context:nil];
+ [UIView setAnimationDuration:0.5f];
+ [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
+ CGRect frame = self.credits.frame;
+ frame.origin.y = kCreditsPositionHidden;
+ self.credits.frame = frame;
+ [UIView commitAnimations];
+ self.creditsVisible = NO;
+ if (UIAccessibilityIsVoiceOverRunning != nil && UIAccessibilityIsVoiceOverRunning()) {
+ UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
+ UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, @"Credits hidden");
+ }
+}
+
+- (IBAction)segmentedButtonValueChanged
+{
+ int page = self.segmentedButton.selectedSegmentIndex;
+ if (page >= 0 && page < kNumberOfPages) {
+ NSURL* bundleURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
+
+ AboutWebViewController* awvc = [[[AboutWebViewController alloc] init] autorelease];
+ awvc.title = pages[page].title;
+ awvc.pageURL = [NSURL URLWithString:pages[page].url relativeToURL:bundleURL];
+ [self.navigationController pushViewController:awvc animated:YES];
+ }
+}
+
+@end
43 Classes/AboutWebViewController.h
@@ -0,0 +1,43 @@
+//
+// AboutWebViewController.h
+// Slake
+//
+// Created by Quentin Leseney on 10/08/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import <UIKit/UIKit.h>
+
+
+@interface AboutWebViewController : UIViewController <UIWebViewDelegate, UIActionSheetDelegate, MFMailComposeViewControllerDelegate> {
+ NSURL* pageURL;
+ NSURL* _actionURL;
+}
+
+@property (nonatomic, retain) NSURL* pageURL;
+@property (nonatomic, retain) NSURL* actionURL;
+
+@end
130 Classes/AboutWebViewController.m
@@ -0,0 +1,130 @@
+//
+// AboutWebViewController.h
+// Slake
+//
+// Created by Quentin Leseney on 10/08/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import "AboutWebViewController.h"
+
+@implementation AboutWebViewController
+
+@synthesize pageURL = _pageURL;
+@synthesize actionURL = _actionURL;
+
+
+- (void)dealloc
+{
+ [_pageURL release];
+ [_actionURL release];
+ [super dealloc];
+}
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+
+ UIWebView* webView = (UIWebView*)self.view;
+ NSURLRequest* request = [NSURLRequest requestWithURL:self.pageURL];
+ webView.scalesPageToFit = YES;
+ webView.delegate = self;
+ [webView loadRequest:request];
+}
+
+- (void)viewDidUnload
+{
+ // Release any retained subviews of the main view.
+ // e.g. self.myOutlet = nil;
+ [super viewDidUnload];
+}
+
+- (void)viewDidAppear:(BOOL)animated
+{
+ [super viewDidAppear:animated];
+}
+
+- (void)showActionSheetForURL:(NSURL*)url
+{
+ self.actionURL = url;
+ NSString* scheme = [url scheme];
+ NSString* openButtonTitle;
+ NSString* copyButtonTitle;
+ if ([scheme isEqualToString:@"mailto"]) {
+ openButtonTitle = @"Open in Mail";
+ copyButtonTitle = @"Copy Email Address";
+ } else {
+ openButtonTitle = @"Open in Safari";
+ copyButtonTitle = @"Copy URL";
+ }
+ UIActionSheet* sheet = [[[UIActionSheet alloc] initWithTitle:[url absoluteString]
+ delegate:self
+ cancelButtonTitle:@"Cancel"
+ destructiveButtonTitle:nil
+ otherButtonTitles:openButtonTitle, copyButtonTitle, nil] autorelease];
+ sheet.actionSheetStyle = UIActionSheetStyleDefault;
+ UIView* rootView = [UIApplication sharedApplication].keyWindow;
+ [sheet showInView:rootView];
+}
+
+- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
+{
+ switch (buttonIndex) {
+ case 0:
+ [[UIApplication sharedApplication] openURL:self.actionURL];
+ break;
+ case 1:
+ [UIPasteboard generalPasteboard].string = [self.actionURL absoluteString];
+ break;
+ }
+}
+
+- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
+{
+ if (navigationType == UIWebViewNavigationTypeLinkClicked) {
+ NSURL* url = [request URL];
+ NSString* scheme = [url scheme];
+ if ([scheme isEqualToString:@"mailto"] && [MFMailComposeViewController canSendMail]) {
+ // Trim off "mailto:"
+ NSString* emailAddress = [[url absoluteString] substringFromIndex:[scheme length] + 1];
+ MFMailComposeViewController *mailViewController = [[[MFMailComposeViewController alloc] init] autorelease];
+ mailViewController.mailComposeDelegate = self;
+ [mailViewController setToRecipients:[NSArray arrayWithObject:emailAddress]];
+ [self presentModalViewController:mailViewController animated:YES];
+ } else {
+ [self showActionSheetForURL:[request URL]];
+ }
+ return NO;
+ }
+ return YES;
+}
+
+-(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
+{
+ [self dismissModalViewControllerAnimated:YES];
+}
+
+@end
66 Classes/CalendarHelpers.h
@@ -0,0 +1,66 @@
+//
+// CalendarHelpers.h
+// Slake
+//
+// Created by Quentin Leseney on 7/07/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// All date structures are using a shared gregorian calendar in English locale and the UTC timezone
+// (no daylight saving, safe to perform dates arithmetics)
+//
+
+#import <Foundation/Foundation.h>
+
+@interface NSCalendar (CalendarHelpers)
+
++ (BOOL)isLeapYear:(int)year;
+
++ (NSCalendar*)gregorian;
+
+@end
+
+
+@interface NSDate (CalendarHelpers)
+
+- (NSString*)readableDateWithWeekDay;
+
+- (NSString*)readableDateNoWeekDay;
+
+@end
+
+
+@interface NSDateFormatter (CalendarHelpers)
+
++ (NSDateFormatter*) dateFormatterWithFormat:(NSString*)format;
+
+@end
+
+
+@interface NSObject (CalendarHelpers)
+
+- (NSDate*) dateFromStringISO8601DateTimeExtended;
+
+@end
130 Classes/CalendarHelpers.m
@@ -0,0 +1,130 @@
+//
+// CalendarHelpers.m
+// Slake
+//
+// Created by Quentin Leseney on 7/07/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+#import "CalendarHelpers.h"
+
+@implementation NSCalendar (CalendarHelpers)
+
++ (BOOL)isLeapYear:(int)year
+{
+ if (year % 400 == 0) {
+ return YES;
+ } else if (year % 100 == 0) {
+ return NO;
+ } else if (year % 4 == 0) {
+ return YES;
+ } else {
+ return NO;
+ }
+}
+
++ (NSCalendar*)gregorian
+{
+ static NSCalendar* gregorian = nil;
+ if (gregorian == nil) {
+ gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
+ gregorian.locale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en"] autorelease];
+ gregorian.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
+ }
+ return gregorian;
+}
+
+@end
+
+
+@implementation NSDate (CalendarHelpers)
+
+- (NSString*)readableDateWithWeekDay
+{
+ static NSDateFormatter* dateFormatterReadableDateWithWeekDay = nil;
+ if (dateFormatterReadableDateWithWeekDay == nil) {
+ dateFormatterReadableDateWithWeekDay = [[NSDateFormatter alloc] init];
+ dateFormatterReadableDateWithWeekDay.dateFormat = @"EEE d MMM yyyy";
+ dateFormatterReadableDateWithWeekDay.calendar = [NSCalendar gregorian];
+ dateFormatterReadableDateWithWeekDay.locale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en"] autorelease];
+ dateFormatterReadableDateWithWeekDay.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
+ }
+ return [dateFormatterReadableDateWithWeekDay stringFromDate:self];
+}
+
+- (NSString*)readableDateNoWeekDay
+{
+ static NSDateFormatter* dateFormatterReadableDateNoWeekDay = nil;
+ if (dateFormatterReadableDateNoWeekDay == nil) {
+ dateFormatterReadableDateNoWeekDay = [[NSDateFormatter alloc] init];
+ dateFormatterReadableDateNoWeekDay.dateFormat = @"d MMM yyyy";
+ dateFormatterReadableDateNoWeekDay.calendar = [NSCalendar gregorian];
+ dateFormatterReadableDateNoWeekDay.locale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en"] autorelease];
+ dateFormatterReadableDateNoWeekDay.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
+ }
+ return [dateFormatterReadableDateNoWeekDay stringFromDate:self];
+}
+
+@end
+
+
+@implementation NSDateFormatter (CalendarHelpers)
+
+// Date formatter to parse NSString representing a basic (no hyphen) calendar date of the form 20100330
+// http://en.wikipedia.org/wiki/ISO_8601#Calendar_dates
++ (NSDateFormatter*) dateFormatterWithFormat:(NSString*)format
+{
+ NSDateFormatter* dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
+ dateFormatter.calendar = [NSCalendar gregorian];
+ dateFormatter.dateFormat = format;
+ dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
+ return dateFormatter;
+}
+
+@end
+
+
+@implementation NSObject (CalendarHelpers)
+
+// Parse an NSString representing an extended (using separators) date and time of the form 2010-03-30T00:00:00
+// http://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations
+- (NSDate*) dateFromStringISO8601DateTimeExtended
+{
+ static NSDateFormatter* dateFormatterISO8601DateTimeExtended = nil;
+ if (dateFormatterISO8601DateTimeExtended == nil) {
+ dateFormatterISO8601DateTimeExtended = [[NSDateFormatter alloc] init];
+ dateFormatterISO8601DateTimeExtended.calendar = [NSCalendar gregorian];
+ dateFormatterISO8601DateTimeExtended.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss";
+ dateFormatterISO8601DateTimeExtended.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
+ }
+
+ if ([self isKindOfClass:[NSString class]]) {
+ return [dateFormatterISO8601DateTimeExtended dateFromString:(NSString*)self];
+ } else {
+ return nil;
+ }
+}
+
+@end
59 Classes/Chart.h
@@ -0,0 +1,59 @@
+//
+// Chart.h
+// Slake
+//
+// Created by Quentin Leseney on 10/05/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import <CoreData/CoreData.h>
+
+@class ChartSeries;
+@class Place;
+
+@interface Chart : NSManagedObject
+{
+}
+
+@property (nonatomic, retain) NSDate* xEnd;
+@property (nonatomic, retain) NSDate* xStart;
+@property (nonatomic, retain) NSNumber* yMax;
+@property (nonatomic, retain) NSNumber* yMin;
+@property (nonatomic, retain) Place* place;
+@property (nonatomic, retain) NSSet* series;
+@property (nonatomic, retain) NSDate* loadDate;
+
+@end
+
+
+@interface Chart (CoreDataGeneratedAccessors)
+- (void)addSeriesObject:(ChartSeries*)value;
+- (void)removeSeriesObject:(ChartSeries*)value;
+- (void)addSeries:(NSSet*)value;
+- (void)removeSeries:(NSSet*)value;
+
+@end
+
45 Classes/Chart.m
@@ -0,0 +1,45 @@
+//
+// Chart.m
+// Slake
+//
+// Created by Quentin Leseney on 10/05/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import "Chart.h"
+#import "Place.h"
+
+@implementation Chart
+
+@dynamic xEnd;
+@dynamic xStart;
+@dynamic yMax;
+@dynamic yMin;
+@dynamic place;
+@dynamic series;
+@dynamic loadDate;
+
+@end
47 Classes/ChartDataset.h
@@ -0,0 +1,47 @@
+//
+// ChartDataset.h
+// Slake
+//
+// Created by Quentin Leseney on 10/05/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import <CoreData/CoreData.h>
+#import "CorePlot-CocoaTouch.h"
+
+@class ChartSeries;
+@class ChartValue;
+
+@interface ChartDataset : NSManagedObject <CPPlotDataSource>
+{
+}
+
+@property (nonatomic, retain) ChartSeries* series;
+
+// An array of ChartValues
+@property (nonatomic, retain) NSArray* values;
+
+@end
66 Classes/ChartDataset.m
@@ -0,0 +1,66 @@
+//
+// ChartDataset.m
+// Slake
+//
+// Created by Quentin Leseney on 10/05/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import "ChartDataset.h"
+#import "Place.h"
+
+@implementation ChartDataset
+
+@dynamic series;
+@dynamic values;
+
+-(NSUInteger)numberOfRecordsForPlot:(CPPlot *)plot
+{
+ return self.values.count;
+}
+
+
+-(NSArray*)numbersForPlot:(CPPlot*)plot field:(NSUInteger)fieldEnum
+ recordIndexRange:(NSRange)indexRange
+{
+ NSAssert(indexRange.location == 0 && indexRange.length == self.values.count, @"ChartDataSet: incorrect indexRange requested");
+
+ NSArray* result;
+ if(fieldEnum == CPScatterPlotFieldX)
+ {
+ result = [self.values valueForKey:@"dayInYear"];
+ //result = [fetchedObjects valueForKey:@"timeIntervalInReferenceYear"]; //uncomment to use interval
+ }
+ else
+ {
+ //CPScatterPlotFieldY
+ result = [self.values valueForKey: @"percentage"];
+ }
+ return result;
+}
+
+
+@end
42 Classes/ChartLoader.h
@@ -0,0 +1,42 @@
+//
+// ChartLoader.h
+// Slake
+//
+// Created by Ben Williamson on 8/06/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import <Foundation/Foundation.h>
+#import "DataLoader.h"
+
+@interface ChartLoader : DataLoader
+{
+ NSManagedObjectID* _placeID;
+}
+
+- (id)initWithPlaceID:(NSManagedObjectID *)placeID;
+
+@end
108 Classes/ChartLoader.m
@@ -0,0 +1,108 @@
+//
+// ChartLoader.m
+// Slake
+//
+// Created by Ben Williamson on 8/06/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import "ChartLoader.h"
+#import "ChartParser.h"
+#import "Place.h"
+#import "NSManagedObjectContext+Helpers.h"
+
+
+@interface ChartLoader () // private
+
+@property (nonatomic, retain) NSManagedObjectID* placeID;
+
+@end
+
+
+@implementation ChartLoader
+
+@synthesize placeID = _placeID;
+
+
+- (void)dealloc
+{
+ [_placeID release];
+ [super dealloc];
+}
+
+- (id)initWithPlaceID:(NSManagedObjectID*)placeID
+{
+ assert(![placeID isTemporaryID]);
+ if ((self = [super init])) {
+ self.placeID = placeID;
+ }
+ return self;
+}
+
+- (NSString*)resourcePath
+{
+ Place* place = (Place*)[self.context objectWithID:self.placeID];
+ return [@"resources/xmlchart/" stringByAppendingString:place.urn];
+}
+
+- (BOOL)shouldContinueWithStatusCode:(NSInteger)statusCode
+{
+ switch (statusCode) {
+ case 200:
+ return YES;
+
+ case 204:
+ case 404:
+ {
+ Place* place = (Place*)[self.context objectWithID:self.placeID];
+ if (place.chart)
+ {
+ [self.context deleteObject:place.chart];
+ [self.context saveAndLogErrors];
+ }
+ return NO;
+ }
+
+ case 500:
+ return NO;
+
+ default:
+ // Ever hopeful
+ return YES;
+ }
+}
+
+- (DataParser*)makeParser
+{
+ Place* place = (Place*)[self.context objectWithID:self.placeID];
+ return [[[ChartParser alloc] initWithPlace:place context:self.context] autorelease];
+}
+
+- (void)didFinishLoading
+{
+}
+
+@end
69 Classes/ChartParser.h
@@ -0,0 +1,69 @@
+//
+// ChartParser.h
+// Slake
+//
+// Created by Quentin Leseney on 11/05/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This parser reads an XML file representing data values for dates.
+// The structure is a chart contains a number of series, each series containing values for a year.
+// A series can be decomposed in datasets containing values for contiguous days.
+//
+// Specifities:
+// * The XML structure defined that values are reported for regular intervals.
+// This parser requires that the interval is one day.
+// * Each series must contain values that are only in the same year
+// * Because year series are viewed stacked on a horizontal axis ranging from 1 Jan to 31 Dec and
+// some years are leap years, the output model contains 366 values for any year,
+// where the value for 28 Feb is duplicated to fill in the 29 Feb gap.
+// * If some data values are incorrect, gaps can result within a parsed dataset.
+// In that case new datasets are created in the output model keep day contiguity.
+// * Percentages used in the output model for a value are the value divided by the chart yMax value
+
+#import "Chart.h"
+#import "DataParser.h"
+#import "ChartSeries.h"
+#import "ChartDataset.h"
+
+@class ChartParser;
+@class Place;
+
+@interface ChartParser : DataParser
+{
+@private
+ Place* _place;
+ NSDateFormatter* _dateFormatter;
+ NSNumberFormatter* _numberFormatter;
+ Chart* _chart;
+ ChartSeries* _currentSeries;
+ int _currentDayInYear;
+ BOOL _incorrectValueInDataset;
+ NSMutableArray* _values; // Array of ChartValues
+}
+
+- (id)initWithPlace:(Place*)place context:(NSManagedObjectContext*)context;
+
+@end
357 Classes/ChartParser.m
@@ -0,0 +1,357 @@
+//
+// ChartParser.m
+// Slake
+//
+// Created by Quentin Leseney on 11/05/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import "ChartParser.h"
+#import "Chart.h"
+#import "ChartSeries.h"
+#import "ChartDataset.h"
+#import "ChartValue.h"
+#import "Place.h"
+#import "Observation.h"
+#import "Measurement.h"
+#import "NSManagedObjectContext+Helpers.h"
+#import "CalendarHelpers.h"
+
+
+@interface ChartParser () // private
+
+@property (nonatomic, retain) Place* place;
+
+@property (nonatomic, retain) NSDateFormatter* dateFormatter;
+@property (nonatomic, retain) NSNumberFormatter* numberFormatter;
+@property (nonatomic, retain) Chart* chart;
+@property (nonatomic, retain) ChartSeries* currentSeries;
+@property (nonatomic) int currentDayInYear; // 0 when start date not set
+@property (nonatomic) BOOL incorrectValueInDataset;// when gap potentially required the creation a new dataset
+@property (nonatomic, retain) NSMutableArray* values; // current dataset values
+
+- (NSDate*)dateFromString:(NSString*)string;
+- (NSNumber*)numberFromString:(NSString*)string;
+
+@end
+
+
+@implementation ChartParser
+
+@synthesize place = _place;
+@synthesize dateFormatter = _dateFormatter;
+@synthesize numberFormatter = _numberFormatter;
+@synthesize chart = _chart;
+@synthesize currentSeries = _currentSeries;
+@synthesize currentDayInYear = _currentDayInYear;
+@synthesize incorrectValueInDataset = _incorrectValueInDataset;
+@synthesize values = _values;
+
+- (void)dealloc
+{
+ [_place release];
+ [_dateFormatter release];
+ [_numberFormatter release];
+ [_chart release];
+ [_currentSeries release];
+ [_values release];
+ [super dealloc];
+}
+
+- (id)initWithPlace:(Place*)place context:(NSManagedObjectContext*)context
+{
+ if ((self = [super initWithContext:context])) {
+ self.place = place;
+
+ self.numberFormatter = [[[NSNumberFormatter alloc] init] autorelease];
+ self.numberFormatter.numberStyle = NSNumberFormatterDecimalStyle;
+ //parse . as decimal separator, regardless of default locale
+ self.numberFormatter.locale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en"] autorelease];
+ self.currentDayInYear = 0;
+
+ [self setStartCallback:@selector(startChart:) forElement:@"chart"];
+ [self setCompleteCallback:@selector(gotChart:) forElement:@"chart"];
+ [self setCompleteCallback:@selector(gotConfiguration:) forElement:@"configuration"];
+ [self setStartCallback:@selector(startSeries:) forElement:@"series"];
+ [self setCompleteCallback:@selector(gotSeries:) forElement:@"series"];
+ [self setStartCallback:@selector(startDataset:) forElement:@"dataset"];
+ [self setCompleteCallback:@selector(gotDataset:) forElement:@"dataset"];
+ [self setCompleteCallback:@selector(gotStartDate:) forElement:@"startdate"];
+ [self setCompleteCallback:@selector(gotRecord:) forElement:@"record"];
+ }
+ return self;
+}
+
+// Robust against "string" argument that is not actually an NSString.
+- (NSDate*)dateFromString:(NSString*)string
+{
+ if ([string isKindOfClass:[NSString class]]) {
+ return [self.dateFormatter dateFromString:string];
+ } else {
+ return nil;
+ }
+}
+
+// Robust against "string" argument that is not actually an NSString.
+- (NSNumber*)numberFromString:(NSString*)string
+{
+ if ([string isKindOfClass:[NSString class]]) {
+ return [self.numberFormatter numberFromString:string];
+ } else {
+ return nil;
+ }
+}
+
+#pragma mark XML file example
+
+/*
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<chart>
+ <configuration>
+ <dateformat>yyyyMMdd</dateformat>
+ <yAxisLabel>Stored Volume (ML)</yAxisLabel>
+ <xStart>20100301</xStart>
+ <xEnd>20100511</xEnd>
+ <yMin>0</yMin>
+ <yMax>1094839</yMax>
+ </configuration>
+ <series>
+ <name>2010</name>
+ <interval>
+ <unit>day</unit>
+ <value>1</value>
+ </interval>
+ <dataset>
+ <startdate>20100301</startdate>
+ <record>24014.112</record>
+ <record>23924.32</record>
+ </dataset>
+ <dataset>
+ <startdate>20100323</startdate>
+ <record>227077.5</record>
+ <record>227188.2</record>
+ <record>227253.2</record>
+ <record>227271.7</record>
+ <record>106.061</record>
+ </dataset>
+ </series>
+ <series>
+ <name>2009</name>
+ <interval>
+ <unit>day</unit>
+ <value>1</value>
+ </interval>
+ </series>
+</chart>
+*/
+
+
+#pragma mark XMLStreamParser callbacks
+
+- (void)startChart:(NSString*)elementName
+{
+ self.chart = [NSEntityDescription
+ insertNewObjectForEntityForName:@"Chart"
+ inManagedObjectContext:self.context];
+}
+
+- (void)gotConfiguration:(id)element
+{
+ NSString* dateformat = [element objectForKey:@"dateformat"];
+ if ([dateformat isKindOfClass:[NSString class]]) {
+ self.dateFormatter = [NSDateFormatter dateFormatterWithFormat:dateformat];
+ }
+ else {
+ self.dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"yyyyMMdd"];
+ }
+
+ self.chart.xStart = [self dateFromString:[element objectForKey:@"xStart"]];
+ self.chart.xEnd = [self dateFromString:[element objectForKey:@"xEnd"]];
+ self.chart.yMin = [self numberFromString:[element objectForKey:@"yMin"]];
+ self.chart.yMax = [self numberFromString:[element objectForKey:@"yMax"]];
+ NSString* yAxislabel = [element objectForKey:@"yAxisLabel"];
+ NSString* unit = self.place.obsCurrent.capacity.unit;
+ if (unit && [yAxislabel rangeOfString:unit].location == NSNotFound)
+ {
+ NSLog(@"Warning: Unit of capacity in observation (%@) not found in chart y axis label \"%@\", values may be inconsistent", unit, yAxislabel);
+ }
+}
+
+- (void)startSeries:(NSString*)elementName
+{
+ if (!self.chart) {
+ NSLog(@"Malformed XML chart: found <series> tag outside <chart>");
+ } else if (!self.dateFormatter) {
+ NSLog(@"Malformed XML chart: found <series> tag but no configuration has been found");
+ } else {
+ if (self.currentSeries) {
+ NSLog(@"Malformed XML chart: found starting <series> tag while previous series missing closing </series> tag");
+ [self.context deleteObject:self.currentSeries];
+ self.values = nil;
+ self.currentDayInYear = 0;
+ }
+ self.currentSeries = [NSEntityDescription
+ insertNewObjectForEntityForName:@"ChartSeries"
+ inManagedObjectContext:self.context];
+ }
+}
+
+- (void)gotSeries:(id)element
+{
+ //unused [element objectForKey:@"title"]
+ if (!self.currentSeries) {
+ NSLog(@"Malformed XML chart: found closing </series> tag without matching starting <series> tag");
+ } else if (![element isKindOfClass:[NSDictionary class]]) {
+ NSLog(@"Malformed XML chart: no <interval> defined in series");
+ [self.context deleteObject:self.currentSeries];
+ } else {
+ NSDictionary* interval = [element objectForKey:@"interval"];
+ if (![interval isKindOfClass:[NSDictionary class]]) {
+ NSLog(@"Malformed XML chart: incorrect <interval> structure");
+ [self.context deleteObject:self.currentSeries];
+ } else {
+ NSString* unit = [interval objectForKey:@"unit"];
+ NSNumber* value = [self numberFromString:[interval objectForKey:@"value"]];
+ if (![unit isKindOfClass:[NSString class]] ||
+ ![unit isEqualToString:@"day"] ||
+ ![value isKindOfClass:[NSNumber class]] ||
+ ![value isEqualToNumber:[NSNumber numberWithInt:1]])
+ {
+ NSLog(@"Malformed XML chart: incorrect <interval> structure, expecting 1-day interval");
+ [self.context deleteObject:self.currentSeries];
+ } else {
+ [self.chart addSeriesObject:self.currentSeries];
+ }
+ }
+ }
+ self.currentSeries = nil;
+}
+
+- (void)startDataset:(NSString*)elementName
+{
+ self.values = [[[NSMutableArray alloc] init] autorelease];
+ self.incorrectValueInDataset = NO;
+}
+
+- (void)gotDataset:(id)element
+{
+ if (self.currentSeries) {
+ ChartDataset* dataset = [NSEntityDescription
+ insertNewObjectForEntityForName:@"ChartDataset"
+ inManagedObjectContext:self.context];
+ dataset.values = self.values;
+ self.values = nil;
+ self.currentDayInYear = 0;
+ [self.currentSeries addDatasetsObject:dataset];
+ }
+}
+
+- (void)gotStartDate:(id)element
+{
+ if (!self.chart || !self.currentSeries || self.currentDayInYear != 0)
+ {
+ NSLog(@"Malformed XML chart: unexpected <startDate> tag");
+ } else {
+ NSDate* date = [self dateFromString:element];
+ NSCalendar* gregorian = [NSCalendar gregorian];
+ int year = [[gregorian components:NSYearCalendarUnit fromDate:date] year];
+ int day = [gregorian ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:date];
+ if (self.currentDayInYear >= 31 + 28 + 1 && ![NSCalendar isLeapYear:[self.currentSeries.year intValue]]) {
+ day++;
+ }
+ self.currentDayInYear = day;
+ if (self.currentSeries.year && year != [self.currentSeries.year intValue]) {
+ NSLog(@"Malformed XML chart: incorrect year for <startDate> in series");
+ self.currentDayInYear = 0;
+ } else {
+ self.currentSeries.year = [NSNumber numberWithInt:year];
+ }
+ }
+}
+
+- (void)gotRecord:(id)element
+{
+ if (!self.chart || !self.currentSeries) {
+ NSLog(@"Malformed XML chart: unexpected <record> tag");
+ } else if (self.currentDayInYear == 0) {
+ NSLog(@"Malformed XML chart: <record> found without startDate set");
+ } else if (self.values && self.chart.yMax) {
+ NSNumber* number = [self numberFromString:element];
+ //only add correct values
+ if (number) {
+ ChartValue* value = [[[ChartValue alloc] init] autorelease];
+ value.dayInYear = self.currentDayInYear;
+ value.value = [number doubleValue];
+ double yMax = [self.chart.yMax doubleValue];
+ value.percentage = (yMax == 0.0) ? 0.0 : value.value / yMax;
+ if (self.incorrectValueInDataset) {
+ //if incorrect value found, start a new dataset to keep day contiguity
+ ChartDataset* dataset = [NSEntityDescription
+ insertNewObjectForEntityForName:@"ChartDataset"
+ inManagedObjectContext:self.context];
+ dataset.values = self.values;
+ [self.currentSeries addDatasetsObject:dataset];
+ self.values = [[[NSMutableArray alloc] init] autorelease];
+ self.incorrectValueInDataset = NO;
+ }
+ [self.values addObject:value];
+ } else {
+ //only deal with it only if more values in this dataset
+ self.incorrectValueInDataset = YES;
+ }
+ self.currentDayInYear++;
+ if (self.currentDayInYear == 31 + 28 + 1 && ![NSCalendar isLeapYear:[self.currentSeries.year intValue]]) {
+ //add the 28 Feb value again to fill in the gap
+ [self gotRecord:element];
+ }
+ }
+}
+
+- (void)gotChart:(id)element
+{
+ if (!self.chart)
+ {
+ NSLog(@"Malformed XML chart: unexpected closing </chart> tag");
+ } else {
+ self.chart.loadDate = [NSDate date];
+
+ Chart* oldChart = self.place.chart;
+ if (oldChart) {
+ [self.context deleteObject:oldChart];
+ }
+ self.place.chart = self.chart;
+ [self.context saveAndLogErrors];
+
+ self.place = nil;
+ self.chart = nil;
+ self.currentSeries = nil;
+ self.values = nil;
+ self.dateFormatter = nil;
+ self.numberFormatter = nil;
+ }
+}
+
+@end
46 Classes/ChartRequest.h
@@ -0,0 +1,46 @@
+//
+// ChartRequest.h
+// Slake
+//
+// Created by Ben Williamson on 31/05/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import <Foundation/Foundation.h>
+#import "DataRequest.h"
+
+@class Place;
+
+@interface ChartRequest : DataRequest
+{
+ Place* place;
+}
+
+@property (nonatomic, retain) Place* place;
+
++ (ChartRequest*)chartRequestForPlace:(Place*)place force:(BOOL)force;
+
+@end
106 Classes/ChartRequest.m
@@ -0,0 +1,106 @@
+//
+// ChartRequest.m
+// Slake
+//
+// Created by Ben Williamson on 31/05/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import "ChartRequest.h"
+#import "ChartLoader.h"
+#import "Place.h"
+#import "Chart.h"
+#import "DataManager.h"
+
+
+@implementation ChartRequest
+
+@synthesize place;
+
+- (void)dealloc
+{
+ [place release];
+ [super dealloc];
+}
+
+- (DataLoader*)makeLoader
+{
+ return [[[ChartLoader alloc] initWithPlaceID:[self.place objectID]] autorelease];
+}
+
+- (BOOL)isSatisfied
+{
+ NSDate* date = self.place.chart.loadDate;
+ if (self.isForceLoad) {
+ // Force load is satisfied if loaded since the request was made
+ return NSOrderedAscending == [self.requestDate compare:date];
+ } else {
+ // Unforced load is satisfied if it was loaded "recently enough"
+ return [DataManager dateIsRecentEnough:date];
+ }
+}
+
+- (BOOL)isClearable
+{
+ return YES;
+}
+
+- (BOOL)isEqual:(id)other
+{
+ if (other == self) {
+ return YES;
+ }
+ return [other isMemberOfClass:[ChartRequest class]]
+ && [other place] == self.place
+ && [other isForceLoad] == [self isForceLoad];
+}
+
+- (NSUInteger)hash
+{
+ int prime = 31;
+ int result = 1;
+ result = prime * result + [self.place hash];
+ result = prime * result + self.isForceLoad ? 12 : 34;
+ return result;
+}
+
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"%@chart for %@",
+ self.isForceLoad ? @"forced " : @"",
+ self.place.longName];
+}
+
++ (ChartRequest*)chartRequestForPlace:(Place*)place force:(BOOL)force;
+{
+ assert([NSThread isMainThread]);
+ ChartRequest* request = [[[ChartRequest alloc] init] autorelease];
+ request.place = place;
+ request.isForceLoad = force;
+ return request;
+}
+
+@end
59 Classes/ChartSeries.h
@@ -0,0 +1,59 @@
+//
+// ChartSeries.h
+// Slake
+//
+// Created by Quentin Leseney on 10/05/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import <CoreData/CoreData.h>
+
+@class ChartDataset;
+@class Chart;
+@class ChartValue;
+
+@interface ChartSeries : NSManagedObject
+{
+ NSNumber* _leapYear;
+}
+
+@property (nonatomic, retain) NSNumber* year;
+@property (nonatomic, retain) NSSet* datasets;
+@property (nonatomic, retain) Chart* chart;
+
+- (ChartValue*)getValueForDayInYear:(int)day;
+
+@end
+
+
+@interface ChartSeries (CoreDataGeneratedAccessors)
+- (void)addDatasetsObject:(ChartDataset*)value;
+- (void)removeDatasetsObject:(ChartDataset*)value;
+- (void)addDatasets:(NSSet*)value;
+- (void)removeDatasets:(NSSet*)value;
+
+@end
+
67 Classes/ChartSeries.m
@@ -0,0 +1,67 @@
+//
+// ChartSeries.m
+// Slake
+//
+// Created by Quentin Leseney on 10/05/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import "ChartSeries.h"
+#import "ChartDataset.h"
+#import "ChartValue.h"
+
+@implementation ChartSeries
+
+@dynamic year;
+@dynamic datasets;
+@dynamic chart;
+
+-(void)dealloc
+{
+ [_leapYear release];
+ [super dealloc];
+}
+
+- (ChartValue*)getValueForDayInYear:(int)day
+{
+ ChartValue* result = nil;
+ for (ChartDataset* set in self.datasets)
+ {
+ if ([set.values count] > 0)
+ {
+ int startDay = ((ChartValue*)[set.values objectAtIndex:0]).dayInYear;
+ if (day >= startDay && day < startDay + [set.values count])
+ {
+ result = [set.values objectAtIndex:day - startDay];
+ NSAssert(result.dayInYear == day, @"result.dayInYear != day in ChartSeries getValueForDayInYear:(int)day");
+ return result;
+ }
+ }
+ }
+ return nil;
+}
+
+@end
48 Classes/ChartValue.h
@@ -0,0 +1,48 @@
+//
+// ChartValue.h
+// Slake
+//
+// Created by Quentin Leseney on 10/05/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+@class ChartDataset;
+
+@interface ChartValue : NSObject <NSCoding>
+{
+ int dayInYear;
+ double value;
+ float percentage;
+}
+
+// The day in [1, 366]. If the year is non-leap, for each day after 28 Feb,
+// it is actually the (day-1)nth day in year so that leap and non-leap years are stacked.
+// For instance, the value for 28 Feb is returned both for day 59 (28 Feb) and day 60
+@property (nonatomic) int dayInYear;
+@property (nonatomic) double value;
+@property (nonatomic) float percentage;
+
+@end
62 Classes/ChartValue.m
@@ -0,0 +1,62 @@
+//
+// ChartValue.m
+// Slake
+//
+// Created by Quentin Leseney on 10/05/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import "ChartValue.h"
+
+@implementation ChartValue
+
+@synthesize dayInYear;
+@synthesize value;
+@synthesize percentage;
+
+- (void)dealloc
+{
+ [super dealloc];
+}
+
+- (id)initWithCoder:(NSCoder*)decoder
+{
+ if ((self = [super init])) {
+ self.dayInYear = [decoder decodeIntForKey:@"dayInYear"];
+ self.value = [decoder decodeDoubleForKey:@"value"];
+ self.percentage = [decoder decodeFloatForKey:@"percentage"];
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder*)encoder
+{
+ [encoder encodeInt:self.dayInYear forKey:@"dayInYear"];
+ [encoder encodeDouble:self.value forKey:@"value"];
+ [encoder encodeFloat:self.percentage forKey:@"percentage"];
+}
+
+@end
92 Classes/ChartViewController.h
@@ -0,0 +1,92 @@
+//
+// ChartViewController.h
+// Slake
+//
+// Created by Ben Williamson on 4/05/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import <UIKit/UIKit.h>
+#import "CorePlot-CocoaTouch.h"
+
+@class Place;
+@class Chart;
+@class ChartValue;
+@class Measurement;
+
+@protocol MarkerLabelDelegate
+
+- (void)showLabelsCurrentYearDate:(NSDate*)date
+ currentYearPercentage:(Measurement*)currentYearPercentage
+ currentYearVolume:(Measurement*)currentYearVolume
+ lastYearDate:(NSDate*)date
+ lastYearPercentage:(Measurement*)lastYearPercentage
+ lastYearVolume:(Measurement*)lastYearVolume
+ awayFrom:(float)viewXPosition;
+
+- (void)hideLabels;
+
+@end
+
+//notify chart values changes for any rendering
+@protocol ChartDelegate
+
+- (void)chartUpdated;
+
+@end
+
+
+@interface ChartViewController : UIViewController <CPPlotSpaceDelegate, CPPlotDataSource>
+{
+ CPXYGraph* graph;
+ Place* place;
+ Chart* _chart; // not retained
+ //marker
+ CPScatterPlot* _markerPlot;
+ id <MarkerLabelDelegate> _markerLabelDelegate;
+ id <ChartDelegate> _chartDelegate;
+ int _xCoordinate;
+ float _viewXPosition;
+ NSNumber* _currentYearYCoordinate;
+ NSNumber* _lastYearYCoordinate;
+}
+
+@property (nonatomic, retain) Place* place;
+@property (nonatomic, assign) id <MarkerLabelDelegate> markerLabelDelegate;
+@property (nonatomic, assign) id <ChartDelegate> chartDelegate;
+
+// To be called once the nib containing the chart controller and its view has been loaded.
+// Typically when the superview did load.
+- (void)linkGraphToHostedLayer;
+
+// To be called on parent's view controller viewDidLoad
+-(void)setXAxisSetTickLocations:(NSSet*)locations;
+-(void)setYAxisSetTickLocations:(NSSet*)locations;
+-(void)setXAxisRangeFrom:(float)start length:(float)length;
+
+-(CGPoint)viewCoordinatesForChartPoint:(NSDecimal*)chartPoint;
+
+@end
591 Classes/ChartViewController.m
@@ -0,0 +1,591 @@
+//
+// ChartViewController.m
+// Slake
+//
+// Created by Ben Williamson on 4/05/10.
+//
+// Copyright (c) 2010 Bureau of Meteorology
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import "ChartViewController.h"
+#import "Chart.h"
+#import "ChartSeries.h"
+#import "ChartDataset.h"
+#import "ChartValue.h"
+#import "Measurement.h"
+#import "Place.h"
+#import "Observation.h"
+#import "CalendarHelpers.h"
+
+@interface ChartViewController () // private
+
+@property (nonatomic, retain) CPXYGraph* graph;
+@property (nonatomic, retain) CPScatterPlot* markerPlot;
+//marker
+@property (nonatomic) int xCoordinate;
+@property (nonatomic) float viewXPosition;
+@property (nonatomic, retain) NSNumber* currentYearYCoordinate;
+@property (nonatomic, retain) NSNumber* lastYearYCoordinate;
+
+- (void)updateChart:(Chart*)chart;
+
+- (void)createPlotSpace;
+
+@end
+
+
+@implementation ChartViewController
+
+@synthesize graph;
+@synthesize markerPlot = _markerPlot;
+@synthesize xCoordinate = _xCoordinate;
+@synthesize viewXPosition = _viewXPosition;
+@synthesize currentYearYCoordinate = _currentYearYCoordinate;
+@synthesize lastYearYCoordinate = _lastYearYCoordinate;
+@synthesize chartDelegate = _chartDelegate;
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [graph release];
+ [place release];
+ [_markerPlot release];
+ [_currentYearYCoordinate release];
+ [_lastYearYCoordinate release];
+ [super dealloc];
+}
+
+
+- (void)setPlace:(Place *)newPlace
+{
+ if (newPlace != place)
+ {
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextObjectsDidChangeNotification object:[place managedObjectContext]];
+ [place release];
+ place = [newPlace retain];
+ _chart = place.chart;
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(objectsDidChangeNotification:) name:NSManagedObjectContextObjectsDidChangeNotification object:[place managedObjectContext]];
+ }
+}
+
+
+- (Place*)place
+{
+ return place;
+}
+
+
+- (void)viewDidUnload
+{
+ // Release any retained subviews of the main view.
+ // e.g. self.myOutlet = nil;
+ self.graph = nil;
+ self.markerPlot = nil;
+ self.currentYearYCoordinate = nil;
+ self.lastYearYCoordinate = nil;
+}<