Operating system requirements: iOS 5.0 or later.
Mobile device: iPad.
This example displays dashboard growth indicator and then a modal window with a message. They are hidden in three seconds. After that a mailing window is displayed.
The development environment console also displays the number of dashboard settings, dashboard data description, a modal window message and a dimension panel title.
Executing the example requires to place the following code instead of the executeExample method of the ViewController class (see the Displaying of Dashboard section):
// Get custom example placed in the body of this method
-(void) executeExample {
// Get dashboard controller
MABaseReportViewController *controller = m_controller;
// Enter the number of dashboard settings
NSDictionary *settings = [[controller delegate] reportSettings];
if(settings != nil){
NSLog(@"Number of dashboard settings: %i", [settings count]);
}
// Display dashboard loading indicator
[controller showActivityIndicator];
// Continue executing the example after a pause
[self performSelector:@selector(continueExample:) withObject:controller afterDelay:3];
}
// Continue executing the example
-(void) continueExample:(MABaseReportViewController *)controller {
// Get dashboard title
NSString *title = @"";
if ([[(MADashboardReportViewController*)controller delegate] title]) {
title = [[(MADashboardReportViewController*)controller delegate] title];
}
// Display modal window with message
[controller showWaiterWithTitle:title andMessage:@" Loading"];
// Display modal window message
NSString *message = [[controller waiterView] message];
NSLog(@"Modal window message: %@", message);
// Start time for three seconds
[NSTimer scheduledTimerWithTimeInterval:3.0f target:self selector:@selector(timerEvent)userInfo:nil repeats:NO];
}
// Handle time event
-(void) timerEvent {
// Get dashboard controller
MADashboardReportViewController *controller = (MADashboardReportViewController*)m_controller;
// Display dashboard data description
NSData *dashboardData = [[controller delegate] dashboardData];
if(dashboardData != nil)
NSLog(@"Dashboard data description: %@", dashboardData);
// Display dimension panel title
NSString *dimPanelTitle = [[[controller delegate] dimensionsPanel] title];
if(dimPanelTitle != nil)
NSLog(@"Dimension panel title: %@", dimPanelTitle);
// Hide modal window with message
[controller hideWaiter];
// Hide loading indicator
[controller hideActivityIndicator];
// Display mailing window
[controller composeMail];
}
It is also required to replace the code in the static example file MADashboardReportViewController.mm with the code given in the drop-down list:

Substitution code for the MADashboardReportViewController.mm file.
#import "MADashboardReportViewController.h"
#import "MADashboardReportViewControllerDelegate.h"
#import "UIView+Screenshot.h"
#import "APXMLParser.h"
#import "UIColor+hex.h"
#import "TransparentToolbar.h"
#import "MADataReportActionViewController.h"
#import "APCompositeBlock.h"
#import "MAReportAccessRights.h"
#include "PPLAccessRightsManager.h"
#import "NuGridController.h"
#import "NuGridView.h"
#import "MAGridDataViewControllerPrivate.h"
#import "MATextDataViewController.h"
#import "MAWebDataViewController.h"
#import "MAImageDataViewController.h"
#import "MADataReportViewController.h"
#import "BackButtonHandlerProtocol.h"
#import "MAProceduralReportDataViewController.h"
extern NSString *DATASOURCE_CHANGED_NOTIFICATION;
@implementation MADashboardReportViewController {
PanelViewController *m_panelViewController;
SplitViewController *m_splitViewController;
BOOL m_viewSettingsPopoverDisplayed;
UIAlertView *m_waiterView;
int m_screenshotCounter;
BOOL m_hasControls;
NSMutableDictionary *m_localScreenshots;
NSMutableSet *m_readyForScreenshotControllers;
BOOL m_shouldBackAction;
BOOL m_dashboardSetSelection;
}
@synthesize splitViewController = m_splitViewController, panelViewController = m_panelViewController;
@synthesize delegate = m_delegate, report = m_report;
@synthesize waiterView = m_waiterView;
// Initialize delegate based controller
- (id) initWithDelegate: (id<MADashboardReportViewControllerDelegate>)delegate {
if ((self = [super initWithDelegate: delegate])) {
m_dashboardSetSelection = NO;
m_shouldBackAction = YES;
NSAssert(self.delegate, @"ReportDelegate not nil");
// Get path to dashboard resources
NSArray *resourcesPaths = [m_delegate dashboardResourcesPath];
// Get path to MIME types of dashboard resources
NSArray *resourcesMimesTypes = [m_delegate dashboardResourcesMimeTypes];
NSString *xmlPath;
for (int i = 0; i < [resourcesMimesTypes count]; i++) {
if ([(NSString *)[resourcesMimesTypes objectAtIndex:i] isEqualToString:@"application/xml"]) {
xmlPath = (NSString *)[resourcesPaths objectAtIndex:i];
}
}
NSData *xmlData = [NSData dataWithContentsOfFile:xmlPath];
APXMLParserObject *structure = [APXMLParser parseXML:xmlData];
m_report = [APKap alloc];
[m_report initWithParserObject:structure delegate:self];
BOOL handleAllControls = YES;
for (APCompositeBlock *i in m_report.compositeBlocks.allValues)
{
if (i.hasParamsBlock) {
handleAllControls = NO;
break;
}
}
for (APCompositeBlock *i in m_report.compositeBlocks.allValues)
{
i.handleAllControls = handleAllControls;
}
LOG(@"handleAllControls: %d", handleAllControls);
NSArray *blocks = [structure findObjectsOfElementName:@"block"];
if (self.delegate.hasSelectionSynchronizationConfig) {
for (APXMLParserObject *i in blocks) {
NSString * controlKey = [i.attributes objectForKey:@"key"];
if ([[i.attributes objectForKey:@"type"] isEqualToString:@"Control"]) {
m_hasControls = YES;
APXMLParserObject *syncIndexKey = [i objectPropForKey:@"syncIndex"];
if (syncIndexKey) {
NSNumber *value = [syncIndexKey.attributes objectForKey:@"val"];
// Creates an object describing dashboard control with specified key and dimension panel synchronization key
[self.delegate addDimensionPanelControlWithKey:controlKey syncIndexKey: [value intValue]];
}
} else {
APXMLParserObject* title = [i objectPropForKey:@"title"];
if (title) {
APXMLParserObject* show = [title objectPropForKey:@"show"];
NSNumber* val = [NSNumber numberWithInt:0];
if (show) {
val = [show.attributes objectForKey:@"val"];
}
if ([val intValue] == 1) {
APXMLParserObject* text = [title objectPropForKey:@"text"];
NSString* textVal = [NSString string];
if (text) {
textVal = [text.attributes objectForKey:@"val"];
}
if (![textVal isEqualToString:@""]) {
[m_report.dataViewsTitles setObject:textVal forKey:controlKey];
}
}
}
}
}
}
// Create a dashboard split view controller with sliding dimension panel
m_splitViewController = [SplitViewController new];
// Create a dimension panel controller
m_panelViewController = [PanelViewController new];
m_panelViewController.delegate = self;
[m_panelViewController setPanelTitle:NSLocalizedString(@"Controls", @"DimPanel:Title")];
[self.delegate pullSelection];
if (m_hasControls) {
m_splitViewController.panelViewController = m_panelViewController;
}
m_splitViewController.firstViewVisible = NO;
self.report.isfullScreenEnabled = self.delegate.hasScreenshot;
[self addObserverDataSourceChanged];
m_localScreenshots = [NSMutableDictionary new];
m_readyForScreenshotControllers = [NSMutableSet new];
}
return self;
}
// Apply selected dimension element selection
- (void) panelViewDidHide:(PanelViewController *)panelController {
[self.delegate pushSelection];
}
// Load selected dimension element selections
- (void) panelViewDidShow:(PanelViewController *)panelController {
[self.delegate pullSelection];
}
// Sunscribe for data source change event
- (void) addObserverDataSourceChanged
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updatePanelViewVisibility:)
name:DATASOURCE_CHANGED_NOTIFICATION
object:nil];
}
// Unsubscribe from data source change event
- (void) removeObserverDataSourceChanged
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:DATASOURCE_CHANGED_NOTIFICATION object:nil];
}
// Refresh panel visibility state
- (void) updatePanelViewVisibility: (id) sender
{
if (m_splitViewController.panelViewController) {
m_splitViewController.panelViewController.view.hidden =
[self.delegate dimensionsPanel].dimensionsCount <= 0;
}
}
// Create and set up table data view controller
- (MAGridDataViewController *)createGridDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey {
MAGridDataViewController *controller = [self.delegate createGridDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.delegate = self;
[(UIScrollView *)controller.gridController.view setBounces: NO];
return controller;
}
// Create and set up map data view controller
- (MAMapDataViewController *)createMapDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey {
MAMapDataViewController *controller = [self.delegate createMapDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.delegate = self;
return controller;
}
// Create and set up bubble tree data view controller
- (MABubbleTreeDataViewController *)createBubbleTreeDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey {
MABubbleTreeDataViewController *controller = [self.delegate createBubbleTreeDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.delegate = self;
return controller;
}
// Create and set up chart data view controller
- (MAChartDataViewController *)createChartDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey {
MAChartDataViewController *controller = [self.delegate createChartDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.delegate = self;
return controller;
}
// Create and set up bubble chart data view controller
- (MABubbleDataViewController *)createBubbleDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey {
MABubbleDataViewController *controller = [self.delegate createBubbleDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.delegate = self;
return controller;
}
// Create and set up tree map data view controller
- (MATreeMapDataViewController *)createTreeMapDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey {
MATreeMapDataViewController *controller = [self.delegate createTreeMapDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.delegate = self;
return controller;
}
// Create and set up regular report data view controller
- (MAProceduralReportDataViewController *)createProceduralReportDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey {
MAProceduralReportDataViewController *controller = [self.delegate createProceduralReportDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.reportController = (MADataReportViewController *)self;
return controller;
}
// Create and set up express report data view controller
- (MADataViewController *)createExpressReportDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey
{
MADataViewController *controller = [self.delegate createExpressReportDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.delegate = (MADataReportViewController *)self;
return controller;
}
// Create and set up text data view controller
- (MATextDataViewController *)createTextDataViewController
{
MATextDataViewController *controller = [[MATextDataViewController alloc] init];
controller.delegate = self;
return controller;
}
// Create and set up browser data view controller
- (MAWebDataViewController *)createWebDataViewController
{
MAWebDataViewController *controller = [[MAWebDataViewController alloc] init];
controller.delegate = self;
return controller;
}
// Create and set up static image data view controller
- (MAImageDataViewController *)createImageDataViewController
{
MAImageDataViewController *controller = [[MAImageDataViewController alloc] init];
controller.delegate = self;
return controller;
}
// Return repository data source key by dashboard block key
- (NSString *)metabaseKeyByBlockKey:(NSString *)key {
return [self.delegate metabaseKeyByBlockKey:key];
}
// Create a dashboard empty button
- (UIBarButtonItem *)barSpace {
UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
return [space autorelease];
}
// Create a dashboard button
- (UIBarButtonItem *)createRightBarItem {
double height = 44;
UIToolbar *result = [[[TransparentToolbar alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, height)] autorelease];
result.autoresizingMask = UIViewAutoresizingFlexibleHeight;
result.backgroundColor = [UIColor clearColor];
NSMutableArray *buttons = [NSMutableArray new];
UIBarButtonItem *button = nil;
if (m_report.fullScreenBlockKey) {
id<MADataViewControllerProtocol>dataView = [m_report.dataViews objectForKey:m_report.fullScreenBlockKey];
NSArray *customButtons = [dataView barButtonItems];
if ([customButtons count]) {
[buttons addObjectsFromArray:customButtons];
}
if (dataView.hasSettingsController) {
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"i.png"] style:UIBarButtonItemStylePlain target:self action:@selector(dataViewSettingsAction:)];
[buttons addObject:button];
[button release];
[buttons addObject:[self barSpace]];
}
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithImage:nil style:UIBarButtonItemStylePlain target:self action:nil];
[buttons addObject:backButton];
[backButton release];
} else {
if ([m_report.compositeBlocks count]>1) {
button = [[[UIBarButtonItem alloc] initWithTitle: m_report.slideMode?NSLocalizedString(@"Slide: ON", @"APViewController :: Slide: ON"):NSLocalizedString(@"Slide: OFF", @"APViewController :: Slide: OFF")
style:UIBarButtonItemStylePlain
target:self
action:@selector(slideModeAction:)] autorelease];
[buttons addObject:button];
}
button = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(reportAction:)];
[buttons addObject:button];
[button release];
}
[result setItems:buttons];
[buttons release];
CGSize bestSize = [result sizeThatFits:result.frame.size];
CGRect frame = result.frame;
frame.size = bestSize;
result.frame = frame;
return [[[UIBarButtonItem alloc] initWithCustomView:result] autorelease];
}
// Set dashboard elements
- (void) setBarButtonItems:(NSArray *)items forDataViewController:(id<MADataViewControllerProtocol>)controller {
self.navigationItem.rightBarButtonItem = [self createRightBarItem];
}
//
- (void) slideModeAction: (id) sender {
if (!self.delegate.hasScreenshot) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", @"Error")
message:NSLocalizedString(@"Cannot switch to Slideshow mode",
@"Cannot switch to Slideshow mode")
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil];
[alert show];
[alert release];
return;
}
[self showWaiter];
for (MADataViewController *i in m_report.compositeBlocks.allValues) {
i.view.hidden = YES;
}
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
m_report.slideMode = !m_report.slideMode;
self.navigationItem.rightBarButtonItem = [self createRightBarItem];
[self hideWaiter];
}
// Handle dashboard action event
- (void) reportAction: (id) sender {
MAReportAccessRights *rights = m_delegate.accessRights;
BOOL isReadonly = !rights.canWrite;
MADataReportActionViewController *controller = [[[MADataReportActionViewController alloc] initWithDelegate:self readOnly:isReadonly] autorelease];
// Display controller in popup window from specified element
[self showInPopover:controller fromBarButtonItem:sender];
}
// Handle data view settings action event
- (void) dataViewSettingsAction:(id) sender {
if (m_popoverController) {
[self hidePopover];
m_viewSettingsPopoverDisplayed = NO;
return;
}
UIViewController<PopoverContainedControllerProtocol> *controller = (UIViewController<PopoverContainedControllerProtocol> *)[(id<MADataViewControllerProtocol>)[m_report.dataViews objectForKey:m_report.fullScreenBlockKey] settingsController];
m_viewSettingsPopoverDisplayed = YES;
[self showInPopover:controller fromBarButtonItem:sender];
}
// Handle popup window hide event
- (void) popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
if (m_viewSettingsPopoverDisplayed) {
UINavigationController *nav = (UINavigationController *)popoverController.contentViewController;
UIViewController<PopoverContainedControllerProtocol> *ctl = (UIViewController<PopoverContainedControllerProtocol> *)[[nav viewControllers] objectAtIndex:0];
[(id<MADataViewControllerProtocol>)[m_report.dataViews objectForKey:m_report.fullScreenBlockKey] settingsControllerClosed:ctl];
}
m_viewSettingsPopoverDisplayed = NO;
[m_popoverController release];
m_popoverController = nil;
}
// Handle full-screen mode exit event
- (void) fullscreenDismissAction:(id) sender {
m_shouldBackAction = YES;
if (m_popoverController) {
if (m_viewSettingsPopoverDisplayed) {
UINavigationController *nav = (UINavigationController *)m_popoverController.contentViewController;
UIViewController<PopoverContainedControllerProtocol> *ctl = (UIViewController<PopoverContainedControllerProtocol> *)[[nav viewControllers] objectAtIndex:0];
[(id<MADataViewControllerProtocol>)[m_report.dataViews objectForKey:m_report.fullScreenBlockKey] settingsControllerClosed:ctl];
m_viewSettingsPopoverDisplayed = NO;
}
[m_popoverController dismissPopoverAnimated:YES];
[m_popoverController release];
m_popoverController = nil;
}
[m_splitViewController setHasControls:m_hasControls];
m_splitViewController.firstViewVisible = NO;
// Inform that data view controller exits full-screen mode
[self.delegate dataViewWillLeaveFullscreen:(id<MADataViewControllerProtocol>)[m_report.dataViews objectForKey:m_report.fullScreenBlockKey]];
[m_report dismissFullscreenCompositeBlock];
[self updatePanelViewVisibility:nil];
}
// Display full-screen block controls
- (void)showControlsForFullscreenBlock: (NSString *)blockKey {
m_shouldBackAction = NO;
self.navigationController.navigationBar.backItem.title = NSLocalizedString(@"Back", @"APViewController :: Report: Back");
self.navigationItem.rightBarButtonItem = [self createRightBarItem];
// Inform that block enters to full-screen mode
[self.delegate didSelectedBlockWithKey:blockKey];
if (!m_hasControls) {
m_splitViewController.panelViewController = m_panelViewController;
[m_splitViewController setHasControls:YES];
}
m_splitViewController.splitView.fixSecondViewSize = NO;
m_splitViewController.splitView.titleView.titleLabel.text = self.reportTitle;
m_splitViewController.splitView.hasTitle = YES;
[m_panelViewController setPanelTitle:NSLocalizedString(@"Layout", @"DimPanel:Title")];
NSLog(@"setting title %@", self.title);
m_splitViewController.firstViewVisible = NO;
}
// Hide full-screen block controls
- (void)hideControlsForFullscreenBlock:(NSString *)blockKey {
self.navigationItem.rightBarButtonItem = [self createRightBarItem];
m_shouldBackAction = NO;
self.navigationController.navigationBar.backItem.title = NSLocalizedString(@"Back", @"APViewController :: Report: Back");
m_splitViewController.panelViewController = nil;
m_splitViewController.splitView.fixSecondViewSize = NO;
m_splitViewController.splitView.hasTitle = YES;
m_splitViewController.splitView.titleView.titleLabel.text = self.reportTitle;
[m_panelViewController setPanelTitle:NSLocalizedString(@"Layout", @"DimPanel:Title")];
NSLog(@"setting title %@", self.title);
m_splitViewController.firstViewVisible = NO;
[self.delegate didSelectedBlockWithKey:blockKey];
}
// Exit blocks from full-screen mode
- (void)dismissControlsForFullscreenBlock {
self.navigationItem.rightBarButtonItem = [self createRightBarItem];
m_splitViewController.splitView.fixSecondViewSize = YES;
m_splitViewController.splitView.hasTitle = NO;
[m_panelViewController setPanelTitle:NSLocalizedString(@"Controls", @"DimPanel:Title")];
// Inform that block exits full-screen mode
[self.delegate didDismissedBlock];
if (!m_hasControls) {
m_splitViewController.panelViewController = nil;
}
}
// Load dashboard data view
- (void)loadView {
[super loadView];
[self.view addSubview:m_splitViewController.view];
// Set up split view controller
m_splitViewController.splitView.overlap = 44.0;
m_splitViewController.splitView.titleHeight = 50.0;
m_splitViewController.splitView.titleView.backgroundColor = [UIColor colorWithHex:@"#e3e7ec"];
m_splitViewController.splitView.titleView.bottomLineColor = [UIColor whiteColor];
m_splitViewController.splitView.hasTitle = NO;
m_splitViewController.splitView.titleView.titleLabel.text = self.reportTitle;
m_splitViewController.contentViewController = m_report;
m_splitViewController.splitView.fixSecondViewSize = YES;
m_splitViewController.firstViewVisible = NO;
m_splitViewController.noResizeUntilAnimated = YES;
[m_splitViewController setHasControls:m_hasControls];
self.navigationItem.rightBarButtonItem = [self createRightBarItem];
// Refresh pivot objects for building data tables
[self.delegate refreshPivots];
for (NSString *i in m_report.compositeBlocks) {
// Save composite block
[m_delegate setCompositeBlock:[m_report.compositeBlocks objectForKey:i] forBlockKey:i];
}
// If there is a list of settings
if (!self.delegate.hasSelectionSynchronizationConfig) {
for (APCompositeBlock *i in m_report.compositeBlocks.allValues) {
if (i.handleSelectionBus) {
for (APCompositeBlock *j in m_report.compositeBlocks.allValues) {
if (i == j) continue;
for (NSString *handleBlockKey in i.handleBlockKeys) {
if ([handleBlockKey isEqualToString: j.key]) {
// Link dashbgoard blocks
[self.delegate addSlaveBlock:i.key toMasterBlock:j.key];
}
}
}
}
}
// Set up linking of blocks by dashboard settings
} else [self.delegate configureSelectionWithConfig];
}
// Display loading indicator
- (void) showActivityIndicator {
NSLog(@"************* showWaiter");
[self.splitViewController showWaiter];
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
}
// Hide loading indicator
- (void) hideActivityIndicator {
NSLog(@"************* hideWaiter");
[self.splitViewController hideWaiter];
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
if (![self.delegate hasScreenshot]) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
UIImage *image = [self screenshot];
[self.delegate setScreenshot:UIImagePNGRepresentation(image)];
self.report.isfullScreenEnabled = YES;
});
}
}
// Link dashobard blocks
- (void) addSlaveBlock:(NSString *)slaveKey toMasterBlock:(NSString *)masterKey {
[self.delegate addSlaveBlock:slaveKey toMasterBlock:masterKey];
}
// Display settings bar
- (void) dataViewController: (id<MADataViewControllerProtocol>) ctl showSettingsController: (UIViewController<PopoverContainedControllerProtocol> *) settings fromView: (UIView *) view {
// Display panel in popup window of specified dashboard data view
[self showInPopover:settings fromView:view];
}
// Save screenshot to drawing context
- (void) captureScreenshotToContext:(CGContextRef)context {
[self.view.layer renderInContext:context];
}
// Insert image inside another image
+ (UIImage *)insertImage:(UIImage *)image2 inImage:(UIImage *)image1 inRect:(CGRect)rect
{
UIGraphicsBeginImageContext(image1.size);
[image1 drawInRect:CGRectMake(0, 0, image1.size.width, image1.size.height)];
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(ctx, UIColor.whiteColor.CGColor);
CGContextFillRect(ctx, rect);
[image2 drawInRect:rect];
UIImage *output = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return output;
}
// Create a screenshot
- (UIImage *) screenshot {
UIView *annoyingView = m_panelViewController.view;
BOOL oldvisible = annoyingView.layer.hidden;
annoyingView.layer.hidden = YES;
UIGraphicsBeginImageContext(self.view.bounds.size);
CGContextRef contextRef = UIGraphicsGetCurrentContext();
[self.view.layer renderInContext:contextRef];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
annoyingView.layer.hidden = oldvisible;
for (NSString *q in m_report.compositeBlocks) {
APCompositeBlock *i = [m_report.compositeBlocks objectForKey:q];
MADataViewController *v = [m_report.dataViews objectForKey:q];
if ([i.type isEqualToString:@"Map"] || ([i.type isEqualToString:@"TreeMap"]) ||([i.type isEqualToString:@"BubbleTree"])) {
CGRect insertionRect = [i.view convertRect:v.view.bounds toView:self.view];
insertionRect.origin.x += 2;
insertionRect.origin.y += 53;
UIImage *localScreenshot = v.screenshot;
screenshot = [MADashboardReportViewController insertImage:localScreenshot inImage:screenshot inRect:insertionRect];
}
}
return screenshot;
}
#pragma mark BaseSettingsViewControllerDelegate
// Execute action with dashboard
- (void) performSettingsAction:(NSString *)key {
[self hidePopover];
if ([key isEqualToString:kDataReportMailAction]) { // Sending email
[self composeMail];
} else if ([key isEqualToString:kDataReportSaveAction]) { // Saving dashboard settings
[self showWaiterWithTitle:NSLocalizedString(@"Saving...", @"saving message") andMessage:nil];
[self performSelector:@selector(saveReport) withObject:nil afterDelay:0.1];
}
}
// Save dashboard settings
- (void) saveReport {
UIImage *image = [self screenshot];
[self.delegate setScreenshot:UIImagePNGRepresentation(image)];
// Save dashboard settings
[self.delegate saveReport];
[self hideWaiter];
}
// Execute action with dashboard with additional parameters
- (void) performSettingsAction:(NSString *)key withParameter:(NSObject *)params {
[self hidePopover];
if ([key isEqualToString:kSaveFavoriteAction]) {
if (!self.delegate.hasSelectionSynchronizationConfig) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Legacy report", @"legacy report")
message:NSLocalizedString(@"Adding legacy reports to favorites is not supported", @"legacy report error message")
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil];
[alert show];
[alert release];
} else {
[self showWaiterWithTitle:NSLocalizedString(@"Please Wait...", nil) andMessage:nil];
[self performSelector:@selector(addToFavorites:) withObject:(NSString *)params afterDelay:0.5];
}
}
}
// Add dashboard to favorites
- (void)addToFavorites:(NSString *)name
{
[self.delegate saveFavoriteWithName:name];
[self hideWaiter];
}
// Display dashboard data views
- (void) viewDidLayoutSubviews {
m_splitViewController.view.frame = self.view.bounds;
}
- (void) dealloc {
for (MADataViewController *i in m_report.dataViews.allValues) {
i.delegate = nil;
}
[m_report release];
[m_panelViewController release];
[m_splitViewController release];
[self removeObserverDataSourceChanged];
[m_localScreenshots release];
[m_readyForScreenshotControllers release];
[super dealloc];
}
// Display waiting window
- (void)showWaiter
{
if (!m_waiterView) {
m_waiterView = [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Switching...", nil)
message:nil
delegate:self
cancelButtonTitle:nil
otherButtonTitles:nil] autorelease];
UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityView.frame = CGRectMake(139.0f - 18.0f, 50.0f, 37.0f, 37.0f);
[activityView startAnimating];
[m_waiterView addSubview:activityView];
[m_waiterView show];
[activityView release];
}
}
// Hide waiting window
- (void)hideWaiter
{
[m_waiterView dismissWithClickedButtonIndex:0 animated:YES];
m_waiterView = nil;
}
#pragma mark MADataViewControllerDelegate
// Handle data view controller availability change event
- (void) dataViewController: (id<MADataViewControllerProtocol>) ctl availabilityUpdated:(BOOL) availability {
if (availability) {
[self dataViewControllerDidFinishCalculations:ctl];
} else {
[self dataViewControllerWillStartCalculations:ctl];
}
}
// Handle data view controller calculation start event
- (void) dataViewControllerWillStartCalculations: (id<MADataViewControllerProtocol>) ctl {
NSString *key = [[[m_report dataViews] allKeysForObject:ctl] lastObject];
if (self.report.fullScreenBlockKey && [self.report.fullScreenBlockKey isEqual:key]) {
[self showActivityIndicator];
} else {
APCompositeBlock *block = [[m_report compositeBlocks] objectForKey:key];
[block dataViewControllerWillStartCalculations];
}
}
// Handle data view controller calculation end event
- (void) dataViewControllerDidFinishCalculations: (id<MADataViewControllerProtocol>) ctl {
NSString *key = [[[m_report dataViews] allKeysForObject:ctl] lastObject];
if (self.report.fullScreenBlockKey && [self.report.fullScreenBlockKey isEqual:key]) {
[self hideActivityIndicator];
} else {
NSString *key = [[[m_report dataViews] allKeysForObject:ctl] lastObject];
APCompositeBlock *block = [m_report.compositeBlocks objectForKey:key];
[block dataViewControllerDidFinishCalculations];
}
}
// Inform that data view controller is ready to create a screenshot
- (void) dataViewControllerReadyForScreenshot:(id<MADataViewControllerProtocol>)ctl
{
if ([self.delegate hasScreenshot]) return;
BOOL dashboardHasGrid = NO;
for(MADataViewController *controller in [m_report.dataViews allValues]) {
if([controller isKindOfClass:[MAGridDataViewController class]]) {
dashboardHasGrid = YES;
break;
}
}
BOOL uncheckingClass = dashboardHasGrid ? [ctl isKindOfClass:[MABubbleTreeDataViewController class]] || [ctl isKindOfClass:[MATreeMapDataViewController class]] || [ctl isKindOfClass:[MAMapData3DViewController class]] || [ctl isKindOfClass:[MAImageDataViewController class]] || [ctl isKindOfClass:[MAWebDataViewController class]] || [ctl isKindOfClass:[MATextDataViewController class]] : YES;
if ([ctl isKindOfClass:[MAGridDataViewController class]]) {
m_dashboardSetSelection = [(MAGridDataViewController*)ctl noStartupSelection] || [(MAGridDataViewController*)ctl gridSelection].count > 0;
if (m_dashboardSetSelection) {
for(MADataViewController *controller in [m_report.dataViews allValues]) {
if(![controller isKindOfClass:[MAGridDataViewController class]]) {
[controller updateDataWithGridSelection];
}
}
}
}
if (m_dashboardSetSelection || uncheckingClass) {
NSValue *v = [NSValue valueWithNonretainedObject:ctl];
if ([m_readyForScreenshotControllers containsObject:v])
return;
[m_readyForScreenshotControllers addObject:v];
if (m_screenshotCounter == 0)
[m_localScreenshots removeAllObjects];
CGRect place = ctl.view.bounds;
place = [self.view convertRect:place fromView:ctl.view];
UIImage *ctlScreenshot = ctl.screenshot;
[m_localScreenshots setObject:ctlScreenshot forKey:[NSValue valueWithCGRect:place]];
m_screenshotCounter++;
if (m_screenshotCounter == [m_report.dataViews count]) {
UIView *annoyingView = m_panelViewController.view;
BOOL oldvisible = annoyingView.layer.hidden;
annoyingView.layer.hidden = YES;
UIGraphicsBeginImageContext(self.view.bounds.size);
CGContextRef contextRef = UIGraphicsGetCurrentContext();
[self.view.layer renderInContext:contextRef];
annoyingView.layer.hidden = oldvisible;
[m_localScreenshots enumerateKeysAndObjectsUsingBlock:^(NSValue *key, UIImage *localScreenshot, BOOL *bStop){
CGRect rect = key.CGRectValue;
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(ctx, UIColor.whiteColor.CGColor);
CGContextFillRect(ctx, rect);
[localScreenshot drawInRect:rect];
}];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *data = UIImagePNGRepresentation(screenshot);
[self.delegate setScreenshot:data];
self.report.isfullScreenEnabled = YES;
[m_localScreenshots removeAllObjects];
[m_readyForScreenshotControllers removeAllObjects];
}
}
}
// Get dashboard settings dictionary
- (NSDictionary *) configurationForDataViewController: (id<MADataViewControllerProtocol>) controller {
return [self.delegate configurationForDataViewController:controller];
}
// Get saved dashboard data view controller settings
- (NSData *) stateForDataViewController: (id<MADataViewControllerProtocol>) controller {
return [self.delegate stateForDataViewController:controller];
}
// Save dashboard data view controller settings
- (void) setState: (NSData *) state forDataViewController: (id<MADataViewControllerProtocol>) controller {
[self.delegate setState:state forDataViewController:controller];
}
// Inform that data view controller changed data sample
- (void) dataViewControllerChangedSelection:(id<MADataViewControllerProtocol>)controller {
[self.delegate dataViewControllerChangedSelection:controller];
}
// Refresh dashboard title
- (void) dataViewControllerReloadTitle:(id<MADataViewControllerProtocol>)controller {
m_splitViewController.splitView.titleView.titleLabel.text = self.reportTitle;
}
// Return dashboard title
- (NSString *)reportTitle {
if (!m_report.fullScreenBlockKey) {
return self.delegate.title;
} else {
NSString *title = [m_report.dataViewsTitles objectForKey:m_report.fullScreenBlockKey];
if (title) {
return title;
} else {
id<MADataViewControllerProtocol>dataView = [m_report.dataViews objectForKey:m_report.fullScreenBlockKey];
return dataView.dataViewTitle;
}
}
}
@end
Replace the body of the addDimensionPanelControlWithKey:syncIndexKey: method in the MADashboardReportViewControllerDelegateImpl class with the following code:
// Determine dimension key
int64 dimensionKey = -1;
// Determine array of observer dimensions
NSMutableArray *listenerKeys = [NSMutableArray array];
// Get dimension key and array of observer dimension keys
N_FOREACH(SPPLDashboardSynchronizationDimension, i, m_dashboardReport->synchronizationDimensions()->dimensions()) {
SPPLDashboardDataSourceDimensionObject dimensionObject = i->dimensionObject();
if (i->syncIndexKey() == syncIndexKey && dimensionObject->isOriginal()) {
dimensionKey = dimensionObject->key();
[listenerKeys addObject:dimensionObject->dataSourceObject()->dashboardRelatedId()->nsString()];
}
}
// Creates an object describing dashboard control
[self addDimensionPanelControlWithKey:key dimensionKey:dimensionKey listenerKeys:listenerKeys];
Replace the code of the createReport:metabase: method in the MADashboardReportViewControllerFactory.m file with the following code:
// Create a controller delegate for working with dashboard MADashboardReportDelegateImpl *delegate = [[[MADashboardReportDelegateImpl alloc] initWithDashboardReport:dashboardReport metabase:metabase] autorelease]; // Create a dashboard based on delegate MADashboardReportViewController *report = [[[MADashboardReportViewController alloc] initWithDelegate:delegate] autorelease]; // Set dimension panel report.panelViewController.contentViewController = delegate.dimensionsPanel; return report;
After executing the example the dashboard loading indicator is displayed:

A modal window with a message is displayed against the shaded background in three seconds:

The development environment console also displays information about dashboard:
Modal window message: Loading
The dashboard loading indicator and the message window are hidden in three seconds, after that the mailing window is displayed:

See also: