Download as pdf or txt
Download as pdf or txt
You are on page 1of 14

Tutorial 4 - Creating a

custom property sheet


Copyright © 2009 SAP AG. All rights reserved.SAP, R/3, SAP NetWeaver, Duet, PartnerEdge,
ByDesign, SAP Business ByDesign, and other SAP products and services
mentioned herein as well as their respective logos are trademarks or registered
trademarks of SAP AG in Germany and other countries. Business Objects and the
Business Objects logo, BusinessObjects, Crystal Reports, Crystal Decisions, Web
Intelligence, Xcelsius, and other Business Objects products and services mentioned
herein as well as their respective logos are trademarks or registered trademarks
of Business Objects S.A. in the United States and in other countries. Business
Objects is an SAP company.All other product and service names mentioned are
the trademarks of their respective companies. Data contained in this document
serves informational purposes only. National product specifications may vary.These
materials are subject to change without notice. These materials are provided by
SAP AG and its affiliated companies ("SAP Group") for informational purposes
only, without representation or warranty of any kind, and SAP Group shall not be
liable for errors or omissions with respect to the materials. The only warranties for
SAP Group products and services are those that are set forth in the express
warranty statements accompanying such products and services, if any. Nothing
herein should be construed as constituting an additional warranty.

2009-11-03
Tutorial 4 - Creating a custom property sheet
Introduction

Introduction
This tutorial assumes that you have at least some knowledge of Cascading
Style Sheet (CSS), ActionScript 3.0, and MXML, the XML-based markup
language introduced by Adobe Flex.

The concentration of the tutorial is creating a custom property sheet for those
who do not want to use the default property sheet. We will include Flex
controls in the property sheet so that all of the properties and styles of the
custom component can be exposed. We will also use a sample CSS definition
to style the property sheet to look more like the Xcelsius color scheme.
Download the source code for the custom component so that you could see
what properties and styles it has. You will need to reference the names of
the properties/styles inside the property sheet source code.

For demonstration purposes, only the basic controls for the layout of custom
property sheet are mentioned. Please see the CustomPropSheetHorizon
talSlider sample source code for a more advanced layout.

Task 1: Creating a basic Flex project


1. Create a basic Flex project for the custom property sheet. .
For details on creating a project and adding the framework, refer to the
Xcelsius 2008 Component SDK SP1 User Guide section Create a visual
component.
2. Open the Flex project application MXML file.
3. Inside of the <mx:Application> tag, add applicationCom
plete="init();".

Task 2: Designing the layout for the


property sheet
1. Switch to Design mode by pressing the Design button located next to the
Source button.
2. Design the layout of the custom property sheet. Add the following controls
to the layout:

Tutorial 4 - Creating a custom property sheet 3


Tutorial 4 - Creating a custom property sheet
Task 2: Designing the layout for the property sheet

• Viewstack: id=viewstack1, creationPolicy=all, left=0, right=0, y=45,


height=100%, width=100%, minWidth=268, minHeight=350
• Canvas: id=general, label=General, minWidth=268, minHeight=350,
width=100%, height=100%
• Label: text=Title, x=23, y=24, width=119
• HRule: y=28, height=10, right=28, left=59
• TextInput: id=titleEditor, change=proxy.setProperty('title',
titleEditor.text), y=52, right=69, left=37
• Label: text=Value, x=23, y=116, width=119
• HRule: y=118, height=10, right=28, left=66
• TextInput: id=valueEditor, change=proxy.seProperty('value',
Number(valueEditor.text)), y=144, right=69, left=37
• Button: click=initiateBind('value'), icon=@Embed('resources/bind
to cell.png'), y=143, right=37, width=24
• Canvas: id=appearance, label=Appearance, minWidth=268,
minHeight=350, width=100%, height=100%
• Label: text=Text, x=23, y=23, text=Text, width=119
• HRule: y=28, height=10, right=28, left=56
• CheckBox: id=showTitleEditor, label=Show Title,
change=proxy.setProperty('showTitle', showTitleEditor.selected),
selected=true, x=43, y=54
• ComboBox: id=titleFontFamilyEditor,
dataProvider={_fontNames},
change=proxy.setStyle('titleFontFamily',
titleFontFamilyEditor.value), x=94, y=79, width=129
• ComboBox: id=titleFontSizeEditor, dataProvider={_fontSizes},
change=proxy.setStyle('titleFontSize', titleFontSizeEditor.value),
x=231 y=79 width=55
• Label: text=Color, x=23, y=136, width=119
• HRule: y=141, height=10, right=28, left=62
• Label: text=Title Color, x=43, y=169, text=Title Color:, width=116
• ColorPicker: id=titleColorEditor,
change=proxy.setStyle('titleFontColor',
uint(titleColorEditor.selectedColor)), x=137, y=169
• TabBar: dataProvider=viewstack1

4 Tutorial 4 - Creating a custom property sheet


Tutorial 4 - Creating a custom property sheet
Task 2: Designing the layout for the property sheet

3. After laying out the controls, switch to Source mode, you should have the
following code:

<?xml version="1.0" encoding="utf-8"?>


<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml" layout="ab
solute" applicationComplete="init();">
<mx:ViewStack id="viewstack1" creationPolicy="all"
left="0" right="0" y="45" height="100%" width="100%"
minWidth="268" minHeight="350">
<mx:Canvas id="general" label="General" min
Width="268" minHeight="350" width="100%" height="100%">

<mx:Label x="23" y="24" text="Title"


width="119"/>
<mx:HRule y="28" height="10" right="28"
left="59"/>
<mx:TextInput id="titleEditor" y="52"
right="69" left="37" change="proxy.setProperty('ti
tle',titleEditor.text)"/>
<mx:Label x="23" y="116" text="Value"
width="119"/>
<mx:HRule y="118" height="10" right="28"
left="66"/>
<mx:TextInput id="valueEditor" y="144"
right="69" left="37" change="proxy.setProperty('value',
Number(valueEditor.text))"/>
<mx:Button y="143" right="37" width="24"
click="initiateBind('value');" icon="@Embed('re
sources/bind to cell.png')"/>
</mx:Canvas>
<mx:Canvas id="appearance" label="Appearance"
minWidth="268" minHeight="350" width="100%"
height="100%">
<mx:Label x="23" y="23" text="Text"
width="119"/>
<mx:HRule y="28" height="10" right="28"
left="56"/>
<mx:CheckBox id="showTitleEditor" x="43"
y="54" label="Show Title" change="proxy.setProper
ty('showTitle', showTitleEditor.selected)" select
ed="true"/>
<mx:ComboBox id="titleFontFamilyEditor"
dataProvider="{_fontNames}" x="94" y="79" width="129"
change="proxy.setStyle('titleFontFamily', titleFont
FamilyEditor.value)" />
<mx:ComboBox id="titleFontSizeEditor"
dataProvider="{_fontSizes}" x="231" y="79" width="55"
change="proxy.setStyle('titleFontSize', titleFont

Tutorial 4 - Creating a custom property sheet 5


Tutorial 4 - Creating a custom property sheet
Task 3: Creating a CSS File

SizeEditor.value)" />
<mx:Label x="23" y="136" text="Color"
width="119"/>
<mx:HRule y="141" height="10" right="28"
left="62"/>
<mx:Label x="43" y="169" text="Title Col
or:" width="116"/>
<mx:ColorPicker id="titleColorEditor"
x="137" y="169" change="proxy.setStyle('titleFontCol
or', uint(titleColorEditor.selectedColor))" />
</mx:Canvas>
</mx:ViewStack>
<mx:TabBar x="0" y="0" dataProvider="viewstack1">

</mx:TabBar>
</mx:Application>

Task 3: Creating a CSS File


1. Immediately after <mx:Application> and before <mx:ViewStack>,
add the following tags:

<mx:Style />
<mx:Script>
<![CDATA[

]]>
</mx:Script>

2. Right click on the project folder in the Navigation window and create a
new folder named style; then import PSStyle.css, located in the SDK
install folder: SDK\samples\CustomPropSheetHorizontalSlid
er\CustomPropSheetHorizontalSliderPropertySheet\style\.
This CSS definition file contains several tags that define the styles for
each of them. These styles definitions were chosen because they closely
match Xcelsius property sheet styles: background color is #F4F3EE,
fontFamily is Tahoma, text color is black, etc.
3. Modify the source of <mx:Style> tag to include PSStyle.css: <mx:Style
source="style\PSStyle.css"/>

6 Tutorial 4 - Creating a custom property sheet


Tutorial 4 - Creating a custom property sheet
Task 4: Handling communication between property sheet and the component

Task 4: Handling communication


between property sheet and the
component
Task 4 is divided into five subtasks, 4a through 4e. In the first subtask, you
will import classes from the Xcelsius SDK framework. In the remaining
subtasks, you will implement the following functions:
• init():void
initializes the property sheet on load
• getPropertyBindDisplayName(propertyName:String):String
returns the bind display name or null if not Bound.
• initiateBind(propertyName:String):void
allows the user of the component to bind the Excel spreadsheet cell to
an Xcelsius custom component property/style.
• continueBind(bindingID:String):void
completes the binding when the user has finished selecting the cell to
bind to or cleared the binding.

Subtask 4a: Importing classes and creating local


variables

Inside CData section, include the following segments of code:

import mx.containers.*;
import mx.controls.*;
import mx.core.Container;
import mx.events.FlexEvent;

import xcelsius.binding.BindingDirection;
import xcelsius.binding.tableMaps.input.In
putBindings;
import xcelsius.binding.tableMaps.output.Out
putBindings;
import xcelsius.propertySheets.impl.Proper

Tutorial 4 - Creating a custom property sheet 7


Tutorial 4 - Creating a custom property sheet
Task 4: Handling communication between property sheet and the component

tySheetExternalProxy;
import xcelsius.propertySheets.inter
faces.PropertySheetFunctionNamesSDK;

[Bindable]
private var _fontNames:Array = [];

[Bindable]
protected var _fontSizes:Array = new Ar
ray("8", "9", "10", "11", "12", "14", "16", "18", "20",
"22");

protected var proxy:PropertySheetExternal


Proxy = new PropertySheetExternalProxy();

protected var propertyToBind:String;

protected var currentBindingID:String;

• _fontNames will contain system fonts that the user can choose from.
• _fontSizes is the list of selectable font sizes.
Both of these variables need to be bindable since we bind them to the data
providers of the combo boxes on the "Appearance" tab.

Variable proxy is the Xcelsius proxy that enables communication between


the property sheet and the custom component. The package xcel
sius.propertySheets.impl.PropertySheetExternalProxy for the
proxy is the implementation of the interface xcelsius.proper
tySheets.interfaces.IPropertySheetProxy, which are both included
in the xcelsiusframework.swc.

Variable propertyToBind stores the name of the property that the user is
binding, and currentBindingID stores the current binding id (null if there's
no binding) for the property.

Subtask 4b: Implementing init() function

The function init() sets the callback to continueBind method when the
user is picking Excel cell(s) to bind to, and then notifies Xcelsius that it has
finished loading the property sheet. Refer to the API Documentation for the
list of function name constants. The retrieval of the list of system fonts is

8 Tutorial 4 - Creating a custom property sheet


Tutorial 4 - Creating a custom property sheet
Task 4: Handling communication between property sheet and the component

implemented here. Lastly, it makes a call to initValues method that


initializes the property sheet on load with default property/style values.

protected function init():void


{
proxy.addCallback(PropertySheetFunction
NamesSDK.RESPONSE_BINDING_ID, this.continueBind);
proxy.callContainer(PropertySheetFunction
NamesSDK.INIT_COMPLETE_FUNCTION);
var allFonts:Array = Font.enumerate
Fonts(true);
allFonts.sortOn("fontName", Array.CASEIN
SENSITIVE);
var numFonts:int = allFonts.length;
for (var i:int=0; i<numFonts; i++)
{
var font:Font = allFonts[i];
_fontNames.push(font.fontName);
}
initValues();
}

Subtask 4c: Implementing initValues() function

In initValues(), we first get the array of values for the Xcelsius custom
component properties using proxy.getProperties method, then the
array of values for the styles using proxy. getStyles method. Both
methods need a list of property or style names passed in as an array of
strings.

Next, we process through the arrays retrieving the name and value of each
property and style, and either displaying that value to the corresponding
control's default value or the cell address(es) if bound to the Excel
spreadsheet. If a property has binding capability, make use of getProper
tyBindDisplayName method and add an if-else statement to handle that
correctly.

protected function initValues():void


{
// Process the array of values for the
Xcelsius custom component properties.
var propertyValues:Array = proxy.getProp
erties(["title", "value","showTitle"]);
var propertyValuesLength:int = (property

Tutorial 4 - Creating a custom property sheet 9


Tutorial 4 - Creating a custom property sheet
Task 4: Handling communication between property sheet and the component

Values != null ? propertyValues.length : 0);


for (var i:int=0; i < propertyVal
uesLength; i++)
{
var propertyObject:Object = property
Values[i];
var propertyName:String = propertyOb
ject.name;
var propertyValue:* = propertyOb
ject.value;
var bindingText:String = "";
switch (propertyName)
{
case "title":
titleEditor.text =
String(propertyValue);
break;
case "value":
bindingText = getPropertyBind
DisplayName(propertyName);
if (bindingText != null)
{
valueEditor.enabled =
false;
valueEditor.text = bind
ingText;
}
else
{
valueEditor.text = prop
ertyValue;
}
break;
case "showTitle":
showTitleEditor.selected =
Boolean(propertyValue);
break;
default:
break;
}
}

// Process the array of values for the


custom component styles.
var styleValues:Array = proxy.get
Styles(["titleFontFamily", "titleFontColor", "titleFont
Size"]);
var styleValuesLength:int = (styleValues
!= null ? styleValues.length : 0);

10 Tutorial 4 - Creating a custom property sheet


Tutorial 4 - Creating a custom property sheet
Task 4: Handling communication between property sheet and the component

for (var j:int=0; j < styleValuesLength;


j++)
{
var styleObject:Object = styleVal
ues[j];
var styleName:String = styleOb
ject.name;
var styleValue:* = styleObject.value;

var bindingTextStyle:String = "";


switch (styleName)
{
case "titleFontColor":
titleColorEditor.selectedCol
or = uint(styleValue);
break;
case "titleFontFamily":
titleFontFamilyEditor.selecte
dIndex = _fontNames.indexOf(styleValue);
break;
case "titleFontSize":
titleFontSizeEditor.selecte
dIndex = _fontSizes.indexOf(styleValue);
var index:int;
index = _fontSizes.index
Of(styleValue.toString());
if (index != -1)
{
titleFontSizeEditor.se
lectedIndex = index;
}
else if (!isNaN(styleValue))

{
titleFontSizeEditor.text
= styleValue.toString();
}
else
{
titleFontSizeEditor.se
lectedIndex = -1;
}
break;
default:
break;
}
}
}

Tutorial 4 - Creating a custom property sheet 11


Tutorial 4 - Creating a custom property sheet
Task 4: Handling communication between property sheet and the component

Subtask 4d: Implementing


getPropertyBindDisplayName and initiateBind
functions

Given a property name, getPropertyBindDisplayName gets the array


of bindings for that property by calling proxy.getBindings method. If we
have at least one binding for that property then pick the first one.

protected function getPropertyBindDisplay


Name(propertyName:String):String
{
var propertyBindings:Array = proxy.get
Bindings([propertyName]);
if ((propertyBindings != null) && (prop
ertyBindings.length > 0) && (propertyBindings[0].length
> 0))
{
var bindingID:String = propertyBind
ings[0][0];
return proxy.getBindingDisplay
Name(bindingID);
}
return null;
}

Given a property name, initiateBind allows the user to select the Excel
spreadsheet cell(s) to bind to an Xcelsius custom component property. If
there is an existing binding for that property, show that in the Excel binding
selection window and store the currentBindingID (null if there is no
current binding) in case we "continueBinding". Use the function proxy.re
questUserSelection method to let the user choose where to bind to in
the Excel spreadsheet.

protected function initiateBind(property


Name:String):void
{
currentBindingID = null;
var propertyBindings:Array = proxy.get
Bindings([propertyName]);
if ((propertyBindings != null) && (prop
ertyBindings.length > 0))
{
currentBindingID = propertyBind

12 Tutorial 4 - Creating a custom property sheet


Tutorial 4 - Creating a custom property sheet
Task 4: Handling communication between property sheet and the component

ings[0];
}
propertyToBind = propertyName;
proxy.requestUserSelection(current
BindingID);
}

Subtask 4e: Implementing continueBind function

continueBind method completes the binding when the user has finished
selecting the cell(s) to bind to or cleared the binding. Again, we process
through each property that has binding capability to do the following: filling
the control with current value and set property when the user explicitly clears
binding, disabling the option to manually enter a value once the component
if the property is bound, displaying the range address, and the actual binding
using proxy.bind method. BindingDirection.BOTH updates the custom
component property when the spreadsheet changes and also updates the
spreadsheet when the custom component changes. InputBindings.SIN
GLETON writes to a single cell in the spreadsheet. OutputBindings.SIN
GLETON reads a single cell in the spreadsheet.

For more information on bindings and the custom property sheet API, refer
to Appendix B in the Xcelsius 2008 Component SDK SP1 User Guide.

protected function continue


Bind(bindingID:String):void
{
var propertyName:String = propertyToBind;

var propertyValues:Array;
var propertyObject:Object;
var bindingAddresses:Array;

if (currentBindingID != null)
{
proxy.unbind(currentBindingID);
currentBindingID = null;
}

switch (propertyName)
{
case "value":
if ((bindingID == null) ||
(bindingID == ""))

Tutorial 4 - Creating a custom property sheet 13


Tutorial 4 - Creating a custom property sheet
Task 4: Handling communication between property sheet and the component

{
valueEditor.enabled = true;
propertyValues = proxy.get
Properties([propertyName]);
propertyObject = propertyVal
ues[0];
valueEditor.text = property
Object.value;
proxy.setProperty(property
Name, propertyObject.value);
return;
}
valueEditor.enabled = false;
valueEditor.text = proxy.getBind
ingDisplayName(bindingID);
proxy.bind("value", null,
bindingID, BindingDirection.BOTH, InputBindings.SINGLE
TON, OutputBindings.SINGLETON);
break;
default:
break;
}
}
Save and build.

14 Tutorial 4 - Creating a custom property sheet

You might also like