Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'overviewer'

  • Loading branch information...
commit ffd56ee4fad6ac727de692d6295d7cd8ae0e46a9 2 parents 3cc5223 + c08fe94
@jverkoey jverkoey authored
Showing with 3,708 additions and 57 deletions.
  1. +1 −1  docs/Doxyfile
  2. BIN  docs/gfx/overview-disk1.png
  3. BIN  docs/gfx/overview-log1.png
  4. BIN  docs/gfx/overview-maxloglevel1.png
  5. BIN  docs/gfx/overview-memory1.png
  6. BIN  docs/gfx/overview-memorywarning1.png
  7. BIN  docs/gfx/overview1.png
  8. +56 −0 examples/photos/NetworkPhotoAlbums/NetworkPhotoAlbum.xcodeproj/project.pbxproj
  9. +7 −6 examples/photos/NetworkPhotoAlbums/src/AppDelegate.m
  10. +1 −0  examples/photos/NetworkPhotoAlbums/src/DribbblePhotoAlbumViewController.m
  11. +1 −0  examples/photos/NetworkPhotoAlbums/src/FacebookPhotoAlbumViewController.m
  12. +1 −1  examples/photos/NetworkPhotoAlbums/src/NetworkPhotoAlbumViewController.m
  13. +3 −2 examples/photos/NetworkPhotoAlbums/src/NetworkPhotoAlbum_Prefix.pch
  14. +84 −0 src/Doxygen.h
  15. +14 −0 src/core/src/NICommonMetrics.h
  16. +12 −0 src/core/src/NICommonMetrics.m
  17. +14 −0 src/core/src/NIDataStructures.h
  18. +71 −0 src/core/src/NIDataStructures.m
  19. +19 −0 src/core/unittests/NIDataStructureTests.m
  20. +5 −7 src/networkimage/src/NINetworkImageView.m
  21. +361 −0 src/overview/NimbusOverview.xcodeproj/project.pbxproj
  22. +20 −0 src/overview/lib/NimbusOverview_Prefix.pch
  23. BIN  src/overview/resources/NimbusOverviewer.bundle/gfx/blueprint.gif
  24. +122 −0 src/overview/src/NIDeviceInfo.h
  25. +203 −0 src/overview/src/NIDeviceInfo.m
  26. +95 −0 src/overview/src/NIOverview.h
  27. +381 −0 src/overview/src/NIOverview.m
  28. +80 −0 src/overview/src/NIOverviewGraphView.h
  29. +124 −0 src/overview/src/NIOverviewGraphView.m
  30. +249 −0 src/overview/src/NIOverviewLogger.h
  31. +186 −0 src/overview/src/NIOverviewLogger.m
  32. +168 −0 src/overview/src/NIOverviewPageView.h
  33. +731 −0 src/overview/src/NIOverviewPageView.m
  34. +33 −0 src/overview/src/NIOverviewSwizzling.h
  35. +174 −0 src/overview/src/NIOverviewSwizzling.m
  36. +59 −0 src/overview/src/NIOverviewView.h
  37. +211 −0 src/overview/src/NIOverviewView.m
  38. +150 −0 src/overview/src/NimbusOverview.h
  39. +72 −40 src/photos/src/NIToolbarPhotoViewController.m
View
2  docs/Doxyfile
@@ -31,7 +31,7 @@ PROJECT_NAME = Nimbus
# This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER = 0.4.1.0
+PROJECT_NUMBER = 0.5.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer
View
BIN  docs/gfx/overview-disk1.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  docs/gfx/overview-log1.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  docs/gfx/overview-maxloglevel1.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  docs/gfx/overview-memory1.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  docs/gfx/overview-memorywarning1.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  docs/gfx/overview1.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
56 examples/photos/NetworkPhotoAlbums/NetworkPhotoAlbum.xcodeproj/project.pbxproj
@@ -13,6 +13,14 @@
6631671713D680A500FF0CBE /* NetworkPhotoAlbumViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6631671613D680A500FF0CBE /* NetworkPhotoAlbumViewController.m */; };
6631673613D6825800FF0CBE /* CatalogTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6631673513D6825800FF0CBE /* CatalogTableViewController.m */; };
6631680D13D6891F00FF0CBE /* DribbblePhotoAlbumViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6631680C13D6891F00FF0CBE /* DribbblePhotoAlbumViewController.m */; };
+ 66409FA013E25C5300E9BA5A /* NIDeviceInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 66409F9213E25C5300E9BA5A /* NIDeviceInfo.m */; };
+ 66409FA113E25C5300E9BA5A /* NIOverview.m in Sources */ = {isa = PBXBuildFile; fileRef = 66409F9513E25C5300E9BA5A /* NIOverview.m */; };
+ 66409FA213E25C5300E9BA5A /* NIOverviewGraphView.m in Sources */ = {isa = PBXBuildFile; fileRef = 66409F9713E25C5300E9BA5A /* NIOverviewGraphView.m */; };
+ 66409FA313E25C5300E9BA5A /* NIOverviewLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 66409F9913E25C5300E9BA5A /* NIOverviewLogger.m */; };
+ 66409FA413E25C5300E9BA5A /* NIOverviewPageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 66409F9B13E25C5300E9BA5A /* NIOverviewPageView.m */; };
+ 66409FA513E25C5300E9BA5A /* NIOverviewSwizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = 66409F9D13E25C5300E9BA5A /* NIOverviewSwizzling.m */; };
+ 66409FA613E25C5300E9BA5A /* NIOverviewView.m in Sources */ = {isa = PBXBuildFile; fileRef = 66409F9F13E25C5300E9BA5A /* NIOverviewView.m */; };
+ 66409FA813E25C5E00E9BA5A /* NimbusOverviewer.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 66409FA713E25C5E00E9BA5A /* NimbusOverviewer.bundle */; };
665E0BB713CE815D008A1D21 /* NIDataStructures.m in Sources */ = {isa = PBXBuildFile; fileRef = 665E0B9913CE815D008A1D21 /* NIDataStructures.m */; };
665E0BB813CE815D008A1D21 /* NIDebuggingTools.m in Sources */ = {isa = PBXBuildFile; fileRef = 665E0B9B13CE815D008A1D21 /* NIDebuggingTools.m */; };
665E0BB913CE815D008A1D21 /* NIDeviceOrientation.m in Sources */ = {isa = PBXBuildFile; fileRef = 665E0B9D13CE815D008A1D21 /* NIDeviceOrientation.m */; };
@@ -67,6 +75,22 @@
6631673513D6825800FF0CBE /* CatalogTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CatalogTableViewController.m; path = src/CatalogTableViewController.m; sourceTree = "<group>"; };
6631680B13D6891F00FF0CBE /* DribbblePhotoAlbumViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DribbblePhotoAlbumViewController.h; path = src/DribbblePhotoAlbumViewController.h; sourceTree = "<group>"; };
6631680C13D6891F00FF0CBE /* DribbblePhotoAlbumViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DribbblePhotoAlbumViewController.m; path = src/DribbblePhotoAlbumViewController.m; sourceTree = "<group>"; };
+ 66409F9113E25C5300E9BA5A /* NIDeviceInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIDeviceInfo.h; path = ../../../src/overview/src/NIDeviceInfo.h; sourceTree = "<group>"; };
+ 66409F9213E25C5300E9BA5A /* NIDeviceInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIDeviceInfo.m; path = ../../../src/overview/src/NIDeviceInfo.m; sourceTree = "<group>"; };
+ 66409F9313E25C5300E9BA5A /* NimbusOverview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NimbusOverview.h; path = ../../../src/overview/src/NimbusOverview.h; sourceTree = "<group>"; };
+ 66409F9413E25C5300E9BA5A /* NIOverview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIOverview.h; path = ../../../src/overview/src/NIOverview.h; sourceTree = "<group>"; };
+ 66409F9513E25C5300E9BA5A /* NIOverview.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIOverview.m; path = ../../../src/overview/src/NIOverview.m; sourceTree = "<group>"; };
+ 66409F9613E25C5300E9BA5A /* NIOverviewGraphView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIOverviewGraphView.h; path = ../../../src/overview/src/NIOverviewGraphView.h; sourceTree = "<group>"; };
+ 66409F9713E25C5300E9BA5A /* NIOverviewGraphView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIOverviewGraphView.m; path = ../../../src/overview/src/NIOverviewGraphView.m; sourceTree = "<group>"; };
+ 66409F9813E25C5300E9BA5A /* NIOverviewLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIOverviewLogger.h; path = ../../../src/overview/src/NIOverviewLogger.h; sourceTree = "<group>"; };
+ 66409F9913E25C5300E9BA5A /* NIOverviewLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIOverviewLogger.m; path = ../../../src/overview/src/NIOverviewLogger.m; sourceTree = "<group>"; };
+ 66409F9A13E25C5300E9BA5A /* NIOverviewPageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIOverviewPageView.h; path = ../../../src/overview/src/NIOverviewPageView.h; sourceTree = "<group>"; };
+ 66409F9B13E25C5300E9BA5A /* NIOverviewPageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIOverviewPageView.m; path = ../../../src/overview/src/NIOverviewPageView.m; sourceTree = "<group>"; };
+ 66409F9C13E25C5300E9BA5A /* NIOverviewSwizzling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIOverviewSwizzling.h; path = ../../../src/overview/src/NIOverviewSwizzling.h; sourceTree = "<group>"; };
+ 66409F9D13E25C5300E9BA5A /* NIOverviewSwizzling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIOverviewSwizzling.m; path = ../../../src/overview/src/NIOverviewSwizzling.m; sourceTree = "<group>"; };
+ 66409F9E13E25C5300E9BA5A /* NIOverviewView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIOverviewView.h; path = ../../../src/overview/src/NIOverviewView.h; sourceTree = "<group>"; };
+ 66409F9F13E25C5300E9BA5A /* NIOverviewView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIOverviewView.m; path = ../../../src/overview/src/NIOverviewView.m; sourceTree = "<group>"; };
+ 66409FA713E25C5E00E9BA5A /* NimbusOverviewer.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = NimbusOverviewer.bundle; path = ../../../src/overview/resources/NimbusOverviewer.bundle; sourceTree = "<group>"; };
665E0B9713CE815D008A1D21 /* NIBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIBlocks.h; path = ../../../src/core/src/NIBlocks.h; sourceTree = SOURCE_ROOT; };
665E0B9813CE815D008A1D21 /* NIDataStructures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIDataStructures.h; path = ../../../src/core/src/NIDataStructures.h; sourceTree = SOURCE_ROOT; };
665E0B9913CE815D008A1D21 /* NIDataStructures.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIDataStructures.m; path = ../../../src/core/src/NIDataStructures.m; sourceTree = SOURCE_ROOT; };
@@ -361,6 +385,28 @@
name = Processors;
sourceTree = "<group>";
};
+ 66C52CC313DAA79E00D6BA6F /* Overview */ = {
+ isa = PBXGroup;
+ children = (
+ 66409F9113E25C5300E9BA5A /* NIDeviceInfo.h */,
+ 66409F9213E25C5300E9BA5A /* NIDeviceInfo.m */,
+ 66409F9313E25C5300E9BA5A /* NimbusOverview.h */,
+ 66409F9413E25C5300E9BA5A /* NIOverview.h */,
+ 66409F9513E25C5300E9BA5A /* NIOverview.m */,
+ 66409F9613E25C5300E9BA5A /* NIOverviewGraphView.h */,
+ 66409F9713E25C5300E9BA5A /* NIOverviewGraphView.m */,
+ 66409F9813E25C5300E9BA5A /* NIOverviewLogger.h */,
+ 66409F9913E25C5300E9BA5A /* NIOverviewLogger.m */,
+ 66409F9A13E25C5300E9BA5A /* NIOverviewPageView.h */,
+ 66409F9B13E25C5300E9BA5A /* NIOverviewPageView.m */,
+ 66409F9C13E25C5300E9BA5A /* NIOverviewSwizzling.h */,
+ 66409F9D13E25C5300E9BA5A /* NIOverviewSwizzling.m */,
+ 66409F9E13E25C5300E9BA5A /* NIOverviewView.h */,
+ 66409F9F13E25C5300E9BA5A /* NIOverviewView.m */,
+ );
+ name = Overview;
+ sourceTree = "<group>";
+ };
66EA057A13C011C0004FFE1A /* Source */ = {
isa = PBXGroup;
children = (
@@ -379,6 +425,7 @@
children = (
665E0B9513CE814D008A1D21 /* Core */,
665E0BC613CE8161008A1D21 /* Photos */,
+ 66C52CC313DAA79E00D6BA6F /* Overview */,
669815CB13D507F900417E8B /* ASIHTTPRequest */,
669819D313D5739D00417E8B /* Processors */,
669815CA13D507F200417E8B /* JSONKit */,
@@ -389,6 +436,7 @@
66EA059D13C0128E004FFE1A /* Resources */ = {
isa = PBXGroup;
children = (
+ 66409FA713E25C5E00E9BA5A /* NimbusOverviewer.bundle */,
66EAC7DB13D2A77D00BDFF34 /* NimbusPhotos.bundle */,
66EA05A213C01297004FFE1A /* NetworkPhotoAlbum-Info.plist */,
);
@@ -448,6 +496,7 @@
buildActionMask = 2147483647;
files = (
66EAC7DC13D2A77D00BDFF34 /* NimbusPhotos.bundle in Resources */,
+ 66409FA813E25C5E00E9BA5A /* NimbusOverviewer.bundle in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -497,6 +546,13 @@
6631673613D6825800FF0CBE /* CatalogTableViewController.m in Sources */,
6631680D13D6891F00FF0CBE /* DribbblePhotoAlbumViewController.m in Sources */,
667DC2BE13D89FD100C1B0ED /* NIPhotoScrubberView.m in Sources */,
+ 66409FA013E25C5300E9BA5A /* NIDeviceInfo.m in Sources */,
+ 66409FA113E25C5300E9BA5A /* NIOverview.m in Sources */,
+ 66409FA213E25C5300E9BA5A /* NIOverviewGraphView.m in Sources */,
+ 66409FA313E25C5300E9BA5A /* NIOverviewLogger.m in Sources */,
+ 66409FA413E25C5300E9BA5A /* NIOverviewPageView.m in Sources */,
+ 66409FA513E25C5300E9BA5A /* NIOverviewSwizzling.m in Sources */,
+ 66409FA613E25C5300E9BA5A /* NIOverviewView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
13 examples/photos/NetworkPhotoAlbums/src/AppDelegate.m
@@ -18,6 +18,7 @@
#import "FacebookPhotoAlbumViewController.h"
#import "CatalogTableViewController.h"
+#import "NimbusOverview.h"
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -48,13 +49,11 @@ - (void)dealloc {
///////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+
+ [NIOverview applicationDidFinishLaunching];
+
self.window = [[[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds] autorelease];
- /*
- FacebookPhotoAlbumViewController* rootVC = [[[FacebookPhotoAlbumViewController alloc] initWithNibName:nil bundle:nil]
- autorelease];
- rootVC.facebookAlbumId = @"10150160584103418";
-*/
CatalogTableViewController* catalogVC =
[[[CatalogTableViewController alloc] initWithStyle:UITableViewStyleGrouped] autorelease];
@@ -62,8 +61,10 @@ - (BOOL) application:(UIApplication *)application
[self.window addSubview:_rootViewController.view];
- [self.window makeKeyAndVisible];
+ [NIOverview addOverviewToWindow:self.window];
+ [self.window makeKeyAndVisible];
+
return YES;
}
View
1  examples/photos/NetworkPhotoAlbums/src/DribbblePhotoAlbumViewController.m
@@ -29,6 +29,7 @@ @implementation DribbblePhotoAlbumViewController
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)dealloc {
+ NI_RELEASE_SAFELY(_photoInformation);
NI_RELEASE_SAFELY(_apiPath);
[super dealloc];
View
1  examples/photos/NetworkPhotoAlbums/src/FacebookPhotoAlbumViewController.m
@@ -30,6 +30,7 @@ @implementation FacebookPhotoAlbumViewController
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)dealloc {
+ NI_RELEASE_SAFELY(_photoInformation);
NI_RELEASE_SAFELY(_facebookAlbumId);
[super dealloc];
View
2  examples/photos/NetworkPhotoAlbums/src/NetworkPhotoAlbumViewController.m
@@ -32,7 +32,7 @@ @implementation NetworkPhotoAlbumViewController
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)shutdown {
- for (ASIHTTPRequest *request in _queue.operations) {
+ for (ASIHTTPRequest* request in _queue.operations) {
request.delegate = nil;
}
[_queue cancelAllOperations];
View
5 examples/photos/NetworkPhotoAlbums/src/NetworkPhotoAlbum_Prefix.pch
@@ -15,8 +15,9 @@
//
#ifdef __OBJC__
- #import <Foundation/Foundation.h>
- #import <UIKit/UIKit.h>
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+#import <QuartzCore/QuartzCore.h>
#import "NimbusCore.h"
#import "NimbusPhotos.h"
#import "NimbusProcessors.h"
View
84 src/Doxygen.h
@@ -113,6 +113,90 @@
*/
/**
+ * @defgroup Version-5-0 Version 0.5 API Changes
+ * @ingroup Version-History
+ *
+ * Version 0.5.0 of Nimbus was released on July 29, 2011. This major version introduced the new
+ * Nimbus @link NimbusOverview Overview@endlink, a debugging tool that shows detailed information
+ * about the state of your device and application in the device's status bar area.
+ *
+ * @image html overview1.png "The Overview added to the network photo album app."
+ *
+ *
+ * <h2>Added Frameworks</h2>
+ *
+ * - @link NimbusOverview Nimbus Overview@endlink
+ *
+ *
+ * <h2>Core</h2>
+ *
+ * <h3>NICommonMetrics[.h]</h3>
+ *
+ * - <span class="apiDiffAdded">Added</span> <code>NIStatusBarFrameAnimationCurve()</code>
+ * - <span class="apiDiffAdded">Added</span> <code>NIStatusBarFrameAnimationDuration()</code>
+ * - <span class="apiDiffAdded">Added</span> <code>NIStatusBarHeight()</code>
+ * - <span class="apiDiffAdded">Added</span> <code>NIDeviceRotationDuration()</code>
+ *
+ * <h3>NIDataStructures[.h]</h3>
+ *
+ * - <span class="apiDiffAdded">Added</span> <code>[NILinkedList @link NILinkedList::objectEnumerator objectEnumerator@endlink]</code>
+ *
+ * <h3>NIDeviceOrientation[.h]</h3>
+ *
+ * - <span class="apiDiffAdded">Added</span> <code>NIRotateTransformForOrientation()</code>
+ *
+ *
+ * <h2>Network Image</h2>
+ *
+ * <h3>NINetworkImageView[.m]</h3>
+ *
+ * - <span class="apiDiffBugfix">Bugfix</span> Cancel network requests without blocking on the main thread.
+ *
+ *
+ * <h2>Photos</h2>
+ *
+ * <h3>NIToolbarPhotoViewController[.m]</h3>
+ *
+ * - <span class="apiDiffBugfix">Bugfix</span> Fix various memory leaks related to not releasing views on dealloc.
+ * - <span class="apiDiffBugfix">Bugfix</span> Fix memory leak when toggling the toolbar mode between a scrubber and buttons.
+ *
+ *
+ * <h2>Examples</h2>
+ *
+ * <h3>NetworkPhotoAlbums</h3>
+ *
+ * - <span class="apiDiffBugfix">Bugfix</span> Fix various memory leaks related to not releasing views on dealloc.
+ *
+ *
+ * <h2>Real Live People Involved in this Release</h2>
+ *
+ * <div class="contributor_profile">
+ * <img width="135px" height="135px" src="http://www.gravatar.com/avatar/f3c8603c353afa79b9f1c77f35efd566?s=135&amp;d=http://three20.info/gfx/team/silhouette.gif" />
+ * <div class="name">Jeff Verkoeyen</div>
+ * <div class="github"><a href="http://github.com/jverkoey">jverkoey</a></div>
+ * </div>
+ *
+ * <div class="clearfix"></div>
+ *
+ * <h3>Add Your Name to This List</h3>
+ *
+ * Contributions are highly encouraged! If you have a feature that you feel would fit within the
+ * Nimbus framework, feel free to fire off a pull request on GitHub. Bugs may be reported
+ * using the issue tracker on GitHub as well.
+ *
+ * Check out the <a href="https://github.com/jverkoey/nimbus/issues?sort=created&direction=desc&state=open&page=1&milestone=5">tasks grab bag</a>
+ * for opportunities to help out.
+ *
+ * <h2>Robots Involved in this Release</h2>
+ *
+ * <div class="contributor_profile">
+ * <div class="name"><a href="http://www.stack.nl/~dimitri/doxygen/">Doxygen</a></div>
+ * </div>
+ *
+ * <div class="clearfix"></div>
+ */
+
+/**
* @defgroup Version-4 Version 0.4 API Changes
* @ingroup Version-History
*
View
14 src/core/src/NICommonMetrics.h
@@ -54,6 +54,20 @@ UIViewAnimationCurve NIStatusBarAnimationCurve();
NSTimeInterval NIStatusBarAnimationDuration();
/**
+ * The animation curve used when animating the status bar frame.
+ *
+ * Value: UIViewAnimationCurveEaseInOut
+ */
+UIViewAnimationCurve NIStatusBarFrameAnimationCurve();
+
+/**
+ * The animation duration for animating the status bar frame.
+ *
+ * Value: 0.35 seconds
+ */
+NSTimeInterval NIStatusBarFrameAnimationDuration();
+
+/**
* Get the status bar's current height.
*
* If the status bar is hidden this will return 0.
View
12 src/core/src/NICommonMetrics.m
@@ -42,6 +42,18 @@ NSTimeInterval NIStatusBarAnimationDuration() {
///////////////////////////////////////////////////////////////////////////////////////////////////
+UIViewAnimationCurve NIStatusBarFrameAnimationCurve() {
+ return UIViewAnimationCurveEaseInOut;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+NSTimeInterval NIStatusBarFrameAnimationDuration() {
+ return 0.35;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
CGFloat NIStatusBarHeight() {
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
CGFloat statusBarHeight = MIN(statusBarFrame.size.width, statusBarFrame.size.height);
View
14 src/core/src/NIDataStructures.h
@@ -190,6 +190,20 @@ typedef void NILinkedListLocation;
/**
+ * @name Enumerating Objects
+ * @{
+ */
+#pragma mark Enumerating Objects
+
+/**
+ * Create an enumerator that can be used to enumerate this linked list.
+ */
+- (NSEnumerator *)objectEnumerator;
+
+/**@}*/// End of Enumerating Objects
+
+
+/**
* @name Constant-Time Access
* @{
*/
View
71 src/core/src/NIDataStructures.m
@@ -17,6 +17,70 @@
#import "NIDataStructures.h"
#import "NIDebuggingTools.h"
+#import "NIPreprocessorMacros.h"
+
+@interface NILinkedList()
+
+@property (nonatomic, readonly, assign) struct NILinkedListNode* head;
+
+@end
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+@interface NILinkedListEnumerator : NSEnumerator {
+@private
+ NILinkedList* _ll;
+ struct NILinkedListNode* _iterator;
+}
+
+- (id)initWithLinkedList:(NILinkedList *)ll;
+
+@end
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+@implementation NILinkedListEnumerator
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)dealloc {
+ NI_RELEASE_SAFELY(_ll);
+
+ [super dealloc];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (id)initWithLinkedList:(NILinkedList *)ll {
+ if ((self = [super init])) {
+ _ll = [ll retain];
+ _iterator = ll.head;
+ }
+ return self;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (id)nextObject {
+ id object = nil;
+ if (nil != _iterator) {
+ object = _iterator->object;
+ _iterator = _iterator->next;
+
+ } else {
+ // As per the guidelines in the Objective-C docs for enumerators, we release the linked
+ // list when we are finished enumerating.
+ NI_RELEASE_SAFELY(_ll);
+ }
+ return object;
+}
+
+
+@end
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -24,6 +88,7 @@
///////////////////////////////////////////////////////////////////////////////////////////////////
@implementation NILinkedList
+@synthesize head = _head;
@synthesize count = _count;
@@ -297,6 +362,12 @@ - (void)removeLastObject {
///////////////////////////////////////////////////////////////////////////////////////////////////
+- (NSEnumerator *)objectEnumerator {
+ return [[[NILinkedListEnumerator alloc] initWithLinkedList:self] autorelease];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
- (NILinkedListLocation *)locationOfObject:(id)object {
struct NILinkedListNode* node = _head;
while (0 != node) {
View
19 src/core/unittests/NIDataStructureTests.m
@@ -304,6 +304,25 @@ - (void)testLinkedListIteration {
///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)testLinkedListEnumeration {
+ NILinkedList* ll = [[[NILinkedList alloc] init] autorelease];
+
+ id object1 = [NSArray array];
+ id object2 = [NSDictionary dictionary];
+ id object3 = [NSSet set];
+ [ll addObject:object1];
+ [ll addObject:object2];
+ [ll addObject:object3];
+
+ NSEnumerator* enumerator = [ll objectEnumerator];
+ STAssertEquals([enumerator nextObject], object1, @"The first object should be object1.");
+ STAssertEquals([enumerator nextObject], object2, @"The first object should be object2.");
+ STAssertEquals([enumerator nextObject], object3, @"The first object should be object3.");
+ STAssertNil([enumerator nextObject], @"The final object should be nil.");
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)testLinkedListCopying {
NILinkedList* ll = [[[NILinkedList alloc] init] autorelease];
View
12 src/networkimage/src/NINetworkImageView.m
@@ -68,11 +68,11 @@ @implementation NINetworkImageView
- (void)cancelOperation {
if ([self.operation isKindOfClass:[ASIHTTPRequest class]]) {
ASIHTTPRequest* request = (ASIHTTPRequest *)self.operation;
- [request clearDelegatesAndCancel];
-
- } else {
- [self.operation cancel];
+ // Clear the delegate so that we don't receive a didFail notification when we cancel the
+ // operation.
+ request.delegate = nil;
}
+ [self.operation cancel];
}
@@ -189,9 +189,7 @@ - (void)_didFinishLoadingWithImage: (UIImage *)image
contentMode: contentMode
scaleOptions: scaleOptions];
- // Store the image in the memory cache, possibly with an expiration date. The expiration
- // date will allow the image to be released from memory if it expires whenever we receive
- // a memory warning.
+ // Store the image in the memory cache, possibly with an expiration date.
[self.imageMemoryCache storeObject: image
withName: cacheKey
expiresAfter: expirationDate];
View
361 src/overview/NimbusOverview.xcodeproj/project.pbxproj
@@ -0,0 +1,361 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 665E09A813CB7D84008A1D21 /* NimbusOverview.h in Headers */ = {isa = PBXBuildFile; fileRef = 665E09A713CB7D84008A1D21 /* NimbusOverview.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6675CFCB13E20E3600BC6759 /* NIDeviceInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 6675CFBD13E20E3600BC6759 /* NIDeviceInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6675CFCC13E20E3600BC6759 /* NIDeviceInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 6675CFBE13E20E3600BC6759 /* NIDeviceInfo.m */; };
+ 6675CFCE13E20E3600BC6759 /* NIOverview.m in Sources */ = {isa = PBXBuildFile; fileRef = 6675CFC013E20E3600BC6759 /* NIOverview.m */; };
+ 6675CFCF13E20E3600BC6759 /* NIOverviewGraphView.h in Headers */ = {isa = PBXBuildFile; fileRef = 6675CFC113E20E3600BC6759 /* NIOverviewGraphView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6675CFD013E20E3600BC6759 /* NIOverviewGraphView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6675CFC213E20E3600BC6759 /* NIOverviewGraphView.m */; };
+ 6675CFD113E20E3600BC6759 /* NIOverviewLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 6675CFC313E20E3600BC6759 /* NIOverviewLogger.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6675CFD213E20E3600BC6759 /* NIOverviewLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 6675CFC413E20E3600BC6759 /* NIOverviewLogger.m */; };
+ 6675CFD313E20E3600BC6759 /* NIOverviewPageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 6675CFC513E20E3600BC6759 /* NIOverviewPageView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6675CFD413E20E3600BC6759 /* NIOverviewPageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6675CFC613E20E3600BC6759 /* NIOverviewPageView.m */; };
+ 6675CFD713E20E3600BC6759 /* NIOverviewView.h in Headers */ = {isa = PBXBuildFile; fileRef = 6675CFC913E20E3600BC6759 /* NIOverviewView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6675CFD813E20E3600BC6759 /* NIOverviewView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6675CFCA13E20E3600BC6759 /* NIOverviewView.m */; };
+ 6675CFFA13E2146200BC6759 /* NIOverview.h in Headers */ = {isa = PBXBuildFile; fileRef = 6675CFF913E2146200BC6759 /* NIOverview.h */; };
+ 6675CFFE13E2244A00BC6759 /* NIOverviewSwizzling.h in Headers */ = {isa = PBXBuildFile; fileRef = 6675CFFC13E2244900BC6759 /* NIOverviewSwizzling.h */; };
+ 6675CFFF13E2244A00BC6759 /* NIOverviewSwizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = 6675CFFD13E2244900BC6759 /* NIOverviewSwizzling.m */; };
+ AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 665E0AF713CCCE6A008A1D21 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 665E0AF213CCCE6A008A1D21 /* NimbusCore.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = D2AAC07E0554694100DB518D;
+ remoteInfo = NimbusCore;
+ };
+ 665E0AF913CCCE6A008A1D21 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 665E0AF213CCCE6A008A1D21 /* NimbusCore.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 668750F413A1AC6000FF1C56;
+ remoteInfo = NimbusCoreUnitTests;
+ };
+ 665E0AFB13CCCE71008A1D21 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 665E0AF213CCCE6A008A1D21 /* NimbusCore.xcodeproj */;
+ proxyType = 1;
+ remoteGlobalIDString = D2AAC07D0554694100DB518D;
+ remoteInfo = NimbusCore;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 665E091D13CB7CC0008A1D21 /* NimbusOverview_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NimbusOverview_Prefix.pch; path = lib/NimbusOverview_Prefix.pch; sourceTree = "<group>"; };
+ 665E092513CB7CE2008A1D21 /* unittests.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = unittests.xcconfig; path = ../common/confs/unittests.xcconfig; sourceTree = SOURCE_ROOT; };
+ 665E092613CB7CE2008A1D21 /* library.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = library.xcconfig; path = ../common/confs/library.xcconfig; sourceTree = SOURCE_ROOT; };
+ 665E092713CB7CE2008A1D21 /* project.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = project.xcconfig; path = ../common/confs/project.xcconfig; sourceTree = SOURCE_ROOT; };
+ 665E09A713CB7D84008A1D21 /* NimbusOverview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NimbusOverview.h; path = src/NimbusOverview.h; sourceTree = "<group>"; };
+ 665E0AF213CCCE6A008A1D21 /* NimbusCore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = NimbusCore.xcodeproj; path = ../core/NimbusCore.xcodeproj; sourceTree = SOURCE_ROOT; };
+ 6675CFBD13E20E3600BC6759 /* NIDeviceInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIDeviceInfo.h; path = src/NIDeviceInfo.h; sourceTree = "<group>"; };
+ 6675CFBE13E20E3600BC6759 /* NIDeviceInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIDeviceInfo.m; path = src/NIDeviceInfo.m; sourceTree = "<group>"; };
+ 6675CFC013E20E3600BC6759 /* NIOverview.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIOverview.m; path = src/NIOverview.m; sourceTree = "<group>"; };
+ 6675CFC113E20E3600BC6759 /* NIOverviewGraphView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIOverviewGraphView.h; path = src/NIOverviewGraphView.h; sourceTree = "<group>"; };
+ 6675CFC213E20E3600BC6759 /* NIOverviewGraphView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIOverviewGraphView.m; path = src/NIOverviewGraphView.m; sourceTree = "<group>"; };
+ 6675CFC313E20E3600BC6759 /* NIOverviewLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIOverviewLogger.h; path = src/NIOverviewLogger.h; sourceTree = "<group>"; };
+ 6675CFC413E20E3600BC6759 /* NIOverviewLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIOverviewLogger.m; path = src/NIOverviewLogger.m; sourceTree = "<group>"; };
+ 6675CFC513E20E3600BC6759 /* NIOverviewPageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIOverviewPageView.h; path = src/NIOverviewPageView.h; sourceTree = "<group>"; };
+ 6675CFC613E20E3600BC6759 /* NIOverviewPageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIOverviewPageView.m; path = src/NIOverviewPageView.m; sourceTree = "<group>"; };
+ 6675CFC913E20E3600BC6759 /* NIOverviewView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIOverviewView.h; path = src/NIOverviewView.h; sourceTree = "<group>"; };
+ 6675CFCA13E20E3600BC6759 /* NIOverviewView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIOverviewView.m; path = src/NIOverviewView.m; sourceTree = "<group>"; };
+ 6675CFF913E2146200BC6759 /* NIOverview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = NIOverview.h; path = src/NIOverview.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
+ 6675CFFC13E2244900BC6759 /* NIOverviewSwizzling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NIOverviewSwizzling.h; path = src/NIOverviewSwizzling.h; sourceTree = "<group>"; };
+ 6675CFFD13E2244900BC6759 /* NIOverviewSwizzling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NIOverviewSwizzling.m; path = src/NIOverviewSwizzling.m; sourceTree = "<group>"; };
+ AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ D2AAC07E0554694100DB518D /* libNimbusOverview.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libNimbusOverview.a; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ D2AAC07C0554694100DB518D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DFFF38A50411DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ D2AAC07E0554694100DB518D /* libNimbusOverview.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* NimbusOverview */ = {
+ isa = PBXGroup;
+ children = (
+ 665E091D13CB7CC0008A1D21 /* NimbusOverview_Prefix.pch */,
+ 08FB77AEFE84172EC02AAC07 /* Source */,
+ 0867D69AFE84028FC02AAC07 /* Frameworks */,
+ 665E092213CB7CDA008A1D21 /* Configurations */,
+ 034768DFFF38A50411DB9C8B /* Products */,
+ );
+ name = NimbusOverview;
+ sourceTree = "<group>";
+ };
+ 0867D69AFE84028FC02AAC07 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 665E0AF213CCCE6A008A1D21 /* NimbusCore.xcodeproj */,
+ AACBBE490F95108600F1A2B1 /* Foundation.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 08FB77AEFE84172EC02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 665E09A713CB7D84008A1D21 /* NimbusOverview.h */,
+ 6675CFBD13E20E3600BC6759 /* NIDeviceInfo.h */,
+ 6675CFBE13E20E3600BC6759 /* NIDeviceInfo.m */,
+ 6675CFF913E2146200BC6759 /* NIOverview.h */,
+ 6675CFC013E20E3600BC6759 /* NIOverview.m */,
+ 6675CFC113E20E3600BC6759 /* NIOverviewGraphView.h */,
+ 6675CFC213E20E3600BC6759 /* NIOverviewGraphView.m */,
+ 6675CFC313E20E3600BC6759 /* NIOverviewLogger.h */,
+ 6675CFC413E20E3600BC6759 /* NIOverviewLogger.m */,
+ 6675CFC513E20E3600BC6759 /* NIOverviewPageView.h */,
+ 6675CFC613E20E3600BC6759 /* NIOverviewPageView.m */,
+ 6675CFFC13E2244900BC6759 /* NIOverviewSwizzling.h */,
+ 6675CFFD13E2244900BC6759 /* NIOverviewSwizzling.m */,
+ 6675CFC913E20E3600BC6759 /* NIOverviewView.h */,
+ 6675CFCA13E20E3600BC6759 /* NIOverviewView.m */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 665E092213CB7CDA008A1D21 /* Configurations */ = {
+ isa = PBXGroup;
+ children = (
+ 665E092513CB7CE2008A1D21 /* unittests.xcconfig */,
+ 665E092613CB7CE2008A1D21 /* library.xcconfig */,
+ 665E092713CB7CE2008A1D21 /* project.xcconfig */,
+ );
+ name = Configurations;
+ sourceTree = "<group>";
+ };
+ 665E0AF313CCCE6A008A1D21 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 665E0AF813CCCE6A008A1D21 /* libNimbusCore.a */,
+ 665E0AFA13CCCE6A008A1D21 /* NimbusCoreUnitTests.octest */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ D2AAC07A0554694100DB518D /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 665E09A813CB7D84008A1D21 /* NimbusOverview.h in Headers */,
+ 6675CFCB13E20E3600BC6759 /* NIDeviceInfo.h in Headers */,
+ 6675CFCF13E20E3600BC6759 /* NIOverviewGraphView.h in Headers */,
+ 6675CFD113E20E3600BC6759 /* NIOverviewLogger.h in Headers */,
+ 6675CFD313E20E3600BC6759 /* NIOverviewPageView.h in Headers */,
+ 6675CFD713E20E3600BC6759 /* NIOverviewView.h in Headers */,
+ 6675CFFA13E2146200BC6759 /* NIOverview.h in Headers */,
+ 6675CFFE13E2244A00BC6759 /* NIOverviewSwizzling.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ D2AAC07D0554694100DB518D /* NimbusOverview */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "NimbusOverview" */;
+ buildPhases = (
+ D2AAC07A0554694100DB518D /* Headers */,
+ D2AAC07B0554694100DB518D /* Sources */,
+ D2AAC07C0554694100DB518D /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 665E0AFC13CCCE71008A1D21 /* PBXTargetDependency */,
+ );
+ name = NimbusOverview;
+ productName = NimbusOverview;
+ productReference = D2AAC07E0554694100DB518D /* libNimbusOverview.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "NimbusOverview" */;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 0867D691FE84028FC02AAC07 /* NimbusOverview */;
+ productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
+ projectDirPath = "";
+ projectReferences = (
+ {
+ ProductGroup = 665E0AF313CCCE6A008A1D21 /* Products */;
+ ProjectRef = 665E0AF213CCCE6A008A1D21 /* NimbusCore.xcodeproj */;
+ },
+ );
+ projectRoot = "";
+ targets = (
+ D2AAC07D0554694100DB518D /* NimbusOverview */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXReferenceProxy section */
+ 665E0AF813CCCE6A008A1D21 /* libNimbusCore.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libNimbusCore.a;
+ remoteRef = 665E0AF713CCCE6A008A1D21 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 665E0AFA13CCCE6A008A1D21 /* NimbusCoreUnitTests.octest */ = {
+ isa = PBXReferenceProxy;
+ fileType = wrapper.cfbundle;
+ path = NimbusCoreUnitTests.octest;
+ remoteRef = 665E0AF913CCCE6A008A1D21 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+/* End PBXReferenceProxy section */
+
+/* Begin PBXSourcesBuildPhase section */
+ D2AAC07B0554694100DB518D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 6675CFCC13E20E3600BC6759 /* NIDeviceInfo.m in Sources */,
+ 6675CFCE13E20E3600BC6759 /* NIOverview.m in Sources */,
+ 6675CFD013E20E3600BC6759 /* NIOverviewGraphView.m in Sources */,
+ 6675CFD213E20E3600BC6759 /* NIOverviewLogger.m in Sources */,
+ 6675CFD413E20E3600BC6759 /* NIOverviewPageView.m in Sources */,
+ 6675CFD813E20E3600BC6759 /* NIOverviewView.m in Sources */,
+ 6675CFFF13E2244A00BC6759 /* NIOverviewSwizzling.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 665E0AFC13CCCE71008A1D21 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ name = NimbusCore;
+ targetProxy = 665E0AFB13CCCE71008A1D21 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB921F08733DC00010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 665E092613CB7CE2008A1D21 /* library.xcconfig */;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ COPY_PHASE_STRIP = NO;
+ DSTROOT = /tmp/NimbusOverview.dst;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = lib/NimbusOverview_Prefix.pch;
+ "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = NIMBUS_STATIC_LIBRARY;
+ INSTALL_PATH = /usr/local/lib;
+ PRODUCT_NAME = NimbusOverview;
+ };
+ name = Debug;
+ };
+ 1DEB922008733DC00010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 665E092613CB7CE2008A1D21 /* library.xcconfig */;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ DSTROOT = /tmp/NimbusOverview.dst;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = lib/NimbusOverview_Prefix.pch;
+ "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = NIMBUS_STATIC_LIBRARY;
+ INSTALL_PATH = /usr/local/lib;
+ PRODUCT_NAME = NimbusOverview;
+ };
+ name = Release;
+ };
+ 1DEB922308733DC00010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 665E092713CB7CE2008A1D21 /* project.xcconfig */;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ OTHER_LDFLAGS = "-ObjC";
+ PREBINDING = NO;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ 1DEB922408733DC00010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 665E092713CB7CE2008A1D21 /* project.xcconfig */;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ OTHER_LDFLAGS = "-ObjC";
+ PREBINDING = NO;
+ SDKROOT = iphoneos;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "NimbusOverview" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB921F08733DC00010E9CD /* Debug */,
+ 1DEB922008733DC00010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "NimbusOverview" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB922308733DC00010E9CD /* Debug */,
+ 1DEB922408733DC00010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
View
20 src/overview/lib/NimbusOverview_Prefix.pch
@@ -0,0 +1,20 @@
+//
+// Copyright 2011 Jeff Verkoeyen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifdef __OBJC__
+ #import <Foundation/Foundation.h>
+ #import <UIKit/UIKit.h>
+#endif
View
BIN  src/overview/resources/NimbusOverviewer.bundle/gfx/blueprint.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
122 src/overview/src/NIDeviceInfo.h
@@ -0,0 +1,122 @@
+//
+// Copyright 2011 Jeff Verkoeyen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ * Formats a number of bytes in a human-readable format.
+ *
+ * Will create a string showing the size in bytes, KBs, MBs, or GBs.
+ */
+NSString* NIStringFromBytes(unsigned long long bytes);
+
+
+/**
+ * An interface for accessing device information.
+ *
+ * @ingroup Overview-Sensors
+ *
+ * This class is not meant to be instantiated. All methods are class implementations.
+ *
+ * This class aims to simplify the interface for collecting device information. The low-level
+ * mach APIs provide a host of valuable information but it's often in formats that aren't
+ * particularly ready for presentation.
+ *
+ * @attention When using this class on the simulator, the values returned will reflect
+ * those of the computer within which you're running the simulator, not the
+ * simulated device. This is because the simulator is a first-class citizen
+ * on the computer and has full access to your RAM and disk space.
+ */
+@interface NIDeviceInfo : NSObject
+
+#pragma mark Memory /** @name Memory */
+
+/**
+ * The number of bytes in memory that are free.
+ *
+ * Calculated using the number of free pages of memory.
+ */
++ (unsigned long long)bytesOfFreeMemory;
+
+/**
+ * The total number of bytes of memory.
+ *
+ * Calculated by adding together the number of free, wired, active, and inactive pages of memory.
+ *
+ * This value may change over time on the device due to the way iOS partitions available memory
+ * for applications.
+ */
++ (unsigned long long)bytesOfTotalMemory;
+
+
+#pragma mark Disk Space /** @name Disk Space */
+
+/**
+ * The number of bytes free on disk.
+ */
++ (unsigned long long)bytesOfFreeDiskSpace;
+
+/**
+ * The total number of bytes of disk space.
+ */
++ (unsigned long long)bytesOfTotalDiskSpace;
+
+
+#pragma mark Battery /** @name Battery */
+
+/**
+ * The battery charge level in the range 0 .. 1.0. -1.0 if UIDeviceBatteryStateUnknown.
+ *
+ * This is a thin wrapper for [[UIDevice currentDevice] batteryLevel].
+ */
++ (CGFloat)batteryLevel;
+
+/**
+ * The current battery state.
+ *
+ * This is a thin wrapper for [[UIDevice currentDevice] batteryState].
+ */
++ (UIDeviceBatteryState)batteryState;
+
+
+#pragma mark Caching /** @name Caching */
+
+/**
+ * Fetches the device's current information and then caches it.
+ *
+ * All subsequent calls to NIDeviceInfo methods will use this cached information.
+ *
+ * This can be a useful way to freeze the device info at a moment in time.
+ *
+ * Example:
+ *
+ * @code
+ * [NIDeviceInfo beginCachedDeviceInfo];
+ *
+ * // All calls to NIDeviceInfo methods here will use the information retrieved when
+ * // beginCachedDeviceInfo was called.
+ *
+ * [NIDeviceInfo endCachedDeviceInfo];
+ * @endcode
+ */
++ (BOOL)beginCachedDeviceInfo;
+
+/**
+ * Stop using the cache for the device info methods.
+ */
++ (void)endCachedDeviceInfo;
+
+@end
View
203 src/overview/src/NIDeviceInfo.m
@@ -0,0 +1,203 @@
+//
+// Copyright 2011 Jeff Verkoeyen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "NIDeviceInfo.h"
+
+#ifdef NIMBUS_STATIC_LIBRARY
+#import "NimbusCore/NimbusCore.h"
+#else
+#import "NimbusCore.h"
+#endif
+
+#import <mach/mach.h>
+#import <mach/mach_host.h>
+
+// Static local state.
+static BOOL sIsCaching = NO;
+static BOOL sLastUpdateResult = NO;
+static vm_size_t sPageSize = 0;
+static vm_statistics_data_t sVMStats;
+static NSDictionary* sFileSystem = nil;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+NSString* NIStringFromBytes(unsigned long long bytes) {
+ static const void* sOrdersOfMagnitude[] = {
+ @"bytes", @"KB", @"MB", @"GB"
+ };
+
+ // Determine what magnitude the number of bytes is by shifting off 10 bits at a time
+ // (equivalent to dividing by 1024).
+ NSInteger magnitude = 0;
+ unsigned long long highbits = bytes;
+ unsigned long long inverseBits = ~((unsigned long long)0x3FF);
+ while ((highbits & inverseBits)
+ && magnitude + 1 < (sizeof(sOrdersOfMagnitude) / sizeof(void *))) {
+ // Shift off an order of magnitude.
+ highbits >>= 10;
+ magnitude++;
+ }
+
+ if (magnitude > 0) {
+ unsigned long long dividend = 1024 << (magnitude - 1) * 10;
+ double result = ((double)bytes / (double)(dividend));
+ return [NSString stringWithFormat:@"%.2f %@",
+ result,
+ sOrdersOfMagnitude[magnitude]];
+
+ } else {
+ // We don't need to bother with dividing bytes.
+ return [NSString stringWithFormat:@"%lld %@", bytes, sOrdersOfMagnitude[magnitude]];
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+@implementation NIDeviceInfo
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (void)initialize {
+ [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
+ memset(&sVMStats, 0, sizeof(sVMStats));
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (BOOL)updateHostStatistics {
+ mach_port_t host_port = mach_host_self();
+ mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
+ host_page_size(host_port, &sPageSize);
+ return (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&sVMStats, &host_size)
+ == KERN_SUCCESS);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (BOOL)updateFileSystemAttributes {
+ NI_RELEASE_SAFELY(sFileSystem);
+
+ NSError* error = nil;
+ // This path could be any path that is on the device's local disk.
+ NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+
+ // Fetch the file system information based on the path given (the user's documents directory).
+ sFileSystem =
+ [[[NSFileManager defaultManager] attributesOfFileSystemForPath: [paths lastObject]
+ error: &error] retain];
+ return (nil == error);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+#pragma mark Public Methods
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (unsigned long long)bytesOfFreeMemory {
+ if (!sIsCaching && ![self updateHostStatistics]) {
+ return 0;
+ }
+ unsigned long long mem_free = ((unsigned long long)sVMStats.free_count
+ * (unsigned long long)sPageSize);
+ return mem_free;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (unsigned long long)bytesOfTotalMemory {
+ if (!sIsCaching && ![self updateHostStatistics]) {
+ return 0;
+ }
+ unsigned long long mem_free = (((unsigned long long)sVMStats.free_count
+ + (unsigned long long)sVMStats.active_count
+ + (unsigned long long)sVMStats.inactive_count
+ + (unsigned long long)sVMStats.wire_count)
+ * (unsigned long long)sPageSize);
+ return mem_free;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (unsigned long long)bytesOfFreeDiskSpace {
+ if (!sIsCaching && ![self updateFileSystemAttributes]) {
+ return 0;
+ }
+ unsigned long long bytes = 0;
+
+ NSNumber* number = [sFileSystem objectForKey:NSFileSystemFreeSize];
+ bytes = [number unsignedLongLongValue];
+
+ return bytes;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (unsigned long long)bytesOfTotalDiskSpace {
+ if (!sIsCaching && ![self updateFileSystemAttributes]) {
+ return 0;
+ }
+ unsigned long long bytes = 0;
+
+ NSNumber* number = [sFileSystem objectForKey:NSFileSystemSize];
+ bytes = [number unsignedLongLongValue];
+
+ return bytes;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (CGFloat)batteryLevel {
+ return [[UIDevice currentDevice] batteryLevel];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (UIDeviceBatteryState)batteryState {
+ return [[UIDevice currentDevice] batteryState];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+#pragma mark Caching
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (BOOL)beginCachedDeviceInfo {
+ if (!sIsCaching) {
+ sIsCaching = YES;
+
+ sLastUpdateResult = [self updateHostStatistics];
+ sLastUpdateResult = ([self updateFileSystemAttributes] && sLastUpdateResult);
+ }
+
+ return sLastUpdateResult;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (void)endCachedDeviceInfo {
+ sIsCaching = NO;
+}
+
+
+@end
View
95 src/overview/src/NIOverview.h
@@ -0,0 +1,95 @@
+//
+// Copyright 2011 Jeff Verkoeyen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import <Foundation/Foundation.h>
+
+@class NIOverviewView;
+@class NIOverviewLogger;
+
+/**
+ * The Overview state management class.
+ *
+ * @ingroup Overview
+ *
+ * <h2>What is the Overview?</h2>
+ *
+ * The Overview is a paged view that sits directly below the status bar and presents information
+ * about the device and the currently running application. The Overview is extensible, in that
+ * you can write your own pages and add them to the Overview. The included pages allow you to
+ * see the current and historical state of memory and disk use, the console logs, and important
+ * events that have occurred (such as memory warnings).
+ *
+ *
+ * <h2>Before Using the Overview</h2>
+ *
+ * None of the Overview methods will do anything unless you have the DEBUG preprocessor
+ * macro defined. This is by design. The Overview swizzles private API methods in order to
+ * trick the device into showing the Overview as part of the status bar.
+ *
+ * DO *NOT* SUBMIT YOUR APP TO THE APP STORE WITH DEBUG DEFINED.
+ *
+ * If you submit your app to the App Store with DEBUG defined, you *will* be rejected.
+ * Overview works only because it hacks certain aspects of the device using private APIs
+ * and method swizzling. For good reason, Apple will not look too kindly to the Overview
+ * being included in production code. If Apple ever changes any of the APIs that
+ * the Overview depends on then the Overview would break.
+ */
+@interface NIOverview : NSObject
+
+#pragma mark Initializing the Overview /** @name Initializing the Overview */
+
+/**
+ * Call this immediately in application:didFinishLaunchingWithOptions:.
+ *
+ * Swizzles the necessary methods for adding the Overview to the view hierarchy and registers
+ * notifications for device state changes.
+ */
++ (void)applicationDidFinishLaunching;
+
+/**
+ * Adds the Overview to the given window.
+ *
+ * The Overview will always be fixed at the top of the device's screen directly
+ * beneath the status bar (if it is visible).
+ */
++ (void)addOverviewToWindow:(UIWindow *)window;
+
+
+#pragma mark Accessing State Information /** @name Accessing State Information */
+
+/**
+ * The height of the Overview.
+ */
++ (CGFloat)height;
+
+/**
+ * The frame of the Overview.
+ */
++ (CGRect)frame;
+
+/**
+ * The Overview view.
+ */
++ (NIOverviewView *)view;
+
+/**
+ * The Overview logger.
+ *
+ * This is the logger that all of the Overview pages use to present their information.
+ */
++ (NIOverviewLogger *)logger;
+
+@end
View
381 src/overview/src/NIOverview.m
@@ -0,0 +1,381 @@
+//
+// Copyright 2011 Jeff Verkoeyen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "NIOverview.h"
+
+#ifdef DEBUG
+
+#import "NIDeviceInfo.h"
+#import "NIOverviewView.h"
+#import "NIOverviewPageView.h"
+#import "NIOverviewSwizzling.h"
+#import "NIOverviewLogger.h"
+
+// Static state.
+static CGFloat sOverviewHeight = 60;
+static BOOL sOverviewIsAwake = NO;
+
+static NSTimer* sOverviewHeartbeatTimer = nil;
+
+static NIOverviewView* sOverviewView = nil;
+static NIOverviewLogger* sOverviewLogger = nil;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+#pragma mark Logging
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * @internal
+ *
+ * An undocumented method that replaces the default logging mechanism with a custom implementation.
+ *
+ * Your method prototype should look like this:
+ *
+ * void logger(const char *message, unsigned length, BOOL withSyslogBanner)
+ *
+ * @attention This method is undocumented, unsupported, and unlikely to be around
+ * forever. Don't go using it in production code.
+ *
+ * Source: http://support.apple.com/kb/TA45403?viewlocale=en_US
+ */
+extern void _NSSetLogCStringFunction(void(*)(const char *, unsigned, BOOL));
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Pipes NSLog messages to the Overview and stderr.
+ *
+ * This method is passed as an argument to _NSSetLogCStringFunction to pipe all NSLog
+ * messages through here.
+ */
+void NIOverviewLogMethod(const char* message, unsigned length, BOOL withSyslogBanner) {
+ static NSDateFormatter* formatter = nil;
+ if (nil == formatter) {
+ formatter = [[NSDateFormatter alloc] init];
+ [formatter setTimeStyle:kCFDateFormatterMediumStyle];
+ [formatter setDateStyle:kCFDateFormatterMediumStyle];
+ }
+
+ // Don't autorelease here in an attempt to minimize autorelease thrashing in tight
+ // loops.
+
+ NSString* formattedLogMessage = [[NSString alloc] initWithCString: message
+ encoding: NSUTF8StringEncoding];
+
+ NIOverviewConsoleLogEntry* entry = [[NIOverviewConsoleLogEntry alloc]
+ initWithLog:formattedLogMessage];
+ NI_RELEASE_SAFELY(formattedLogMessage);
+
+ [[NIOverview logger] addConsoleLog:entry];
+ NI_RELEASE_SAFELY(entry);
+
+ formattedLogMessage = [[NSString alloc] initWithFormat:
+ @"%@: %s\n", [formatter stringFromDate:[NSDate date]], message];
+
+ fprintf(stderr, "%s", [formattedLogMessage UTF8String]);
+
+ NI_RELEASE_SAFELY(formattedLogMessage);
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+@implementation NIOverview
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+#pragma mark Device Orientation Changes
+
+#ifdef DEBUG
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (void)didChangeOrientation {
+ static UIDeviceOrientation lastOrientation = UIDeviceOrientationUnknown;
+
+ // Don't animate the overview if the device didn't actually change orientations.
+ if (lastOrientation != [[UIDevice currentDevice] orientation]
+ && [[UIDevice currentDevice] orientation] != UIDeviceOrientationUnknown
+ && [[UIDevice currentDevice] orientation] != UIDeviceOrientationFaceUp
+ && [[UIDevice currentDevice] orientation] != UIDeviceOrientationFaceDown) {
+
+ // When we flip from landscape to landscape or portait to portait the animation lasts
+ // twice as long.
+ UIDeviceOrientation currentOrientation = [[UIDevice currentDevice] orientation];
+ BOOL isLongAnimation = (UIDeviceOrientationIsLandscape(lastOrientation)
+ == UIDeviceOrientationIsLandscape(currentOrientation));
+ lastOrientation = currentOrientation;
+
+ // Hide the overview right away, we'll make it fade back in when the rotation is
+ // finished.
+ sOverviewView.hidden = YES;
+
+ // Delay showing the overview again until the rotation finishes.
+ [self cancelPreviousPerformRequestsWithTarget:self];
+ [self performSelector:@selector(showoverviewAfterRotation) withObject:nil
+ afterDelay:NIDeviceRotationDuration(isLongAnimation)];
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (void)statusBarWillChangeFrame {
+ [UIView beginAnimations:nil context:nil];
+ [UIView setAnimationDuration:NIStatusBarFrameAnimationDuration()];
+ [UIView setAnimationCurve:NIStatusBarFrameAnimationCurve()];
+ CGRect frame = [NIOverview frame];
+ sOverviewView.center = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame));
+ [UIView commitAnimations];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (void)showoverviewAfterRotation {
+ // Don't modify the overview's frame directly, just modify the transform/center/bounds
+ // properties so that the view is rotated with the device.
+
+ sOverviewView.transform = NIRotateTransformForOrientation(NIInterfaceOrientation());
+
+ // Fetch the frame only to calculate the center.
+ CGRect frame = [NIOverview frame];
+ sOverviewView.center = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame));
+
+ CGRect bounds = sOverviewView.bounds;
+ bounds.size.width = (UIInterfaceOrientationIsLandscape(NIInterfaceOrientation())
+ ? frame.size.height
+ : frame.size.width);
+ sOverviewView.bounds = bounds;
+
+ // Get ready to fade the overview back in.
+ sOverviewView.hidden = NO;
+ sOverviewView.alpha = 0;
+
+ [sOverviewView flashScrollIndicators];
+
+ // Fade!
+ [UIView beginAnimations:nil context:nil];
+ [UIView setAnimationDuration:0.2];
+ sOverviewView.alpha = 1;
+ [UIView commitAnimations];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (void)didReceiveMemoryWarning {
+ [sOverviewLogger addEventLog:
+ [[[NIOverviewEventLogEntry alloc] initWithType:NIOverviewEventDidReceiveMemoryWarning]
+ autorelease]];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (void)heartbeat {
+ [NIDeviceInfo beginCachedDeviceInfo];
+ NIOverviewDeviceLogEntry* logEntry =
+ [[[NIOverviewDeviceLogEntry alloc] initWithTimestamp:[NSDate date]]
+ autorelease];
+ logEntry.bytesOfTotalDiskSpace = [NIDeviceInfo bytesOfTotalDiskSpace];
+ logEntry.bytesOfFreeDiskSpace = [NIDeviceInfo bytesOfFreeDiskSpace];
+ logEntry.bytesOfFreeMemory = [NIDeviceInfo bytesOfFreeMemory];
+ logEntry.bytesOfTotalMemory = [NIDeviceInfo bytesOfTotalMemory];
+ logEntry.batteryLevel = [NIDeviceInfo batteryLevel];
+ logEntry.batteryState = [NIDeviceInfo batteryState];
+ [NIDeviceInfo endCachedDeviceInfo];
+
+ [sOverviewLogger addDeviceLog:logEntry];
+
+ [sOverviewView updatePages];
+}
+
+
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+#pragma mark Public Methods
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (void)applicationDidFinishLaunching {
+#ifdef DEBUG
+ if (!sOverviewIsAwake) {
+ sOverviewIsAwake = YES;
+
+ // Set up the logger right away so that all calls to NSLog will be captured by the
+ // overview.
+ _NSSetLogCStringFunction(NIOverviewLogMethod);
+
+ sOverviewLogger = [[NIOverviewLogger alloc] init];
+
+ NIOverviewSwizzleMethods();
+
+ [[NSNotificationCenter defaultCenter] addObserver: self
+ selector: @selector(didChangeOrientation)
+ name: UIDeviceOrientationDidChangeNotification
+ object: nil];
+ [[NSNotificationCenter defaultCenter] addObserver: self
+ selector: @selector(statusBarWillChangeFrame)
+ name: UIApplicationWillChangeStatusBarFrameNotification
+ object: nil];
+ [[NSNotificationCenter defaultCenter] addObserver: self
+ selector: @selector(didReceiveMemoryWarning)
+ name: UIApplicationDidReceiveMemoryWarningNotification
+ object: nil];
+
+ sOverviewHeartbeatTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.5
+ target: self
+ selector: @selector(heartbeat)
+ userInfo: nil
+ repeats: YES]
+ retain];
+ }
+#endif
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (void)addOverviewToWindow:(UIWindow *)window {
+#ifdef DEBUG
+ if (nil != sOverviewView) {
+ // Remove the old overview in case this gets called multiple times (not sure why you would
+ // though).
+ [sOverviewView removeFromSuperview];
+ NI_RELEASE_SAFELY(sOverviewView);
+ }
+
+ sOverviewView = [[NIOverviewView alloc] initWithFrame:[self frame]];
+
+ [sOverviewView addPageView:[NIOverviewMemoryPageView page]];
+ [sOverviewView addPageView:[NIOverviewDiskPageView page]];
+ [sOverviewView addPageView:[NIOverviewConsoleLogPageView page]];
+ [sOverviewView addPageView:[NIOverviewMaxLogLevelPageView page]];
+
+ // Hide the view initially because the initial frame will be wrong when the device
+ // starts the app in any orientation other than portrait. Don't worry, we'll fade the
+ // view in once we get our first device notification.
+ sOverviewView.hidden = YES;
+
+ [window addSubview:sOverviewView];
+
+ NSLog(@"The overview has been added to a window.");
+#endif
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (NIOverviewLogger *)logger {
+#ifdef DEBUG
+ return sOverviewLogger;
+#else
+ return nil;
+#endif
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (CGFloat)height {
+#ifdef DEBUG
+ return sOverviewHeight;
+#else
+ return 0;
+#endif
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (CGRect)frame {
+#ifdef DEBUG
+ UIInterfaceOrientation orient = NIInterfaceOrientation();
+ CGFloat overviewWidth;
+ CGRect frame;
+
+ // We can't take advantage of automatic view positioning because the overview exists
+ // at the topmost view level (even above the root view controller). As such, we have to
+ // calculate the frame depending on the interface orientation.
+ if (orient == UIInterfaceOrientationLandscapeLeft) {
+ overviewWidth = [UIScreen mainScreen].bounds.size.height;
+ frame = CGRectMake(NIOverviewStatusBarHeight(), 0, sOverviewHeight, overviewWidth);
+
+ } else if (orient == UIInterfaceOrientationLandscapeRight) {
+ overviewWidth = [UIScreen mainScreen].bounds.size.height;
+ frame = CGRectMake([UIScreen mainScreen].bounds.size.width
+ - (NIOverviewStatusBarHeight() + sOverviewHeight), 0,
+ sOverviewHeight, overviewWidth);
+
+ } else if (orient == UIInterfaceOrientationPortraitUpsideDown) {
+ overviewWidth = [UIScreen mainScreen].bounds.size.width;
+ frame = CGRectMake(0, [UIScreen mainScreen].bounds.size.height
+ - (NIOverviewStatusBarHeight() + sOverviewHeight),
+ overviewWidth, sOverviewHeight);
+
+ } else if (orient == UIInterfaceOrientationPortrait) {
+ overviewWidth = [UIScreen mainScreen].bounds.size.width;
+ frame = CGRectMake(0, NIOverviewStatusBarHeight(), overviewWidth, sOverviewHeight);
+
+ } else {
+ overviewWidth = [UIScreen mainScreen].bounds.size.width;
+ frame = CGRectMake(0, NIOverviewStatusBarHeight(), overviewWidth, sOverviewHeight);
+ }
+
+ if ([[UIApplication sharedApplication] isStatusBarHidden]) {
+ // When the status bar is hidden we want to position the overview offscreen.
+ switch (orient) {
+ case UIInterfaceOrientationLandscapeLeft: {
+ frame = CGRectOffset(frame, -frame.size.width, 0);
+ break;
+ }
+ case UIInterfaceOrientationLandscapeRight: {
+ frame = CGRectOffset(frame, frame.size.width, 0);
+ break;
+ }
+ case UIInterfaceOrientationPortrait: {
+ frame = CGRectOffset(frame, 0, -frame.size.height);
+ break;
+ }
+ case UIInterfaceOrientationPortraitUpsideDown: {
+ frame = CGRectOffset(frame, 0, frame.size.height);
+ break;
+ }
+ }
+ }
+ return frame;
+
+#else
+ return CGRectZero;
+#endif
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
++ (UIView *)view {
+#ifdef DEBUG
+ return sOverviewView;
+#else
+ return nil;
+#endif
+}
+
+
+@end
View
80 src/overview/src/NIOverviewGraphView.h
@@ -0,0 +1,80 @@
+//
+// Copyright 2011 Jeff Verkoeyen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import <UIKit/UIKit.h>
+
+@protocol NIOverviewGraphViewDataSource;
+
+/**
+ * A graph view.
+ *
+ * @ingroup Overview-Pages
+ */
+@interface NIOverviewGraphView : UIView {
+@private
+ id<NIOverviewGraphViewDataSource> _dataSource;
+}
+
+/**
+ * The data source for this graph view.
+ */
+@property (nonatomic, readwrite, assign) id<NIOverviewGraphViewDataSource> dataSource;
+
+@end
+
+/**
+ * The data source for NIOverviewGraphView.
+ *
+ * @ingroup Overview-Pages
+ */
+@protocol NIOverviewGraphViewDataSource <NSObject>
+
+@required
+
+/**
+ * Fetches the total range of all x values for this graph.
+ */
+- (CGFloat)graphViewXRange:(NIOverviewGraphView *)graphView;
+
+/**
+ * Fetches the total range of all y values for this graph.
+ */
+- (CGFloat)graphViewYRange:(NIOverviewGraphView *)graphView;
+
+/**
+ * The data source should reset its iterator for fetching points in the graph.
+ */
+- (void)resetPointIterator;
+
+/**
+ * Fetches the next point in the graph to plot.
+ */
+- (BOOL)nextPointInGraphView: (NIOverviewGraphView *)graphView
+ point: (CGPoint *)point;
+
+/**
+ * The data source should reset its iterator for fetching events in the graph.
+ */
+- (void)resetEventIterator;
+
+/**
+ * Fetches the next event in the graph to plot.
+ */
+- (BOOL)nextEventInGraphView: (NIOverviewGraphView *)graphView
+ xValue: (CGFloat *)xValue
+ color: (UIColor **)color;
+
+@end
View
124 src/overview/src/NIOverviewGraphView.m
@@ -0,0 +1,124 @@
+//
+// Copyright 2011 Jeff Verkoeyen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "NIOverviewGraphView.h"
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+@implementation NIOverviewGraphView
+
+@synthesize dataSource = _dataSource;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (id)initWithFrame:(CGRect)frame {
+ if ((self = [super initWithFrame:frame])) {
+ self.opaque = NO;
+ self.layer.borderWidth = 1;
+ self.layer.borderColor = [UIColor colorWithWhite:1 alpha:0.2].CGColor;
+ }
+ return self;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)drawGraphWithContext:(CGContextRef)context {
+ CGSize contentSize = self.bounds.size;
+
+ CGFloat xRange = [self.dataSource graphViewXRange:self];
+ CGFloat yRange = [self.dataSource graphViewYRange:self];
+
+ [self.dataSource resetPointIterator];
+
+ CGContextSetLineWidth(context, 1);
+ CGContextSetShouldAntialias(context, YES);
+
+ BOOL isFirstPoint = YES;
+ CGPoint point = CGPointZero;
+ while ([self.dataSource nextPointInGraphView:self point:&point]) {
+ CGPoint scaledPoint = CGPointMake(point.x / xRange, point.y / yRange);
+ CGPoint plotPoint = CGPointMake(floorf(scaledPoint.x * contentSize.width) - 0.5f,
+ contentSize.height
+ - floorf((scaledPoint.y * 0.8 + 0.1)
+ * contentSize.height) - 0.5f);
+ if (!isFirstPoint) {
+ CGContextAddLineToPoint(context, plotPoint.x, plotPoint.y);
+ }
+ CGContextMoveToPoint(context, plotPoint.x, plotPoint.y);
+ isFirstPoint = NO;
+ }
+
+ CGContextSetStrokeColorWithColor(context, [UIColor colorWithWhite:1 alpha:0.6].CGColor);
+ CGContextStrokePath(context);
+
+ [self.dataSource resetEventIterator];
+
+ CGFloat xValue = 0;
+ UIColor* color = nil;
+ while ([self.dataSource nextEventInGraphView:self xValue:&xValue color:&color]) {
+ CGFloat scaledXValue = xValue / xRange;
+ CGFloat plotXValue = floorf(scaledXValue * contentSize.width) - 0.5f;
+ CGContextMoveToPoint(context, plotXValue, 0);
+ CGContextAddLineToPoint(context, plotXValue, contentSize.height);
+
+ CGContextSetStrokeColorWithColor(context, color.CGColor);
+ CGContextStrokePath(context);
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)drawRect:(CGRect)rect {
+ CGContextRef context = UIGraphicsGetCurrentContext();
+
+ CGRect bounds = self.bounds;
+
+ UIGraphicsPushContext(context);
+
+ [self drawGraphWithContext:context];
+
+ CGContextSetFillColorWithColor(context, [UIColor colorWithWhite:1 alpha:0.2].CGColor);
+ CGContextFillRect(context, bounds);
+
+ CGGradientRef glossGradient = nil;
+ CGColorSpaceRef colorspace = nil;
+ size_t numberOfLocations = 2;
+ CGFloat locations[2] = { 0.0, 1.0 };
+ CGFloat components[8] = {
+ 1.0, 1.0, 1.0, 0.35,
+ 1.0, 1.0, 1.0, 0.06
+ };
+
+ colorspace = CGColorSpaceCreateDeviceRGB();
+ glossGradient = CGGradientCreateWithColorComponents(colorspace,
+ components, locations, numberOfLocations);
+
+ CGPoint topCenter = CGPointMake(CGRectGetMidX(bounds), 0.0f);
+ CGPoint midCenter = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
+ CGContextDrawLinearGradient(context, glossGradient, topCenter, midCenter, 0);
+
+ CGGradientRelease(glossGradient);
+ glossGradient = nil;
+ CGColorSpaceRelease(colorspace);
+ colorspace = nil;
+
+ UIGraphicsPopContext();
+}
+
+
+@end
View
249 src/overview/src/NIOverviewLogger.h
@@ -0,0 +1,249 @@
+//
+// Copyright 2011 Jeff Verkoeyen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import <Foundation/Foundation.h>
+
+#ifdef NIMBUS_STATIC_LIBRARY
+#import "NimbusCore/NimbusCore.h"
+#else
+#import "NimbusCore.h"
+#endif
+
+extern NSString* const NIOverviewLoggerDidAddConsoleLog;
+
+@class NIOverviewDeviceLogEntry;
+@class NIOverviewConsoleLogEntry;
+@class NIOverviewEventLogEntry;
+
+/**
+ * The Overview logger.
+ *
+ * @ingroup Overview-Logger
+ *
+ * This object stores all of the historical information used to draw the graphs in the
+ * Overview memory and disk pages, as well as the console log page.
+ *
+ * The primary log should be accessed by calling [NIOverview @link NIOverview::logger logger@endlink].
+ */
+@interface NIOverviewLogger : NSObject {
+@private
+ NILinkedList* _deviceLogs;
+ NILinkedList* _consoleLogs;
+ NILinkedList* _eventLogs;
+ NSTimeInterval _oldestLogAge;
+}
+
+#pragma mark Configuration Settings /** @name Configuration Settings */
+
+/**
+ * The oldest age of a memory or disk log entry.
+ *
+ * Log entries older than this number of seconds will be pruned from the log.
+ *
+ * By default this is 1 minute.
+ */
+@property (nonatomic, readwrite, assign) NSTimeInterval oldestLogAge;
+
+
+#pragma mark Adding Log Entries /** @name Adding Log Entries */
+
+/**
+ * Add a device log.
+ *
+ * This method will first prune expired entries and then add the new entry to the log.
+ */
+- (void)addDeviceLog:(NIOverviewDeviceLogEntry *)logEntry;
+
+/**
+ * Add a console log.
+ *
+ * This method will not prune console log entries.
+ */
+- (void)addConsoleLog:(NIOverviewConsoleLogEntry *)logEntry;
+
+/**
+ * Add a event log.
+ *
+ * This method will first prune expired entries and then add the new entry to the log.
+ */
+- (void)addEventLog:(NIOverviewEventLogEntry *)logEntry;
+
+
+#pragma mark Accessing Logs /** @name Accessing Logs */
+
+/**
+ * The linked list of device logs.
+ *
+ * Log entries are in increasing chronological order.
+ */
+@property (nonatomic, readonly, retain) NILinkedList* deviceLogs;
+
+/**
+ * The linked list of console logs.
+ *
+ * Log entries are in increasing chronological order.
+ */
+@property (nonatomic, readonly, retain) NILinkedList* consoleLogs;
+
+/**
+ * The linked list of events.
+ *
+ * Log entries are in increasing chronological order.
+ */
+@property (nonatomic, readonly, retain) NILinkedList* eventLogs;
+
+@end
+
+
+/**
+ * The basic requirements for a log entry.
+ *
+ * @ingroup Overview-Logger-Entries
+ *
+ * A basic log entry need only define a timestamp in order to be particularly useful.
+ */
+@interface NIOverviewLogEntry : NSObject {
+@private
+ NSDate* _timestamp;
+}
+
+#pragma mark Creating an Entry /** @name Creating an Entry */
+
+/**
+ * Designated initializer.
+ */
+- (id)initWithTimestamp:(NSDate *)timestamp;
+
+
+#pragma mark Entry Information /** @name Entry Information */
+
+/**
+ * The timestamp for this log entry.
+ */
+@property (nonatomic, readwrite, retain) NSDate* timestamp;
+
+@end
+
+
+/**
+ * A device log entry.
+ *
+ * @ingroup Overview-Logger-Entries
+ */
+@interface NIOverviewDeviceLogEntry : NIOverviewLogEntry {
+@private
+ unsigned long long _bytesOfFreeMemory;
+ unsigned long long _bytesOfTotalMemory;
+ unsigned long long _bytesOfTotalDiskSpace;
+ unsigned long long _bytesOfFreeDiskSpace;
+
+ CGFloat _batteryLevel;
+ UIDeviceBatteryState _batteryState;
+}
+
+#pragma mark Entry Information /** @name Entry Information */
+
+/**
+ * The number of bytes of free memory.
+ */
+@property (nonatomic, readwrite, assign) unsigned long long bytesOfFreeMemory;
+
+/**
+ * The number of bytes of total memory.
+ */
+@property (nonatomic, readwrite, assign) unsigned long long bytesOfTotalMemory;
+
+/**
+ * The number of bytes of free disk space.
+ */
+@property (nonatomic, readwrite, assign) unsigned long long bytesOfFreeDiskSpace;
+
+/**
+ * The number of bytes of total disk space.
+ */
+@property (nonatomic, readwrite, assign) unsigned long long bytesOfTotalDiskSpace;
+
+/**
+ * The battery level.
+ */
+@property (nonatomic, readwrite, assign) CGFloat batteryLevel;
+
+/**
+ * The state of the battery.
+ */
+@property (nonatomic, readwrite, assign) UIDeviceBatteryState batteryState;
+
+@end
+
+
+/**
+ * A console log entry.
+ *
+ * @ingroup Overview-Logger-Entries
+ */
+@interface NIOverviewConsoleLogEntry : NIOverviewLogEntry {
+@private
+ NSString* _log;
+}
+
+#pragma mark Creating an Entry /** @name Creating an Entry */
+
+/**
+ * Designated initializer.
+ */
+- (id)initWithLog:(NSString *)log;
+
+
+#pragma mark Entry Information /** @name Entry Information */
+
+/**
+ * The text that was written to the console log.
+ */
+@property (nonatomic, readwrite, copy) NSString* log;
+
+@end
+
+
+typedef enum {
+ NIOverviewEventDidReceiveMemoryWarning,
+} NIOverviewEventType;
+
+/**
+ * An event log entry.
+ *
+ * @ingroup Overview-Logger-Entries
+ */
+@interface NIOverviewEventLogEntry : NIOverviewLogEntry {
+@private
+ NSInteger _eventType;
+}
+
+#pragma mark Creating an Entry /** @name Creating an Entry */
+
+/**
+ * Designated initializer.
+ */
+- (id)initWithType:(NSInteger)type;
+
+
+#pragma mark Entry Information /** @name Entry Information */
+
+/**
+ * The type of event.
+ */
+@property (nonatomic, readwrite, assign) NSInteger type;
+
+@end
View
186 src/overview/src/NIOverviewLogger.m
@@ -0,0 +1,186 @@
+//
+// Copyright 2011 Jeff Verkoeyen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#import "NIOverviewLogger.h"
+
+NSString* const NIOverviewLoggerDidAddConsoleLog = @"NIOverviewLoggerDidAddConsoleLog";
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+@implementation NIOverviewLogger
+
+@synthesize oldestLogAge = _oldestLogAge;
+@synthesize deviceLogs = _deviceLogs;
+@synthesize consoleLogs = _consoleLogs;
+@synthesize eventLogs = _eventLogs;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)dealloc {
+ NI_RELEASE_SAFELY(_deviceLogs);
+ NI_RELEASE_SAFELY(_consoleLogs);
+ NI_RELEASE_SAFELY(_eventLogs);
+
+ [super dealloc];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (id)init {
+ if ((self = [super init])) {
+ _deviceLogs = [[NILinkedList alloc] init];
+ _consoleLogs = [[NILinkedList alloc] init];
+ _eventLogs = [[NILinkedList alloc] init];
+
+ _oldestLogAge = 60;
+ }
+ return self;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)pruneEntriesFromLinkedList:(NILinkedList *)ll {
+ NSDate* cutoffDate = [NSDate dateWithTimeIntervalSinceNow:-_oldestLogAge];
+ while ([[((NIOverviewLogEntry *)[ll firstObject])
+ timestamp] compare:cutoffDate] == NSOrderedAscending) {
+ [ll removeFirstObject];
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)addDeviceLog:(NIOverviewDeviceLogEntry *)logEntry {
+ [self pruneEntriesFromLinkedList:_deviceLogs];
+
+ [_deviceLogs addObject:logEntry];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)addConsoleLog:(NIOverviewConsoleLogEntry *)logEntry {
+ [_consoleLogs addObject:logEntry];
+
+ [[NSNotificationCenter defaultCenter] postNotificationName: NIOverviewLoggerDidAddConsoleLog
+ object: nil
+ userInfo:
+ [NSDictionary dictionaryWithObject:logEntry forKey:@"entry"]];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)addEventLog:(NIOverviewEventLogEntry *)logEntry {
+ [self pruneEntriesFromLinkedList:_eventLogs];
+
+ [_eventLogs addObject:logEntry];
+}
+
+
+@end
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+@implementation NIOverviewLogEntry
+
+@synthesize timestamp = _timestamp;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)dealloc {
+ NI_RELEASE_SAFELY(_timestamp);
+
+ [super dealloc];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (id)initWithTimestamp:(NSDate *)timestamp {
+ if ((self = [super init])) {
+ _timestamp = [timestamp retain];
+ }
+ return self;
+}
+
+
+@end
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+@implementation NIOverviewDeviceLogEntry
+
+@synthesize bytesOfFreeMemory = _bytesOfFreeMemory;
+@synthesize bytesOfTotalMemory = _bytesOfTotalMemory;
+@synthesize bytesOfTotalDiskSpace = _bytesOfTotalDiskSpace;
+@synthesize bytesOfFreeDiskSpace = _bytesOfFreeDiskSpace;
+@synthesize batteryLevel = _batteryLevel;
+@synthesize batteryState = _batteryState;
+
+@end
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+@implementation NIOverviewConsoleLogEntry
+
+@synthesize log = _log;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (void)dealloc {
+ NI_RELEASE_SAFELY(_log);
+
+ [super dealloc];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (id)initWithLog:(NSString *)log {
+ if ((self = [super initWithTimestamp:[NSDate date]])) {
+ _log = [log copy];
+ }
+
+ return self;
+}
+
+
+@end
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+@implementation NIOverviewEventLogEntry
+
+@synthesize type = _type;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+- (id)initWithType:(NSInteger)type {
+ if ((self = [super initWithTimestamp:[NSDate date]])) {
+ _type = type;
+ }
+
+ return self;
+}
+
+
+@end
View
168 src/overview/src/NIOverviewPageView.h
@@ -0,0 +1,168 @@
+//
+// Copyright 2011 Jeff Verkoeyen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unl