Требования к операционной системе: iOS 5.0 и выше.
Мобильное устройство: iPad.
В данном примере отображаются индикатор загрузки аналитической панели, а затем модальное окно с сообщением. Через три секунды после их отображения они скрываются. После этого отображается окно отправки почты.
Также в консоль среды разработки выводится количество настроек аналитической панели, описание её данных, сообщение модального окна и заголовок панели измерений.
Для выполнения примера необходимо разместить вместо метода executeExample класса ViewController (см. раздел «Отображение аналитической панели») следующий код:
// Выполняем пользовательский пример, размещённый в теле данного метода
-(void) executeExample {
// Получаем контроллер аналитической панели
MABaseReportViewController *controller = m_controller;
// Выводим количество настроек аналитической панели
NSDictionary *settings = [[controller delegate] reportSettings];
if(settings != nil){
NSLog(@"Количество настроек аналитической панели: %i", [settings count]);
}
// Отображаем индикатор загрузки аналитической панели
[controller showActivityIndicator];
// Продолжаем выполнение примера после паузы
[self performSelector:@selector(continueExample:) withObject:controller afterDelay:3];
}
// Продолжаем выполнение примера
-(void) continueExample:(MABaseReportViewController *)controller {
// Получаем заголовок аналитической панели
NSString *title = @"";
if ([[(MADashboardReportViewController*)controller delegate] title]) {
title = [[(MADashboardReportViewController*)controller delegate] title];
}
// Отображаем модальное окно с сообщением
[controller showWaiterWithTitle:title andMessage:@" Выполняется загрузка"];
// Выводим сообщение модального окна
NSString *message = [[controller waiterView] message];
NSLog(@"Сообщение модального окна: %@", message);
// Запускаем таймер на три секунды
[NSTimer scheduledTimerWithTimeInterval:3.0f target:self selector:@selector(timerEvent)userInfo:nil repeats:NO];
}
// Обрабатываем событие таймера
-(void) timerEvent {
// Получаем контроллер аналитической панели
MADashboardReportViewController *controller = (MADashboardReportViewController*)m_controller;
// Выводим описание данных аналитической панели
NSData *dashboardData = [[controller delegate] dashboardData];
if(dashboardData != nil)
NSLog(@"Описание данных аналитической панели: %@", dashboardData);
// Выводим заголовок панели измерений
NSString *dimPanelTitle = [[[controller delegate] dimensionsPanel] title];
if(dimPanelTitle != nil)
NSLog(@"Заголовок панели измерений: %@", dimPanelTitle);
// Скрываем модальное окно с сообщением
[controller hideWaiter];
// Скрываем индикатор загрузки
[controller hideActivityIndicator];
// Отображаем окно отправки почты
[controller composeMail];
}
Также необходимо заменить код в файле статичного примера MADashboardReportViewController.mm на код, приведенный в раскрывающемся списке:

Замещающий код
для файла MADashboardReportViewController.mm.
#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;
// Инициализируем контроллер на основе делегата
- (id) initWithDelegate: (id<MADashboardReportViewControllerDelegate>)delegate {
if ((self = [super initWithDelegate: delegate])) {
m_dashboardSetSelection = NO;
m_shouldBackAction = YES;
NSAssert(self.delegate, @"ReportDelegate not nil");
// Получаем путь к ресурсам аналитической панели
NSArray *resourcesPaths = [m_delegate dashboardResourcesPath];
// Получаем путь к MIME-типам ресурсов аналитической панели
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"];
// Создаёт объект, описывающий элемент управления аналитической панели, с указанным ключом и ключом синхронизации измерений панели
[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];
}
}
}
}
}
}
// Создаем контроллер компоновки аналитической панели со сдвигающейся панелью измерений
m_splitViewController = [SplitViewController new];
// Создаем контроллер панели измерений
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;
}
// Применяем выбранную отметку элементов измерения
- (void) panelViewDidHide:(PanelViewController *)panelController {
[self.delegate pushSelection];
}
// Загружаем выбранные отметки элементов измерения
- (void) panelViewDidShow:(PanelViewController *)panelController {
[self.delegate pullSelection];
}
// Подписываемся на событие изменения источника данных
- (void) addObserverDataSourceChanged
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updatePanelViewVisibility:)
name:DATASOURCE_CHANGED_NOTIFICATION
object:nil];
}
// Отписываемся от события изменения источника данных
- (void) removeObserverDataSourceChanged
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:DATASOURCE_CHANGED_NOTIFICATION object:nil];
}
// Обновляем статус видимости панели
- (void) updatePanelViewVisibility: (id) sender
{
if (m_splitViewController.panelViewController) {
m_splitViewController.panelViewController.view.hidden =
[self.delegate dimensionsPanel].dimensionsCount <= 0;
}
}
// Создаем и настраиваем контроллер представления данных в виде таблицы
- (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;
}
// Создаем и настраиваем контроллер представления данных в виде карты
- (MAMapDataViewController *)createMapDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey {
MAMapDataViewController *controller = [self.delegate createMapDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.delegate = self;
return controller;
}
// Создаем и настраиваем контроллер представления данных в виде пузырькового дерева
- (MABubbleTreeDataViewController *)createBubbleTreeDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey {
MABubbleTreeDataViewController *controller = [self.delegate createBubbleTreeDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.delegate = self;
return controller;
}
// Создаем и настраиваем контроллер представления данных в виде диаграммы
- (MAChartDataViewController *)createChartDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey {
MAChartDataViewController *controller = [self.delegate createChartDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.delegate = self;
return controller;
}
// Создаем и настраиваем контроллер представления данных в виде пузырьковой диаграммы
- (MABubbleDataViewController *)createBubbleDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey {
MABubbleDataViewController *controller = [self.delegate createBubbleDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.delegate = self;
return controller;
}
// Создаем и настраиваем контроллер представления данных в виде плоского дерева
- (MATreeMapDataViewController *)createTreeMapDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey {
MATreeMapDataViewController *controller = [self.delegate createTreeMapDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.delegate = self;
return controller;
}
// Создаем и настраиваем контроллер представления данных в регламентном отчете
- (MAProceduralReportDataViewController *)createProceduralReportDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey {
MAProceduralReportDataViewController *controller = [self.delegate createProceduralReportDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.reportController = (MADataReportViewController *)self;
return controller;
}
// Создаем и настраиваем контроллер представления данных в экспресс-отчете
- (MADataViewController *)createExpressReportDataViewControllerWithMetabaseKey:(NSString *)key blockKey:(NSString *)blockKey
{
MADataViewController *controller = [self.delegate createExpressReportDataViewControllerWithMetabaseKey:key blockKey:blockKey];
controller.delegate = (MADataReportViewController *)self;
return controller;
}
// Создаем и настраиваем контроллер текстового отображения
- (MATextDataViewController *)createTextDataViewController
{
MATextDataViewController *controller = [[MATextDataViewController alloc] init];
controller.delegate = self;
return controller;
}
// Создаем и настраиваем контроллер представления данных в виде браузера
- (MAWebDataViewController *)createWebDataViewController
{
MAWebDataViewController *controller = [[MAWebDataViewController alloc] init];
controller.delegate = self;
return controller;
}
// Создаем и настраиваем контроллер представления данных в виде статичного изображения
- (MAImageDataViewController *)createImageDataViewController
{
MAImageDataViewController *controller = [[MAImageDataViewController alloc] init];
controller.delegate = self;
return controller;
}
// Возвращаем ключ источника данных в репозитории по ключу блока аналитической панели
- (NSString *)metabaseKeyByBlockKey:(NSString *)key {
return [self.delegate metabaseKeyByBlockKey:key];
}
// Создаем пустую кнопку панели
- (UIBarButtonItem *)barSpace {
UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
return [space autorelease];
}
// Создаем кнопку панели
- (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];
}
// Устанавливаем элементы панели
- (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];
}
// Обрабатываем событие действия аналитической панели
- (void) reportAction: (id) sender {
MAReportAccessRights *rights = m_delegate.accessRights;
BOOL isReadonly = !rights.canWrite;
MADataReportActionViewController *controller = [[[MADataReportActionViewController alloc] initWithDelegate:self readOnly:isReadonly] autorelease];
// Отображаем контроллер во всплывающем окне из указанного элемента
[self showInPopover:controller fromBarButtonItem:sender];
}
// Обрабатываем событие действия настроек представления данных
- (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];
}
// Обрабатываем событие скрытия всплывающего окна
- (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;
}
// Обрабатываем событие отключения полноэкранного режима
- (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;
// Извещаем о том, что контроллер представления данных будет выведен из полноэкранного режима
[self.delegate dataViewWillLeaveFullscreen:(id<MADataViewControllerProtocol>)[m_report.dataViews objectForKey:m_report.fullScreenBlockKey]];
[m_report dismissFullscreenCompositeBlock];
[self updatePanelViewVisibility:nil];
}
// Отображаем элементы управления для полноэкранного блока
- (void)showControlsForFullscreenBlock: (NSString *)blockKey {
m_shouldBackAction = NO;
self.navigationController.navigationBar.backItem.title = NSLocalizedString(@"Back", @"APViewController :: Report: Back");
self.navigationItem.rightBarButtonItem = [self createRightBarItem];
// Извещаем о переходе блока в полноэкранный режим
[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;
}
// Скрываем элементы управления полноэкранного блока
- (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];
}
// Выводим блоки из полноэкранного режима
- (void)dismissControlsForFullscreenBlock {
self.navigationItem.rightBarButtonItem = [self createRightBarItem];
m_splitViewController.splitView.fixSecondViewSize = YES;
m_splitViewController.splitView.hasTitle = NO;
[m_panelViewController setPanelTitle:NSLocalizedString(@"Controls", @"DimPanel:Title")];
// Извещаем о выходе блока из полноэкранного режима
[self.delegate didDismissedBlock];
if (!m_hasControls) {
m_splitViewController.panelViewController = nil;
}
}
// Загружаем представление данных аналитической панели
- (void)loadView {
[super loadView];
[self.view addSubview:m_splitViewController.view];
// Настраиваем контроллер компоновки экрана
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];
// Обновляем объекты, представляющие собой основу для построения таблиц с данными
[self.delegate refreshPivots];
for (NSString *i in m_report.compositeBlocks) {
// Сохраняем составной блок
[m_delegate setCompositeBlock:[m_report.compositeBlocks objectForKey:i] forBlockKey:i];
}
// При наличии списка настроек
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]) {
// Связываем блоки аналитической панели
[self.delegate addSlaveBlock:i.key toMasterBlock:j.key];
}
}
}
}
}
// Настраиваем связывание блоков по настройкам аналитической панели
} else [self.delegate configureSelectionWithConfig];
}
// Отображаем индикатор загрузки
- (void) showActivityIndicator {
NSLog(@"************* showWaiter");
[self.splitViewController showWaiter];
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
}
// Скрываем индикатор загрузки
- (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;
});
}
}
// Связываем блоки аналитической панели
- (void) addSlaveBlock:(NSString *)slaveKey toMasterBlock:(NSString *)masterKey {
[self.delegate addSlaveBlock:slaveKey toMasterBlock:masterKey];
}
// Отображаем панель настроек
- (void) dataViewController: (id<MADataViewControllerProtocol>) ctl showSettingsController: (UIViewController<PopoverContainedControllerProtocol> *) settings fromView: (UIView *) view {
// Отображаем панель во всплывающем окне указанного представления данных аналитической панели
[self showInPopover:settings fromView:view];
}
// Сохраняем скриншот в контекст отрисовки
- (void) captureScreenshotToContext:(CGContextRef)context {
[self.view.layer renderInContext:context];
}
// Устанавливаем изображение внутрь другого изображения
+ (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;
}
// Создаем скриншот
- (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
// Выполняем действие над аналитической панелью
- (void) performSettingsAction:(NSString *)key {
[self hidePopover];
if ([key isEqualToString:kDataReportMailAction]) { // Отправка письма
[self composeMail];
} else if ([key isEqualToString:kDataReportSaveAction]) { // Сохранение настроек аналитической панели
[self showWaiterWithTitle:NSLocalizedString(@"Saving...", @"saving message") andMessage:nil];
[self performSelector:@selector(saveReport) withObject:nil afterDelay:0.1];
}
}
// Сохраняем настройки аналитической панели
- (void) saveReport {
UIImage *image = [self screenshot];
[self.delegate setScreenshot:UIImagePNGRepresentation(image)];
// Сохраняем настройки аналитической панели
[self.delegate saveReport];
[self hideWaiter];
}
// Выполняем действие над аналитической панелью с дополнительными параметрами
- (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];
}
}
}
// Добавляем аналитическую панель в избранное
- (void)addToFavorites:(NSString *)name
{
[self.delegate saveFavoriteWithName:name];
[self hideWaiter];
}
// Отображаем представления данных аналитической панели
- (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];
}
// Отображаем окно ожидания
- (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];
}
}
// Скрываем окно ожидания
- (void)hideWaiter
{
[m_waiterView dismissWithClickedButtonIndex:0 animated:YES];
m_waiterView = nil;
}
#pragma mark MADataViewControllerDelegate
// Обрабатываем событие изменения доступности контроллера представления данных
- (void) dataViewController: (id<MADataViewControllerProtocol>) ctl availabilityUpdated:(BOOL) availability {
if (availability) {
[self dataViewControllerDidFinishCalculations:ctl];
} else {
[self dataViewControllerWillStartCalculations:ctl];
}
}
// Обрабатываем событие начала вычислений контроллера представления данных
- (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];
}
}
// Обрабатываем событие завершения вычислений контроллера представления данных
- (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];
}
}
// Извещаем о том, что контроллер представления данных готов к созданию скриншотов
- (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];
}
}
}
// Получаем справочник настроек аналитической панели
- (NSDictionary *) configurationForDataViewController: (id<MADataViewControllerProtocol>) controller {
return [self.delegate configurationForDataViewController:controller];
}
// Получаем сохраненные настройки контроллера представления данных аналитической панели
- (NSData *) stateForDataViewController: (id<MADataViewControllerProtocol>) controller {
return [self.delegate stateForDataViewController:controller];
}
// Сохраняем настройки контроллера представления данных аналитической панели
- (void) setState: (NSData *) state forDataViewController: (id<MADataViewControllerProtocol>) controller {
[self.delegate setState:state forDataViewController:controller];
}
// Извещаем о том, что контроллер представления данных сменил выборку данных
- (void) dataViewControllerChangedSelection:(id<MADataViewControllerProtocol>)controller {
[self.delegate dataViewControllerChangedSelection:controller];
}
// Обновляем заголовок аналитической панели
- (void) dataViewControllerReloadTitle:(id<MADataViewControllerProtocol>)controller {
m_splitViewController.splitView.titleView.titleLabel.text = self.reportTitle;
}
// Возвращаем заголовок аналитической панели
- (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
Тело метода addDimensionPanelControlWithKey:syncIndexKey: в классе MADashboardReportViewControllerDelegateImpl заменить на следующий код:
// Определяем ключ измерения
int64 dimensionKey = -1;
// Определяем массив ключей измерений-наблюдателей
NSMutableArray *listenerKeys = [NSMutableArray array];
// Получаем ключ измерения и массив ключей измерений-наблюдателей
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()];
}
}
// Создаёт объект, описывающий элемент управления аналитической панели
[self addDimensionPanelControlWithKey:key dimensionKey:dimensionKey listenerKeys:listenerKeys];
В файле MADashboardReportViewControllerFactory.m заменить код метода createReport:metabase: на следующий:
// Создаем делегат контроллера для работы с аналитической панелью MADashboardReportDelegateImpl *delegate = [[[MADashboardReportDelegateImpl alloc] initWithDashboardReport:dashboardReport metabase:metabase] autorelease]; // Создаем аналитическую панель на основе делегата MADashboardReportViewController *report = [[[MADashboardReportViewController alloc] initWithDelegate:delegate] autorelease]; // Устанавливаем панель измерений report.panelViewController.contentViewController = delegate.dimensionsPanel; return report;
В результате выполнения примера будет отображен индикатор загрузки аналитической панели:

Спустя три секунды на фоне затемнённого окна будет отображено модальное окно с сообщением:

Также в консоль среды разработки будет выведена информация об аналитической панели:
Сообщение модального окна: Выполняется загрузка
Спустя еще три секунды индикатор загрузки аналитической панели и окно с сообщением будут скрыты, после чего отобразится окно отправки почты:

См. также:
Примеры использования компонентов