blob: a795b4c0cba6c22dc4be54a254a6ebd0db4c04b4 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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.
//
////////////////////////////////////////////////////////////////////////////////
package com.flexcapacitor.controller {
import com.flexcapacitor.components.DocumentContainer;
import com.flexcapacitor.components.IDocumentContainer;
import com.flexcapacitor.effects.core.CallMethod;
import com.flexcapacitor.events.HistoryEvent;
import com.flexcapacitor.events.HistoryEventItem;
import com.flexcapacitor.events.RadiateEvent;
import com.flexcapacitor.logging.RadiateLogTarget;
import com.flexcapacitor.model.AttachmentData;
import com.flexcapacitor.model.Device;
import com.flexcapacitor.model.Document;
import com.flexcapacitor.model.DocumentData;
import com.flexcapacitor.model.EventMetaData;
import com.flexcapacitor.model.IDocument;
import com.flexcapacitor.model.IDocumentData;
import com.flexcapacitor.model.IDocumentMetaData;
import com.flexcapacitor.model.IProject;
import com.flexcapacitor.model.IProjectData;
import com.flexcapacitor.model.ISavable;
import com.flexcapacitor.model.ImageData;
import com.flexcapacitor.model.InspectableClass;
import com.flexcapacitor.model.InspectorData;
import com.flexcapacitor.model.MetaData;
import com.flexcapacitor.model.Project;
import com.flexcapacitor.model.SaveResultsEvent;
import com.flexcapacitor.model.SavedData;
import com.flexcapacitor.model.Settings;
import com.flexcapacitor.model.StyleMetaData;
import com.flexcapacitor.services.IServiceEvent;
import com.flexcapacitor.services.WPAttachmentService;
import com.flexcapacitor.services.WPService;
import com.flexcapacitor.services.WPServiceEvent;
import com.flexcapacitor.tools.ITool;
import com.flexcapacitor.utils.ClassUtils;
import com.flexcapacitor.utils.DisplayObjectUtils;
import com.flexcapacitor.utils.SharedObjectUtils;
import com.flexcapacitor.utils.TypeUtils;
import com.flexcapacitor.utils.XMLUtils;
import com.flexcapacitor.utils.supportClasses.ComponentDefinition;
import com.flexcapacitor.utils.supportClasses.ComponentDescription;
import com.flexcapacitor.views.IInspector;
import com.google.code.flexiframe.IFrame;
import flash.desktop.Clipboard;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.IBitmapDrawable;
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.external.ExternalInterface;
import flash.geom.Point;
import flash.globalization.DateTimeStyle;
import flash.net.FileReference;
import flash.net.SharedObject;
import flash.system.ApplicationDomain;
import flash.ui.Mouse;
import flash.ui.MouseCursorData;
import flash.utils.ByteArray;
import flash.utils.Dictionary;
import flash.utils.getTimer;
import mx.collections.ArrayCollection;
import mx.containers.Grid;
import mx.containers.GridItem;
import mx.containers.GridRow;
import mx.containers.TabNavigator;
import mx.controls.LinkButton;
import mx.core.ClassFactory;
import mx.core.DeferredInstanceFromFunction;
import mx.core.IUIComponent;
import mx.core.IVisualElement;
import mx.core.IVisualElementContainer;
import mx.core.UIComponent;
import mx.core.mx_internal;
import mx.effects.effectClasses.PropertyChanges;
import mx.graphics.ImageSnapshot;
import mx.graphics.SolidColor;
import mx.logging.AbstractTarget;
import mx.logging.ILogger;
import mx.logging.Log;
import mx.logging.LogEventLevel;
import mx.managers.ILayoutManager;
import mx.managers.LayoutManager;
import mx.printing.FlexPrintJob;
import mx.printing.FlexPrintJobScaleType;
import mx.states.AddItems;
import mx.styles.IStyleClient;
import mx.utils.ArrayUtil;
import mx.utils.ObjectUtil;
import spark.components.Application;
import spark.components.BorderContainer;
import spark.components.Button;
import spark.components.ComboBox;
import spark.components.Grid;
import spark.components.Image;
import spark.components.Label;
import spark.components.NavigatorContent;
import spark.components.Scroller;
import spark.components.SkinnableContainer;
import spark.components.supportClasses.GroupBase;
import spark.components.supportClasses.SkinnableTextBase;
import spark.components.supportClasses.TextBase;
import spark.core.ContentCache;
import spark.core.IViewport;
import spark.effects.SetAction;
import spark.formatters.DateTimeFormatter;
import spark.layouts.BasicLayout;
import spark.primitives.BitmapImage;
import spark.primitives.Rect;
import spark.skins.spark.DefaultGridItemRenderer;
import org.as3commons.lang.ArrayUtils;
import org.as3commons.lang.DictionaryUtils;
import org.as3commons.lang.ObjectUtils;
use namespace mx_internal;
/**
* Dispatched when register results are received
* */
[Event(name="registerResults", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when a print job is cancelled
* */
[Event(name="printCancelled", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when an item is added to the target
* */
[Event(name="addItem", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when an item is removed from the target
* */
[Event(name="removeItem", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when an item is removed from the target
* */
[Event(name="removeTarget", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when the target is changed
* */
[Event(name="targetChange", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when the document is changed
* */
[Event(name="documentChange", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when a document is opening
* */
[Event(name="documentOpening", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when a document is opened
* */
[Event(name="documentOpen", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when a document is renamed
* */
[Event(name="documentRename", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when the project is changed
* */
[Event(name="projectChange", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when the project is deleted
* */
[Event(name="projectDeletedResults", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when the project is created
* */
[Event(name="projectCreated", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when a property on the target is changed.
* Using propertyChanged instead of propertyChange because of error with bindable
* tag using propertyChange:
* TypeError: Error #1034: Type Coercion failed: cannot convert mx.events::PropertyChangeEvent@11d2187b1 to com.flexcapacitor.events.RadiateEvent.
* */
[Event(name="propertyChanged", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when a property is selected on the target
* */
[Event(name="propertySelected", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when a property edit is requested
* */
[Event(name="propertyEdit", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when the tool changes
* */
[Event(name="toolChange", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when the scale changes
* */
[Event(name="scaleChange", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when the document size or scale changes
* */
[Event(name="documentSizeChange", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Not used yet.
* */
[Event(name="initialized", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Used when the tools list has been updated.
* */
[Event(name="toolsUpdated", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Used when the components list is updated.
* */
[Event(name="componentsUpdated", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Used when the document canvas is updated.
* */
[Event(name="canvasChange", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Event to request a preview if available. Used for HTML preview.
* */
[Event(name="requestPreview", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when the generated code is updated.
* */
[Event(name="codeUpdated", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when a color is selected.
* */
[Event(name="colorSelected", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Dispatched when an object is selected
* */
[Event(name="objectSelected", type="com.flexcapacitor.radiate.events.RadiateEvent")]
/**
* Main class and API that handles the interactions between the view and the models.
*
* Dispatches events and exposes methods to manipulate the documents.
*
* It contains a list of components, tools, devices, inspectors (panels), assets and
* in the future we should add skins, effects and so on.
* These items are created from an XML file at startup so we can configure what is available
* to our user or project. We do this so we can also load in a remote SWF to add
* additional components, sounds, images, skins, inspectors, fonts, etc
*
* Currently we are saving and loading to a remote location or to a local shared object.
* To save to a local file system we will need to modify these functions.
*
* This class supports an Undo / Redo history. The architecture is loosely based on
* the structure found in the Effects classes. We may want to be a proxy to the documents
* and call undo and redo on them since we would like to support more than one
* type of document.
*
* This class can be broken up into multiple classes since it is also handling
* saving and loading and services.
*
* To set a property or style call setProperty or setStyle.
* To add a component call addElement.
* To log a message to the console call Radiate.log.info() or error().
*
* To undo call undo
* To redo call redo
*
* To get the history index access history index
* To check if history exists call the has history
* To check if undo can be performed access has undo
* To check if redo can be performed access has redo
*
* Editing through cut, copy and paste is only partially implemented.
* */
public class Radiate extends EventDispatcher {
public static const SAME_OWNER:String = "sameOwner";
public static const SAME_PARENT:String = "sameParent";
public static const ADDED:String = "added";
public static const MOVED:String = "moved";
public static const REMOVED:String = "removed";
public static const ADD_ERROR:String = "addError";
public static const REMOVE_ERROR:String = "removeError";
public static const RADIATE_LOG:String = "radiate";
public static const LOGGED_IN:String = "loggedIn";
public static const LOGGED_OUT:String = "loggedOut";
public function Radiate(s:SINGLEDOUBLE) {
super(target as IEventDispatcher);
// Create a target
setLoggingTarget(defaultLogTarget);
// initialize - maybe call on startup() instead
initialize();
}
//----------------------------------
// instance
//----------------------------------
private static var _instance:Radiate;
/**
* Attempt to support a console part 2
* */
public static function get log():ILogger {
if (_log) {
return _log;
}
else {
setLoggingTarget(defaultLogTarget);
return _log;
}
}
/**
* @private
*/
public static function set log(value:ILogger):void {
_log = value;
}
/**
* Attempt to support a console part 3
* */
public static function get console():Object {
return _console;
}
/**
* @private
*/
public static function set console(value:Object):void {
_console = value;
if ("console" in logTarget) {
logTarget["console"] = value;
}
}
public static function get instance():Radiate
{
if (!_instance) {
_instance = new Radiate(new SINGLEDOUBLE());
}
return _instance;
}
public static function getInstance():Radiate {
return instance;
}
/**
* Create references for classes we need.
* */
public static var radiateReferences:RadiateReferences;
/**
* If true then importing document
* */
public static var importingDocument:Boolean;
/**
* Upload attachment
* */
public var uploadAttachmentService:WPAttachmentService;
/**
* Service to get list of attachments
* */
public var getAttachmentsService:WPService;
/**
* Service to get list of projects
* */
public var getProjectsService:WPService;
/**
* Service to delete attachment
* */
public var deleteAttachmentService:WPService;
/**
* Service to delete document
* */
public var deleteDocumentService:WPService;
/**
* Service to delete project
* */
public var deleteProjectService:WPService;
/**
* Service to request reset the password
* */
public var lostPasswordService:WPService;
/**
* Service to change the password
* */
public var changePasswordService:WPService;
/**
* Service to login
* */
public var loginService:WPService;
/**
* Service to logout
* */
public var logoutService:WPService;
/**
* Service to register
* */
public var registerService:WPService;
/**
* Service to check if user is logged in
* */
public var getLoggedInStatusService:WPService;
/**
* Set to true when a document is being saved to the server
* */
[Bindable]
public var saveDocumentInProgress:Boolean;
/**
* Set to true when project is being saved to the server
* */
[Bindable]
public var saveProjectInProgress:Boolean;
/**
* Set to true when checking if user is logged in
* */
[Bindable]
public var getLoggedInStatusInProgress:Boolean;
/**
* Set to true when lost password call is made
* */
[Bindable]
public var lostPasswordInProgress:Boolean;
/**
* Set to true when changing password
* */
[Bindable]
public var changePasswordInProgress:Boolean;
/**
* Set to true when registering
* */
[Bindable]
public var registerInProgress:Boolean;
/**
* Set to true when logging in
* */
[Bindable]
public var loginInProgress:Boolean;
/**
* Set to true when logging out
* */
[Bindable]
public var logoutInProgress:Boolean;
/**
* Set to true when deleting a project
* */
[Bindable]
public var deleteProjectInProgress:Boolean;
/**
* Set to true when deleting a document
* */
[Bindable]
public var deleteDocumentInProgress:Boolean;
/**
* Set to true when deleting an attachment
* */
[Bindable]
public var deleteAttachmentInProgress:Boolean;
/**
* Set to true when getting list of attachments
* */
[Bindable]
public var getAttachmentsInProgress:Boolean;
/**
* Set to true when uploading an attachment
* */
[Bindable]
public var uploadAttachmentInProgress:Boolean;
/**
* Set to true when getting list of projects
* */
[Bindable]
public var getProjectsInProgress:Boolean;
/**
* Is user logged in
* */
[Bindable]
public var isUserLoggedIn:Boolean;
/**
* Default storage location for save and load.
* */
[Bindable]
public var defaultStorageLocation:String;
/**
* Can user connect to the service
* */
[Bindable]
public var isUserConnected:Boolean;
/**
* Avatar of user
* */
[Bindable]
public var userAvatar:String = "assets/images/icons/gravatar.png";
/**
* Path to default avatar of user (from Gravatar)
* Gravatars icons don't work locally so using path.
* Default - http://0.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?s=96
* local - assets/images/icons/gravatar.png
* */
[Bindable]
public var defaultUserAvatarPath:String = "assets/images/icons/gravatar.png";
/**
* User info
* */
[Bindable]
public var user:Object;
/**
* User email
* */
[Bindable]
public var userEmail:String;
/**
* User id
* */
[Bindable]
public var userID:int = -1;
/**
* User sites
* */
[Bindable]
public var userSites:Array = [];
/**
* User site path
* */
[Bindable]
public var userSitePath:String;
/**
* User display name
* */
[Bindable]
public var userDisplayName:String = "guest";
/**
* Last save date
* */
[Bindable]
public var lastSaveDate:String;
/**
* Cut data
* */
public var cutData:Object;
/**
* Cut data
* */
public var copiedData:Object;
/**
* Auto save locations
* */
[Bindable]
public var autoSaveLocations:String;
private var _enableAutoSave:Boolean;
[Bindable]
/**
* Auto save enabled
* */
public function get enableAutoSave():Boolean {
return _enableAutoSave;
}
/**
* @private
*/
public function set enableAutoSave(value:Boolean):void {
_enableAutoSave = value;
if (value) {
if (!autoSaveEffect) {
autoSaveEffect = new CallMethod();
autoSaveEffect.method = autoSaveHandler;
autoSaveEffect.repeatCount = 0;
autoSaveEffect.repeatDelay = autoSaveInterval;
}
if (!autoSaveEffect.isPlaying) {
autoSaveEffect.play();
}
}
else {
autoSaveEffect.stop();
}
}
/**
* Interval to check to save project
* */
public var autoSaveInterval:int = 30000;
/**
* Effect to auto save
* */
public var autoSaveEffect:CallMethod;
/**
* Handle auto saving
* */
public function autoSaveHandler():void {
var length:int;
var iProject:IProject;
var iDocumentData:IDocumentData;
var iAttachmentData:AttachmentData;
var imageData:ImageData;
var i:int;
// save documents
/*length = documents.length;
for (i=0;i<length;i++) {
iDocumentData = documents[i] as IDocumentData;
if (iDocumentData.isChanged && !iDocumentData.saveInProgress && iDocumentData.isOpen) {
iDocumentData.save();
}
}*/
// save projects
length = projects.length;
for (i=0;i<length;i++) {
iDocumentData = projects[i] as IDocumentData;
//if (iDocumentData.isChanged && !iDocumentData.saveInProgress && iDocumentData.isOpen) {
if (!iDocumentData.saveInProgress && iDocumentData.isOpen) {
iDocumentData.save();
}
}
// save attachments
length = assets.length;
for (i=0;i<length;i++) {
iAttachmentData = assets[i] as ImageData;
if (iAttachmentData) {
imageData = iAttachmentData as ImageData;
if (!imageData.saveInProgress && imageData.id==null) {
//imageData.save();
uploadAttachment(imageData.byteArray, selectedProject.id, imageData.name, null, imageData.contentType);
}
}
}
}
/**
* Build number
* */
[Bindable]
public var buildNumber:String;
/**
* Build date
* */
[Bindable]
public var buildDate:String;
/**
* Build time
* */
[Bindable]
public var buildTime:String;
//----------------------------------
//
// Events Management
//
//----------------------------------
/**
* Dispatch attachments received event
* */
public function dispatchGetProjectsListResultsEvent(data:Object):void {
var projectsListResultEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECTS_LIST_RECEIVED);
if (hasEventListener(RadiateEvent.PROJECTS_LIST_RECEIVED)) {
projectsListResultEvent.data = data;
dispatchEvent(projectsListResultEvent);
}
}
/**
* Dispatch print cancelled event
* */
public function dispatchPrintCancelledEvent(data:Object, printJob:FlexPrintJob):void {
var printCancelledEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PRINT_CANCELLED);
if (hasEventListener(RadiateEvent.PRINT_CANCELLED)) {
printCancelledEvent.data = data;
printCancelledEvent.selectedItem = printJob;
dispatchEvent(printCancelledEvent);
}
}
/**
* Dispatch print complete event
* */
public function dispatchPrintCompleteEvent(data:Object, printJob:FlexPrintJob):void {
var printCompleteEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PRINT_COMPLETE);
if (hasEventListener(RadiateEvent.PRINT_COMPLETE)) {
printCompleteEvent.data = data;
printCompleteEvent.selectedItem = printJob;
dispatchEvent(printCompleteEvent);
}
}
/**
* Dispatch attachments received event
* */
public function dispatchLoginStatusEvent(loggedIn:Boolean, data:Object):void {
var loggedInStatusEvent:RadiateEvent = new RadiateEvent(RadiateEvent.LOGGED_IN_STATUS);
if (hasEventListener(RadiateEvent.LOGGED_IN_STATUS)) {
loggedInStatusEvent.status = loggedIn ? LOGGED_IN : LOGGED_OUT;
loggedInStatusEvent.data = data;
dispatchEvent(loggedInStatusEvent);
}
}
/**
* Dispatch attachments received event
* */
public function dispatchAttachmentsResultsEvent(successful:Boolean, attachments:Array):void {
var attachmentsReceivedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.ATTACHMENTS_RECEIVED, false, false, attachments);
if (hasEventListener(RadiateEvent.ATTACHMENTS_RECEIVED)) {
attachmentsReceivedEvent.successful = successful;
attachmentsReceivedEvent.status = successful ? "ok" : "fault";
attachmentsReceivedEvent.targets = ArrayUtil.toArray(attachments);
dispatchEvent(attachmentsReceivedEvent);
}
}
/**
* Dispatch upload attachment received event
* */
public function dispatchUploadAttachmentResultsEvent(successful:Boolean, attachments:Array, data:Object):void {
var uploadAttachmentEvent:RadiateEvent = new RadiateEvent(RadiateEvent.ATTACHMENT_UPLOADED, false, false);
if (hasEventListener(RadiateEvent.ATTACHMENT_UPLOADED)) {
uploadAttachmentEvent.successful = successful;
uploadAttachmentEvent.status = successful ? "ok" : "fault";
uploadAttachmentEvent.data = attachments;
uploadAttachmentEvent.selectedItem = data;
dispatchEvent(uploadAttachmentEvent);
}
}
/**
* Dispatch login results event
* */
public function dispatchLoginResultsEvent(successful:Boolean, data:Object):void {
var loginResultsEvent:RadiateEvent = new RadiateEvent(RadiateEvent.LOGIN_RESULTS);
if (hasEventListener(RadiateEvent.LOGIN_RESULTS)) {
loginResultsEvent.data = data;
loginResultsEvent.successful = successful;
dispatchEvent(loginResultsEvent);
}
}
/**
* Dispatch logout results event
* */
public function dispatchLogoutResultsEvent(successful:Boolean, data:Object):void {
var logoutResultsEvent:RadiateEvent = new RadiateEvent(RadiateEvent.LOGOUT_RESULTS);
if (hasEventListener(RadiateEvent.LOGOUT_RESULTS)) {
logoutResultsEvent.data = data;
logoutResultsEvent.successful = successful;
dispatchEvent(logoutResultsEvent);
}
}
/**
* Dispatch register results event
* */
public function dispatchRegisterResultsEvent(successful:Boolean, data:Object):void {
var registerResultsEvent:RadiateEvent = new RadiateEvent(RadiateEvent.REGISTER_RESULTS);
if (hasEventListener(RadiateEvent.REGISTER_RESULTS)) {
registerResultsEvent.data = data;
registerResultsEvent.successful = successful;
dispatchEvent(registerResultsEvent);
}
}
/**
* Dispatch change password results event
* */
public function dispatchChangePasswordResultsEvent(successful:Boolean, data:Object):void {
var changePasswordResultsEvent:RadiateEvent = new RadiateEvent(RadiateEvent.CHANGE_PASSWORD_RESULTS);
if (hasEventListener(RadiateEvent.CHANGE_PASSWORD_RESULTS)) {
changePasswordResultsEvent.data = data;
changePasswordResultsEvent.successful = successful;
dispatchEvent(changePasswordResultsEvent);
}
}
/**
* Dispatch lost password results event
* */
public function dispatchLostPasswordResultsEvent(successful:Boolean, data:Object):void {
var lostPasswordResultsEvent:RadiateEvent = new RadiateEvent(RadiateEvent.LOST_PASSWORD_RESULTS);
if (hasEventListener(RadiateEvent.LOST_PASSWORD_RESULTS)) {
lostPasswordResultsEvent.data = data;
lostPasswordResultsEvent.successful = successful;
dispatchEvent(lostPasswordResultsEvent);
}
}
/**
* Dispatch project deleted results event
* */
public function dispatchProjectDeletedEvent(successful:Boolean, data:Object):void {
var deleteProjectResultsEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_DELETED);
if (hasEventListener(RadiateEvent.PROJECT_DELETED)) {
deleteProjectResultsEvent.data = data;
deleteProjectResultsEvent.successful = successful;
deleteProjectResultsEvent.status = successful ? "ok" : "error";
dispatchEvent(deleteProjectResultsEvent);
}
}
/**
* Dispatch document deleted results event
* */
public function dispatchDocumentDeletedEvent(successful:Boolean, data:Object):void {
var deleteDocumentResultsEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_DELETED);
if (hasEventListener(RadiateEvent.DOCUMENT_DELETED)) {
deleteDocumentResultsEvent.data = data;
deleteDocumentResultsEvent.successful = successful;
deleteDocumentResultsEvent.status = successful ? "ok" : "error";
dispatchEvent(deleteDocumentResultsEvent);
}
}
/**
* Dispatch asset added event
* */
public function dispatchAssetAddedEvent(data:Object):void {
var assetAddedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.ASSET_ADDED);
if (hasEventListener(RadiateEvent.ASSET_ADDED)) {
assetAddedEvent.data = data;
dispatchEvent(assetAddedEvent);
}
}
/**
* Dispatch asset removed event
* */
public function dispatchAssetRemovedEvent(data:IDocumentData, successful:Boolean = true):void {
var assetRemovedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.ASSET_REMOVED);
if (hasEventListener(RadiateEvent.ASSET_REMOVED)) {
assetRemovedEvent.data = data;
dispatchEvent(assetRemovedEvent);
}
}
/**
* Dispatch target change event
* */
public function dispatchTargetChangeEvent(target:*, multipleSelection:Boolean = false):void {
if (importingDocument) return;
var targetChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.TARGET_CHANGE, false, false, target, null, null, multipleSelection);
if (hasEventListener(RadiateEvent.TARGET_CHANGE)) {
targetChangeEvent.selectedItem = target && target is Array ? target[0] : target;
targetChangeEvent.targets = ArrayUtil.toArray(target);
dispatchEvent(targetChangeEvent);
}
}
/**
* Dispatch scale change event
* */
public function dispatchScaleChangeEvent(target:*, scaleX:Number = NaN, scaleY:Number = NaN):void {
var scaleChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.SCALE_CHANGE, false, false, target, null, null);
if (hasEventListener(RadiateEvent.SCALE_CHANGE)) {
scaleChangeEvent.scaleX = scaleX;
scaleChangeEvent.scaleY = scaleY;
dispatchEvent(scaleChangeEvent);
}
}
/**
* Dispatch document size change event
* */
public function dispatchDocumentSizeChangeEvent(target:*):void {
var scaleChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_SIZE_CHANGE, false, false, target, null, null);
if (hasEventListener(RadiateEvent.DOCUMENT_SIZE_CHANGE)) {
dispatchEvent(scaleChangeEvent);
}
}
/**
* Dispatch preview event
* */
public function dispatchPreviewEvent(code:String, type:String):void {
var previewEvent:RadiateEvent = new RadiateEvent(RadiateEvent.REQUEST_PREVIEW);
if (hasEventListener(RadiateEvent.REQUEST_PREVIEW)) {
previewEvent.previewType = type;
previewEvent.value = code;
dispatchEvent(previewEvent);
}
}
/**
* Dispatch code updated event. Type is usually "HTML".
* */
public function dispatchCodeUpdatedEvent(code:String, type:String, openInWindow:Boolean = false):void {
var codeUpdatedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.CODE_UPDATED);
if (hasEventListener(RadiateEvent.CODE_UPDATED)) {
codeUpdatedEvent.previewType = type;
codeUpdatedEvent.value = code;
codeUpdatedEvent.openInBrowser = openInWindow;
dispatchEvent(codeUpdatedEvent);
}
}
/**
* Dispatch color selected event
* */
public function dispatchColorSelectedEvent(color:uint, invalid:Boolean = false):void {
var colorSelectedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.COLOR_SELECTED);
if (hasEventListener(RadiateEvent.COLOR_SELECTED)) {
colorSelectedEvent.color = color;
colorSelectedEvent.invalid = invalid;
dispatchEvent(colorSelectedEvent);
}
}
/**
* Dispatch property selected event
* */
public function dispatchPropertySelectedEvent(property:String, node:MetaData = null):void {
var colorSelectedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROPERTY_SELECTED);
if (hasEventListener(RadiateEvent.PROPERTY_SELECTED)) {
colorSelectedEvent.property = property;
colorSelectedEvent.selectedItem = node;
dispatchEvent(colorSelectedEvent);
}
}
/**
* Dispatch color preview event
* */
public function dispatchColorPreviewEvent(color:uint, invalid:Boolean = false):void {
var colorPreviewEvent:RadiateEvent = new RadiateEvent(RadiateEvent.COLOR_PREVIEW);
if (hasEventListener(RadiateEvent.COLOR_PREVIEW)) {
colorPreviewEvent.color = color;
colorPreviewEvent.invalid = invalid;
dispatchEvent(colorPreviewEvent);
}
}
/**
* Dispatch canvas change event
* */
public function dispatchCanvasChangeEvent(canvas:*, canvasBackgroundParent:*, scroller:Scroller):void {
var targetChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.CANVAS_CHANGE);
if (hasEventListener(RadiateEvent.CANVAS_CHANGE)) {
dispatchEvent(targetChangeEvent);
}
}
/**
* Dispatch tool change event
* */
public function dispatchToolChangeEvent(value:ITool):void {
var toolChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.TOOL_CHANGE);
if (hasEventListener(RadiateEvent.TOOL_CHANGE)) {
toolChangeEvent.selectedItem = target && target is Array ? target[0] : target;
toolChangeEvent.targets = targets;
toolChangeEvent.tool = value;
dispatchEvent(toolChangeEvent);
}
}
/**
* Dispatch target change event with a null target.
* */
public function dispatchTargetClearEvent():void {
var targetChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.TARGET_CHANGE);
if (hasEventListener(RadiateEvent.TARGET_CHANGE)) {
dispatchEvent(targetChangeEvent);
}
}
/**
* Dispatch property change event
* */
public function dispatchPropertyChangeEvent(target:*, changes:Array, properties:Array, multipleSelection:Boolean = false):void {
if (importingDocument) return;
var propertyChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROPERTY_CHANGED, false, false, target, changes, properties, multipleSelection);
if (hasEventListener(RadiateEvent.PROPERTY_CHANGED)) {
propertyChangeEvent.properties = properties;
propertyChangeEvent.changes = changes;
propertyChangeEvent.multipleSelection = multipleSelection;
propertyChangeEvent.selectedItem = target && target is Array ? target[0] : target;
propertyChangeEvent.targets = ArrayUtil.toArray(target);
dispatchEvent(propertyChangeEvent);
}
}
/**
* Dispatch object selected event
* */
public function dispatchObjectSelectedEvent(target:*):void {
var objectSelectedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.OBJECT_SELECTED, false, false, target);
if (hasEventListener(RadiateEvent.OBJECT_SELECTED)) {
dispatchEvent(objectSelectedEvent);
}
}
/**
* Dispatch add items event
* */
public function dispatchAddEvent(target:*, changes:Array, properties:Array, multipleSelection:Boolean = false):void {
if (importingDocument) return;
var event:RadiateEvent = new RadiateEvent(RadiateEvent.ADD_ITEM, false, false, target, changes, properties, multipleSelection);
var length:int = changes ? changes.length : 0;
if (hasEventListener(RadiateEvent.ADD_ITEM)) {
event.properties = properties;
event.changes = changes;
event.multipleSelection = multipleSelection;
event.selectedItem = target && target is Array ? target[0] : target;
event.targets = ArrayUtil.toArray(target);
for (var i:int;i<length;i++) {
if (changes[i] is AddItems) {
event.addItemsInstance = changes[i];
event.moveItemsInstance = changes[i];
}
}
dispatchEvent(event);
}
}
/**
* Dispatch add items event
* */
public function dispatchMoveEvent(target:*, changes:Array, properties:Array, multipleSelection:Boolean = false):void {
if (importingDocument) return;
var event:RadiateEvent = new RadiateEvent(RadiateEvent.MOVE_ITEM, false, false, target, changes, properties, multipleSelection);
var length:int = changes ? changes.length : 0;
if (hasEventListener(RadiateEvent.MOVE_ITEM)) {
event.properties = properties;
event.changes = changes;
event.multipleSelection = multipleSelection;
event.selectedItem = target && target is Array ? target[0] : target;
event.targets = ArrayUtil.toArray(target);
for (var i:int;i<length;i++) {
if (changes[i] is AddItems) {
event.addItemsInstance = changes[i];
event.moveItemsInstance = changes[i];
}
}
dispatchEvent(event);
}
}
/**
* Dispatch remove items event
* */
public function dispatchRemoveItemsEvent(target:*, changes:Array, properties:*, multipleSelection:Boolean = false):void {
var event:RadiateEvent = new RadiateEvent(RadiateEvent.REMOVE_ITEM, false, false, target, changes, properties, multipleSelection);
var length:int = changes ? changes.length : 0;
if (hasEventListener(RadiateEvent.REMOVE_ITEM)) {
event.properties = properties;
event.changes = changes;
event.multipleSelection = multipleSelection;
event.selectedItem = target && target is Array ? target[0] : target;
event.targets = ArrayUtil.toArray(target);
for (var i:int;i<length;i++) {
if (changes[i] is AddItems) {
event.addItemsInstance = changes[i];
event.moveItemsInstance = changes[i];
}
}
dispatchEvent(event);
}
}
/**
* Dispatch to invoke property edit event
* */
public function dispatchTargetPropertyEditEvent(target:Object, changes:Array, properties:Array, multipleSelection:Boolean = false):void {
var propertyEditEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROPERTY_EDIT, false, false, target, changes, properties, null, multipleSelection);
if (hasEventListener(RadiateEvent.PROPERTY_EDIT)) {
dispatchEvent(propertyEditEvent);
}
}
/**
* Dispatch document change event
* */
public function dispatchDocumentChangeEvent(document:IDocument):void {
var documentChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_CHANGE, false, false, document);
if (hasEventListener(RadiateEvent.DOCUMENT_CHANGE)) {
dispatchEvent(documentChangeEvent);
}
}
/**
* Dispatch document rename event
* */
public function dispatchDocumentRenameEvent(document:IDocument, name:String):void {
var documentRenameEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_RENAME, false, false, document);
if (hasEventListener(RadiateEvent.DOCUMENT_RENAME)) {
dispatchEvent(documentRenameEvent);
}
}
/**
* Dispatch project rename event
* */
public function dispatchProjectRenameEvent(project:IProject, name:String):void {
var projectRenameEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_RENAME, false, false, project);
if (hasEventListener(RadiateEvent.PROJECT_RENAME)) {
dispatchEvent(projectRenameEvent);
}
}
/**
* Dispatch documents set
* */
public function dispatchDocumentsSetEvent(documents:Array):void {
var documentChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENTS_SET, false, false, documents);
if (hasEventListener(RadiateEvent.DOCUMENTS_SET)) {
dispatchEvent(documentChangeEvent);
}
}
/**
* Dispatch document opening event
* */
public function dispatchDocumentOpeningEvent(document:IDocument, isPreview:Boolean = false):Boolean {
var documentOpeningEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_OPENING, false, true, document);
var dispatched:Boolean;
if (hasEventListener(RadiateEvent.DOCUMENT_OPENING)) {
dispatched = dispatchEvent(documentOpeningEvent);
}
return dispatched;
}
/**
* Dispatch document open event
* */
public function dispatchDocumentOpenEvent(document:IDocument):void {
var documentOpenEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_OPEN, false, false);
if (hasEventListener(RadiateEvent.DOCUMENT_OPEN)) {
documentOpenEvent.selectedItem = document;
dispatchEvent(documentOpenEvent);
}
}
/**
* Dispatch document removed event
* */
public function dispatchDocumentRemovedEvent(document:IDocument, successful:Boolean = true):void {
var documentRemovedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_REMOVED, false, false);
if (hasEventListener(RadiateEvent.DOCUMENT_REMOVED)) {
documentRemovedEvent.successful = successful;
documentRemovedEvent.selectedItem = document;
dispatchEvent(documentRemovedEvent);
}
}
/**
* Dispatch document save as complete event
* */
public function dispatchProjectSavedEvent(project:IProject):void {
var projectSaveEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_SAVED, false, false);
if (hasEventListener(RadiateEvent.PROJECT_SAVED)) {
projectSaveEvent.selectedItem = project;
dispatchEvent(projectSaveEvent);
}
}
/**
* Dispatch document save complete event
* */
public function dispatchDocumentSaveCompleteEvent(document:IDocument):void {
var documentSaveAsCompleteEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_SAVE_COMPLETE, false, false, document);
if (hasEventListener(RadiateEvent.DOCUMENT_SAVE_COMPLETE)) {
dispatchEvent(documentSaveAsCompleteEvent);
}
}
/**
* Dispatch document not saved event
* */
public function dispatchDocumentSaveFaultEvent(document:IDocument):void {
var documentSaveFaultEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_SAVE_FAULT, false, false, document);
if (hasEventListener(RadiateEvent.DOCUMENT_SAVE_FAULT)) {
dispatchEvent(documentSaveFaultEvent);
}
}
/**
* Dispatch document save as cancel event
* */
public function dispatchDocumentSaveAsCancelEvent(document:IDocument):void {
var documentSaveAsCancelEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_SAVE_AS_CANCEL, false, false, document);
if (hasEventListener(RadiateEvent.DOCUMENT_SAVE_AS_CANCEL)) {
dispatchEvent(documentSaveAsCancelEvent);
}
}
/**
* Dispatch document add event
* */
public function dispatchDocumentAddedEvent(document:IDocument):void {
var documentAddedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.DOCUMENT_ADDED, false, false, document, null, null);
if (hasEventListener(RadiateEvent.DOCUMENT_ADDED)) {
dispatchEvent(documentAddedEvent);
}
}
/**
* Dispatch project closing event
* */
public function dispatchProjectClosingEvent(project:IProject):void {
var projectClosingEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_CLOSING, false, false, project, null, null);
if (hasEventListener(RadiateEvent.PROJECT_CLOSING)) {
dispatchEvent(projectClosingEvent);
}
}
/**
* Dispatch project closed event
* */
public function dispatchProjectOpenedEvent(project:IProject):void {
var projectOpenedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_OPENED, false, false, project, null, null);
if (hasEventListener(RadiateEvent.PROJECT_OPENED)) {
dispatchEvent(projectOpenedEvent);
}
}
/**
* Dispatch project closed event
* */
public function dispatchProjectClosedEvent(project:IProject):void {
var projectClosedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_CLOSED, false, false, project, null, null);
if (hasEventListener(RadiateEvent.PROJECT_CLOSED)) {
dispatchEvent(projectClosedEvent);
}
}
/**
* Dispatch project removed event
* */
public function dispatchProjectRemovedEvent(project:IProject):void {
var projectRemovedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_REMOVED, false, false, project, null, null);
if (hasEventListener(RadiateEvent.PROJECT_REMOVED)) {
dispatchEvent(projectRemovedEvent);
}
}
/**
* Dispatch project change event
* */
public function dispatchProjectChangeEvent(project:IProject, multipleSelection:Boolean = false):void {
var projectChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_CHANGE, false, false, project, null, null, multipleSelection);
if (hasEventListener(RadiateEvent.PROJECT_CHANGE)) {
dispatchEvent(projectChangeEvent);
}
}
/**
* Dispatch projects set event
* */
public function dispatchProjectsSetEvent(projects:Array, multipleSelection:Boolean = false):void {
var projectChangeEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECTS_SET, false, false, projects, null, null, multipleSelection);
if (hasEventListener(RadiateEvent.PROJECTS_SET)) {
dispatchEvent(projectChangeEvent);
}
}
/**
* Dispatch project created event
* */
public function dispatchProjectAddedEvent(project:IProject):void {
var projectCreatedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_ADDED, false, false, project, null, null);
if (hasEventListener(RadiateEvent.PROJECT_ADDED)) {
dispatchEvent(projectCreatedEvent);
}
}
/**
* Dispatch project created event
* */
public function dispatchProjectCreatedEvent(project:IProject):void {
var projectCreatedEvent:RadiateEvent = new RadiateEvent(RadiateEvent.PROJECT_CREATED, false, false, project, null, null);
if (hasEventListener(RadiateEvent.PROJECT_CREATED)) {
dispatchEvent(projectCreatedEvent);
}
}
/**
* Dispatch a history change event
* */
public function dispatchHistoryChangeEvent(newIndex:int, oldIndex:int):void {
var event:RadiateEvent = new RadiateEvent(RadiateEvent.HISTORY_CHANGE);
if (hasEventListener(RadiateEvent.HISTORY_CHANGE)) {
event.newIndex = newIndex;
event.oldIndex = oldIndex;
event.historyEventItem = getHistoryItemAtIndex(newIndex);
dispatchEvent(event);
}
}
/**
* Sets the logging target
* */
public static function setLoggingTarget(target:AbstractTarget = null, category:String = null, consoleObject:Object = null):void {
// Log only messages for the classes in the mx.rpc.* and
// mx.messaging packages.
//logTarget.filters=["mx.rpc.*","mx.messaging.*"];
//var filters:Array = ["mx.rpc.*", "mx.messaging.*"];
//var filters:Array = ["mx.rpc.*", "mx.messaging.*"];
// Begin logging.
if (target) {
logTarget = target;
//logTarget.filters = filters;
logTarget.level = LogEventLevel.ALL;
Log.addTarget(target);
}
// set reference to logger
if (category) {
log = Log.getLogger(category);
}
else {
log = Log.getLogger(RADIATE_LOG);
}
if (consoleObject) {
console = consoleObject;
}
}
/**
* Creates the list of components and tools.
* */
public static function initialize():void {
var componentsXML:XML = new XML(new Radii8LibrarySparkAssets.sparkManifestDefaults());
var toolsXML:XML = new XML(new Radii8LibraryToolAssets.toolsManifestDefaults());
var inspectorsXML:XML = new XML(new Radii8LibraryInspectorAssets.inspectorsManifestDefaults());
var devicesXML:XML = new XML(new Radii8LibraryDeviceAssets.devicesManifestDefaults());
createSettingsData();
createSavedData();
createComponentList(componentsXML);
createInspectorsList(inspectorsXML);
createToolsList(toolsXML);
createDevicesList(devicesXML);
}
/**
* Startup
* */
public static function startup():void {
//ExternalInterface.call("Radiate.getInstance");
ExternalInterface.call("Radiate.instance.setFlashInstance", ExternalInterface.objectID);
//instance.getLoggedInStatus();
}
/**
* Creates the list of components.
* */
public static function createComponentList(xml:XML):void {
var length:uint;
var items:XMLList;
var className:String;
var skinClassName:String;
var inspectors:Array;
var hasDefinition:Boolean;
var classType:Object;
var includeItem:Boolean;
var attributes:XMLList;
var attributesLength:int;
var defaults:Object;
var propertyName:String;
var item:XML;
// get list of component classes
items = XML(xml).component;
length = items.length();
for (var i:int;i<length;i++) {
item = items[i];
var name:String = String(item.id);
className = item.attribute("class");
skinClassName = item.attribute("skinClass");
//inspectors = item.inspector;
includeItem = item.attribute("include")=="false" ? false : true;
// check that definitions exist in domain
// skip any support classes
if (className.indexOf("mediaClasses")==-1 &&
className.indexOf("gridClasses")==-1 &&
className.indexOf("windowClasses")==-1 &&
className.indexOf("supportClasses")==-1) {
hasDefinition = ApplicationDomain.currentDomain.hasDefinition(className);
if (hasDefinition) {
classType = ApplicationDomain.currentDomain.getDefinition(className);
// need to check if we have the skin as well
//hasDefinition = ApplicationDomain.currentDomain.hasDefinition(skinClassName);
if (hasDefinition) {
// get default values
if (item.defaults) {
attributes = item.defaults.attributes();
attributesLength = attributes.length();
defaults = {};
for each (var value:Object in attributes) {
propertyName = String(value.name());
if (propertyName=="dataProvider") {
var array:Array = String(value).split(",");
defaults[propertyName] = new ArrayCollection(array);
}
else {
defaults[propertyName] = String(value);
}
}
}
addComponentType(item.@id, className, classType, inspectors, null, defaults, null, includeItem);
}
else {
log.error("Component skin class, '" + skinClassName + "' not found for '" + className + "'.");
}
}
else {
log.error("Component class not found: " + className);
}
}
else {
// delete support classes
// may need to refactor why we are including them in the first place
delete items[i];
length--;
}
}
// componentDescriptions should now be populated
}
/**
* Creates the list of inspectors.
* */
public static function createInspectorsList(xml:XML):void {
var length:uint;
var inspectorsLength:uint;
var items:XMLList;
var className:String;
var skinClassName:String;
var inspectorClassName:String;
var hasDefinition:Boolean;
var classType:Object;
var includeItem:Boolean;
var attributes:XMLList;
var attributesLength:int;
var defaults:Object;
var propertyName:String;
var item:XML;
var inspectorItems:XMLList;
var inspector:XML;
var inspectableClass:InspectableClass;
var inspectorData:InspectorData;
// get list of inspector classes
items = XML(xml).item;
length = items.length();
// add inspectable classes to the dictionary
for (var i:int;i<length;i++) {
inspectableClass = new InspectableClass(items[i]);
className = inspectableClass.className;
if (inspectableClassesDictionary[className]==null) {
inspectableClassesDictionary[className] = inspectableClass;
}
else {
log.warn("Inspectable class, '" + className + "', was listed more than once during import.");
}
}
// check that definitions exist in domain
for each (inspectableClass in inspectableClassesDictionary) {
length = inspectableClass.inspectors.length;
j = 0;
for (var j:int;j<length;j++) {
inspectorData = inspectableClass.inspectors[j];
className = inspectorData.className;
if (inspectorsDictionary[className]==null) {
hasDefinition = ApplicationDomain.currentDomain.hasDefinition(className);
if (hasDefinition) {
classType = ApplicationDomain.currentDomain.getDefinition(className);
}
else {
log.error("Inspector class not found: " + className);
}
// not passing in classType now since we may load it in later dynamically
addInspectorType(inspectorData.name, className, null, inspectorData.icon, defaults);
}
else {
//log.warn("Inspector class: " + className + ", is already in the dictionary");
}
}
}
// inspectorsInstancesDictionary should now be populated
}
/**
* Creates the list of tools.
* */
public static function createToolsList(xml:XML):void {
var inspectorClassName:String;
var hasDefinition:Boolean;
var toolClassDefinition:Object;
var inspectorClassDefinition:Object;
var inspectorClassFactory:ClassFactory;
var toolClassFactory:ClassFactory;
var items:XMLList;
var className:String;
var includeItem:Boolean;
var attributes:XMLList;
var length:uint;
var attributesLength:int;
var defaults:Object;
var propertyName:String;
var toolInstance:ITool;
var inspectorInstance:UIComponent;
var name:String;
var cursorItems:XMLList;
var cursorItem:XML;
var cursorName:String;
var cursors:Dictionary;
var cursorsCount:int;
var cursorData:MouseCursorData;
var cursorBitmapDatas:Vector.<BitmapData>;
var cursorBitmap:Bitmap;
var cursorClass:Class;
var cursorID:String;
var cursorX:int;
var cursorY:int;
var item:XML;
// get list of tool classes
items = XML(xml).tool;
length = items.length();
for (var i:int;i<length;i++) {
item = items[i];
name = String(item.id);
className = item.attribute("class");
inspectorClassName = item.attribute("inspector");
cursorItems = item..cursor;
includeItem = item.attribute("include")=="false" ? false : true;
if (!includeItem) continue;
hasDefinition = ApplicationDomain.currentDomain.hasDefinition(className);
if (hasDefinition) {
toolClassDefinition = ApplicationDomain.currentDomain.getDefinition(className);
// get default values
if (item.defaults) {
attributes = item.defaults.attributes();
attributesLength = attributes.length();
defaults = {};
for each (var value:Object in attributes) {
propertyName = String(value.name());
if (propertyName=="dataProvider") {
defaults[propertyName] = new ArrayCollection(String(value).split(","));
}
else {
defaults[propertyName] = String(value);
}
}
}
// create tool
toolClassFactory = new ClassFactory(toolClassDefinition as Class);
toolClassFactory.properties = defaults;
toolInstance = toolClassFactory.newInstance();
// create inspector
if (inspectorClassName!="") {
hasDefinition = ApplicationDomain.currentDomain.hasDefinition(inspectorClassName);
if (hasDefinition) {
inspectorClassDefinition = ApplicationDomain.currentDomain.getDefinition(inspectorClassName);
// Create tool inspector
inspectorClassFactory = new ClassFactory(inspectorClassDefinition as Class);
//classFactory.properties = defaults;
inspectorInstance = inspectorClassFactory.newInstance();
}
else {
var errorMessage:String = "Could not find inspector, '" + inspectorClassName + "' for tool, '" + className + "'. ";
errorMessage += "You may need to add a reference to it in RadiateReferences.";
log.error(errorMessage);
}
}
cursorsCount = cursorItems.length();
if (cursorsCount>0) {
cursors = new Dictionary(false);
}
// create mouse cursors
for (var j:int=0;j<cursorsCount;j++) {
cursorItem = cursorItems[j];
cursorName = cursorItem.@name.toString();
cursorX = int(cursorItem.@x.toString());
cursorY = int(cursorItem.@y.toString());
cursorID = cursorName != "" ? className + "." + cursorName : className;
// Create a MouseCursorData object
cursorData = new MouseCursorData();
// Specify the hotspot
cursorData.hotSpot = new Point(cursorX, cursorY);
// Pass the cursor bitmap to a BitmapData Vector
cursorBitmapDatas = new Vector.<BitmapData>(1, true);
// Create the bitmap cursor
// The bitmap must be 32x32 pixels or smaller, due to an OS limitation
//CursorClass = Radii8LibraryToolAssets.EyeDropper;
if (cursorName) {
cursorClass = toolClassDefinition[cursorName];
}
else {
cursorClass = toolClassDefinition["Cursor"];
}
cursorBitmap = new cursorClass();
// Pass the value to the bitmapDatas vector
cursorBitmapDatas[0] = cursorBitmap.bitmapData;
// Assign the bitmap to the MouseCursor object
cursorData.data = cursorBitmapDatas;
// Register the MouseCursorData to the Mouse object with an alias
Mouse.registerCursor(cursorID, cursorData);
cursors[cursorName] = {cursorData:cursorData, id:cursorID};
}
if (cursorsCount>0) {
mouseCursors[className] = cursors;
}
//trace("tool cursors:", cursors);
var toolDescription:ComponentDescription = addToolType(item.@id, className, toolClassDefinition, toolInstance, inspectorClassName, null, defaults, null, cursors);
//trace("tool cursors:", toolDescription.cursors);
}
else {
//trace("Tool class not found: " + classDefinition);
log.error("Tool class not found: " + toolClassDefinition);
}
}
// toolDescriptions should now be populated
}
/**
* Creates the list of devices.
* */
public static function createDevicesList(xml:XML):void {
var includeItem:Boolean;
var items:XMLList;
var length:uint;
var name:String;
var item:XML;
var device:Device;
var type:String;
const RES_WIDTH:String = "resolutionWidth";
const RES_HEIGHT:String = "resolutionHeight";
const USABLE_WIDTH_PORTRAIT:String = "usableWidthPortrait";
const USABLE_HEIGHT_PORTRAIT:String = "usableHeightPortrait";
const USABLE_WIDTH_LANDSCAPE:String = "usableWidthLandscape";
const USABLE_HEIGHT_LANDSCAPE:String = "usableHeightLandscape";
// get list of device classes
items = XML(xml).size;
length = items.length();
for (var i:int;i<length;i++) {
item = items[i];
name = item.attribute("name");
type = item.attribute("type");
device = new Device();
device.name = name;
device.type = type;
if (type=="device") {
device.ppi = item.attribute("ppi");
device.resolutionWidth = item.attribute(RES_WIDTH);
device.resolutionHeight = item.attribute(RES_HEIGHT);
device.usableWidthPortrait = item.attribute(USABLE_WIDTH_PORTRAIT);
device.usableHeightPortrait = item.attribute(USABLE_HEIGHT_PORTRAIT);
device.usableWidthLandscape = item.attribute(USABLE_WIDTH_LANDSCAPE);
device.usableHeightLandscape = item.attribute(USABLE_HEIGHT_LANDSCAPE);
}
else if (type=="screen") {
device.ppi = item.attribute("ppi");
device.resolutionWidth = item.attribute(RES_WIDTH);
device.resolutionHeight = item.attribute(RES_HEIGHT);
continue;
}
includeItem = item.attribute("include")=="false" ? false : true;
deviceCollections.addItem(device);
}
// deviceDescriptions should now be populated
}
/**
* Helper method to get the ID of the mouse cursor by name.
*
* */
public function getMouseCursorID(tool:ITool, name:String = "Cursor"):String {
var component:ComponentDescription = getToolDescription(tool);
if (component.cursors && component.cursors[name]) {
return component.cursors[name].id;
}
return null;
}
//----------------------------------
// target
//----------------------------------
/**
* Use setTarget() or setTargets() method to set the target.
* */
public function get target():Object {
if (_targets.length > 0)
return _targets[0];
else
return null;
}
/**
* @private
*/
/*[Bindable]
public function set target(value:Object):void {
if (_targets.length == 1 && target==value) return;
_targets.splice(0);
if (value) {
_targets[0] = value;
}
}*/
//----------------------------------
// targets
//----------------------------------
/**
* @private
* Storage for the targets property.
*/
private var _targets:Array = [];
/**
* Selected targets
* */
public function get targets():Array {
return _targets;
}
/**
* Use setTargets() to set the targets
* @private
* */
/*public function set targets(value:Array):void {
// remove listeners from previous targets
var n:int = _targets.length;
for (var i:int = n - 1; i >= 0; i--) {
if (_targets[i] == null) {
continue;
}
//removeHandlers(_targets[i]);
}
// Strip out null values.
// Binding will trigger again when the null targets are created.
n = value.length;
for (i = n - 1; i >= 0; i--) {
if (value[i] == null) {
value.splice(i,1);
continue;
}
//addHandlers(value[i]);
}
_targets = value;
}*/
//----------------------------------
// project
//----------------------------------
private var _selectedProject:IProject;
/**
* Reference to the current project
* */
public function get selectedProject():IProject {
return _selectedProject;
}
/**
* @private
*/
[Bindable(event="projectChange")]
public function set selectedProject(value:IProject):void {
if (value==_selectedProject) return;
_selectedProject = value;
}
//----------------------------------
// document
//----------------------------------
private var _documentsTabNavigator:TabNavigator;
/**
* Reference to the tab navigator that creates documents
* */
public function get documentsTabNavigator():TabNavigator {
return _documentsTabNavigator;
}
/**
* @private
*/
public function set documentsTabNavigator(value:TabNavigator):void {
_documentsTabNavigator = value;
}
/**
* Reference to the tab that the document belongs to
* */
public var documentsContainerDictionary:Dictionary = new Dictionary(true);
/**
* Reference to the tab that the document preview belongs to
* */
public var documentsPreviewDictionary:Dictionary = new Dictionary(true);
private var _selectedDocument:IDocument;
/**
* Get the current document.
* */
public function get selectedDocument():IDocument {
return _selectedDocument;
}
/**
* @private
*/
[Bindable(event="documentChange")]
public function set selectedDocument(value:IDocument):void {
if (value==_selectedDocument) return;
_selectedDocument = value;
}
/**
* Templates for creating new projects or documents
* */
[Bindable]
public var templates:Array;
//----------------------------------
// documents
//----------------------------------
/**
* @private
* Storage for the documents property.
*/
private var _documents:Array = [];
/**
* Selected documents
* */
public function get documents():Array {
return _documents;
}
/**
* Selected documents
* @private
* */
[Bindable]
public function set documents(value:Array):void {
// the following comments are old possibly irrelevant...
// remove listeners from previous documents
var n:int = _documents.length;
for (var i:int = n - 1; i >= 0; i--) {
if (_documents[i] == null) {
continue;
}
//removeHandlers(_documents[i]);
}
// Strip out null values.
// Binding will trigger again when the null documents are created.
n = value.length;
for (i = n - 1; i >= 0; i--) {
if (value[i] == null) {
value.splice(i,1);
continue;
}
//addHandlers(value[i]);
}
_documents = value;
}
//----------------------------------
// projects
//----------------------------------
/**
* Reference to the projects belongs to
* */
public var projectsDictionary:Dictionary = new Dictionary(true);
/**
* @private
* Storage for the projects property.
*/
private var _projects:Array = [];
/**
* Selected projects
* */
public function get projects():Array {
return _projects;
}
/**
* Selected projects
* @private
* */
[Bindable]
public function set projects(value:Array):void {
_projects = value;
}
private var _attachments:Array = [];
/**
* Attachments
* */
[Bindable]
public function get attachments():Array {
return _attachments;
}
public function set attachments(value:Array):void {
_attachments = value;
}
private var _assets:ArrayCollection = new ArrayCollection();
/**
* Assets
* */
[Bindable]
public function get assets():ArrayCollection {
return _assets;
}
public function set assets(value:ArrayCollection):void {
_assets = value;
}
private var _toolLayer:IVisualElementContainer;
/**
* Container that tools can draw too
* */
public function get toolLayer():IVisualElementContainer {
return _toolLayer;
}
/**
* @private
*/
public function set toolLayer(value:IVisualElementContainer):void {
_toolLayer = value;
}
/**
* Default log target
* */
public static var defaultLogTarget:AbstractTarget = new RadiateLogTarget();
/**
* Attempt to support a console
* */
public static var logTarget:AbstractTarget;
private static var _log:ILogger;
private static var _console:Object;
public static var SETTINGS_DATA_NAME:String = "settingsData";
public static var SAVED_DATA_NAME:String = "savedData";
public static var WP_HOST:String = "http://www.radii8.com";
public static var WP_PATH:String = "/r8m/";
public static var WP_USER_PATH:String = "";
public static var DEFAULT_DOCUMENT_WIDTH:int = 800;
public static var DEFAULT_DOCUMENT_HEIGHT:int = 792;
public static function getWPURL():String {
return WP_HOST + WP_PATH + WP_USER_PATH;
}
/**
* Is true when preview is visible. This is manually set.
* Needs refactoring.
* */
public var isPreviewVisible:Boolean;
/**
* Settings
* */
public static var settings:Settings;
/**
* Settings
* */
public static var savedData:SavedData;
/**
* Collection of mouse cursors that can be added or removed to
* */
[Bindable]
public static var mouseCursors:Dictionary = new Dictionary(true);
//----------------------------------
//
// Device Management
//
//----------------------------------
/**
* Collection of devices
* */
[Bindable]
public static var deviceCollections:ArrayCollection = new ArrayCollection();
//----------------------------------
//
// Tools Management
//
//----------------------------------
public var _selectedTool:ITool;
/**
* Get selected tool.
* */
public function get selectedTool():ITool {
return _selectedTool;
}
/**
* Collection of tools that can be added or removed to
* */
[Bindable]
public static var toolsDescriptions:ArrayCollection = new ArrayCollection();
/**
* Add the named tool class to the list of available tools.
*
* Not sure if we should create an instance here or earlier or later.
* */
public static function addToolType(name:String, className:String, classType:Object, instance:ITool, inspectorClassName:String, icon:Object = null, defaultProperties:Object=null, defaultStyles:Object=null, cursors:Dictionary = null):ComponentDescription {
var definition:ComponentDescription;
var length:uint = toolsDescriptions.length;
var item:ComponentDescription;
for (var i:uint;i<length;i++) {
item = toolsDescriptions.getItemAt(i) as ComponentDescription;
// check if it exists already
if (item && item.classType==classType) {
return item;
//return false;
}
}
definition = new ComponentDescription();
definition.name = name;
definition.icon = icon;
definition.className = className;
definition.classType = classType;
definition.defaultStyles = defaultStyles;
definition.defaultProperties = defaultProperties;
definition.instance = instance;
definition.inspectorClassName = inspectorClassName;
definition.cursors = cursors;
toolsDescriptions.addItem(definition);
return definition;
}
/**
* Sets the selected tool
* */
public function setTool(value:ITool, dispatchEvent:Boolean = true, cause:String = ""):void {
if (selectedTool) {
selectedTool.disable();
}
_selectedTool = value;
if (selectedTool) {
selectedTool.enable();
}
if (dispatchEvent) {
instance.dispatchToolChangeEvent(selectedTool);
}
}
/**
* Get tool description.
* */
public function getToolDescription(instance:ITool):ComponentDescription {
var length:int = toolsDescriptions.length;
var componentDescription:ComponentDescription;
for (var i:int;i<length;i++) {
componentDescription = ComponentDescription(toolsDescriptions.getItemAt(i));
if (componentDescription.instance==instance) {
return componentDescription;
}
}
return null;
}
/**
* Get tool by name.
* */
public function getToolByName(name:String):ComponentDescription {
var length:int = toolsDescriptions.length;
var componentDescription:ComponentDescription;
for (var i:int;i<length;i++) {
componentDescription = ComponentDescription(toolsDescriptions.getItemAt(i));
if (componentDescription.className==name) {
return componentDescription;
}
}
return null;
}
/**
* Get tool by type.
* */
public function getToolByType(type:Class):ComponentDescription {
var length:int = toolsDescriptions.length;
var componentDescription:ComponentDescription;
for (var i:int;i<length;i++) {
componentDescription = ComponentDescription(toolsDescriptions.getItemAt(i));
if (componentDescription.classType==type) {
return componentDescription;
}
}
return null;
}
//----------------------------------
//
// Inspector Management
//
//----------------------------------
/**
* Collection of inspectors that can be added or removed to
* */
[Bindable]
public static var inspectorsDescriptions:ArrayCollection = new ArrayCollection();
/**
* Dictionary of classes that have inspectors
* */
[Bindable]
public static var inspectableClassesDictionary:Dictionary = new Dictionary();
/**
* Dictionary of instances of inspectors searched by class name
* */
[Bindable]
public static var inspectorsDictionary:Dictionary = new Dictionary();
/**
* Add the named inspector class to the list of available inspectors
* */
public static function addInspectorType(name:String, className:String, classType:Object, icon:Object = null, defaults:Object=null):Boolean {
var inspectorData:InspectorData;
if (inspectorsDictionary[className]==null) {
inspectorData = new InspectorData();
inspectorData.name = name==null ? className : name;
inspectorData.className = className;
inspectorData.classType = classType;
inspectorData.icon = icon;
inspectorData.defaults = defaults;
inspectorsDictionary[className] = inspectorData;
}
return true;
}
/**
* Gets inspector classes or null if the definition is not found.
* */
public function getInspectableClassData(className:String):InspectableClass {
var inspectableClass:InspectableClass = inspectableClassesDictionary[className];
return inspectableClass;
}
/**
* Gets an instance of the inspector class or null if the definition is not found.
* */
public function getInspectorInstance(className:String):IInspector {
var inspectorData:InspectorData = inspectorsDictionary[className];
if (inspectorData) {
if (inspectorData.instance) {
return inspectorData.instance;
}
var instance:IInspector = inspectorData.getInstance();
return instance;
}
return null;
}
/**
* Gets an instance of the inspector class or null if the definition is not found.
* */
public function getInspector(target:Object, domain:ApplicationDomain = null):IInspector {
var className:String;
if (target) {
className = ClassUtils.getQualifiedClassName(target);
var instance:IInspector = getInspectorInstance(className);
return instance;
}
return null;
}
/**
* Gets array of inspector data for the given fully qualified class or object
* */
public function getInspectors(target:Object):Array {
var className:String;
var inspectors:Array;
var inspectorDataArray:Array;
var inspectableClass:InspectableClass;
var length:int;
if (target==null) return [];
if (target is Object) {
className = ClassUtils.getQualifiedClassName(target);
if (target is Application) {
className = ClassUtils.getSuperClassName(target);
}
}
if (target is String) {
className = String(target);
}
className = className ? className.split("::").join(".") : className;
inspectableClass = getInspectableClassData(className);
if (inspectableClass) {
return inspectableClass.inspectors;
}
return [];
}
//----------------------------------
//
// Scale Management
//
//----------------------------------
/**
* Stops on the scale
* */
public var scaleStops:Array = [.05,.0625,.0833,.125,.1666,.25,.333,.50,.667,1,1.25,1.50,1.75,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];
/**
* Increases the zoom of the target application to next value
* */
public function increaseScale(valueFrom:Number = NaN, dispatchEvent:Boolean = true):void {
var newScale:Number;
var currentScale:Number;
if (isNaN(valueFrom)) {
currentScale = Number(DisplayObject(selectedDocument.instance).scaleX.toFixed(4));
}
else {
currentScale = valueFrom;
}
//newScale = DisplayObject(document).scaleX;
for (var i:int=0;i<scaleStops.length;i++) {
if (currentScale<scaleStops[i]) {
newScale = scaleStops[i];
break;
}
}
if (i==scaleStops.length-1) {
newScale = scaleStops[i];
}
newScale = Number(newScale.toFixed(4));
setScale(newScale, dispatchEvent);
}
/**
* Decreases the zoom of the target application to next value
* */
public function decreaseScale(valueFrom:Number = NaN, dispatchEvent:Boolean = true):void {
var newScale:Number;
var currentScale:Number;
if (isNaN(valueFrom)) {
currentScale = Number(DisplayObject(selectedDocument.instance).scaleX.toFixed(4));
}
else {
currentScale = valueFrom;
}
//newScale = DisplayObject(document).scaleX;
for (var i:int=scaleStops.length;i--;) {
if (currentScale>scaleStops[i]) {
newScale = scaleStops[i];
break;
}
}
if (i==0) {
newScale = scaleStops[i];
}
newScale = Number(newScale.toFixed(4));
setScale(newScale, dispatchEvent);
}
/**
* Sets the zoom of the target application to value.
* */
public function setScale(value:Number, dispatchEvent:Boolean = true):void {
if (selectedDocument && !isNaN(value) && value>0) {
//DisplayObject(selectedDocument.instance).scaleX = value;
//DisplayObject(selectedDocument.instance).scaleY = value;
selectedDocument.scale = value;
if (dispatchEvent) {
dispatchScaleChangeEvent(selectedDocument, value, value);
}
}
}
/**
* Gets the scale of the target application.
* */
public function getScale():Number {
if (selectedDocument && selectedDocument.instance && "scaleX" in selectedDocument.instance) {
return Math.max(selectedDocument.instance.scaleX, selectedDocument.instance.scaleY);
}
return NaN;
}
/**
* Center the application
* */
public function centerApplication(vertically:Boolean = true, verticallyTop:Boolean = true, totalDocumentPadding:int = 0):void {
if (!canvasScroller) return;
var viewport:IViewport = canvasScroller.viewport;
var documentVisualElement:IVisualElement = IVisualElement(selectedDocument.instance);
//var contentHeight:int = viewport.contentHeight * getScale();
//var contentWidth:int = viewport.contentWidth * getScale();
// get document size NOT scroll content size
var contentHeight:int = documentVisualElement.height * getScale();
var contentWidth:int = documentVisualElement.width * getScale();
var newHorizontalPosition:int;
var newVerticalPosition:int;
var needsValidating:Boolean;
var vsbWidth:int = canvasScroller.verticalScrollBar ? canvasScroller.verticalScrollBar.width : 11;
var hsbHeight:int = canvasScroller.horizontalScrollBar ? canvasScroller.horizontalScrollBar.height : 11;
var availableWidth:int = canvasScroller.width;// - vsbWidth;
var availableHeight:int = canvasScroller.height;// - hsbHeight;
if (LayoutManager.getInstance().isInvalid()) {
needsValidating = true;
//LayoutManager.getInstance().validateClient(canvasScroller as ILayoutManagerClient);
//LayoutManager.getInstance().validateNow();
}
if (vertically) {
// scroller height 359, content height 504, content height validated 550
// if document is taller than available space and
// verticalTop is true then keep it at the top
if (contentHeight > availableHeight && verticallyTop) {
newVerticalPosition = canvasBackground.y - totalDocumentPadding;
viewport.verticalScrollPosition = Math.max(0, newVerticalPosition);
}
else if (contentHeight > availableHeight) {
newVerticalPosition = (contentHeight + hsbHeight - availableHeight) / 2;
viewport.verticalScrollPosition = Math.max(0, newVerticalPosition);
}
else {
// content height 384, scroller height 359, vsp 12
newVerticalPosition = (availableHeight + hsbHeight - contentHeight) / 2;
viewport.verticalScrollPosition = Math.max(0, newVerticalPosition);
}
}
// if width of content is wider than canvasScroller width then center
if (canvasScroller.width < contentWidth) {
newHorizontalPosition = (contentWidth - availableWidth) / 2;
viewport.horizontalScrollPosition = Math.max(0, newHorizontalPosition);
}
else {
//newHorizontalPosition = (contentWidth - canvasScroller.width) / 2;
//viewport.horizontalScrollPosition = Math.max(0, newHorizontalPosition);
}
}
/**
* Restores the scale of the target application to 100%.
* */
public function restoreDefaultScale(dispatchEvent:Boolean = true):void {
if (selectedDocument) {
setScale(1, dispatchEvent);
}
}
/**
* Sets the scale to fit the available space.
* */
public function scaleToFit(dispatchEvent:Boolean = true):void {
var width:int;
var height:int;
var availableWidth:int;
var availableHeight:int;
var widthScale:Number;
var heightScale:Number;
var newScale:Number;
var documentVisualElement:IVisualElement = selectedDocument ? selectedDocument.instance as IVisualElement : null;
if (documentVisualElement) {
//width = DisplayObject(document).width;
//height = DisplayObject(document).height;
width = documentVisualElement.width;
height = documentVisualElement.height;
var vsbWidth:int = canvasScroller.verticalScrollBar ? canvasScroller.verticalScrollBar.width : 20;
var hsbHeight:int = canvasScroller.horizontalScrollBar ? canvasScroller.horizontalScrollBar.height : 20;
availableWidth = canvasScroller.width - vsbWidth*2.5;
availableHeight = canvasScroller.height - hsbHeight*2.5;
//var scrollerPaddedWidth:int = canvasScroller.width + documentPadding;
//var scrollerPaddedHeight:int = canvasScroller.height + documentPadding;
// if the visible area is less than our content then scale down
if (height > availableHeight || width > availableWidth) {
heightScale = availableHeight/height;
widthScale = availableWidth/width;
newScale = Math.min(widthScale, heightScale);
width = newScale * width;
height = newScale * height;
}
else if (height < availableHeight && width < availableWidth) {
newScale = Math.min(availableHeight/height, availableWidth/width);
width = newScale * width;
height = newScale * height;
//newScale = Math.min(availableHeight/height, availableWidth/width);
//newScale = Math.max(availableHeight/height, availableWidth/width);
}
setScale(newScale, dispatchEvent);
////////////////////////////////////////////////////////////////////////////////
/*var documentRatio:Number = width / height;
var canvasRatio:Number = availableWidth / availableHeight;
var newRatio:Number = documentRatio / canvasRatio;
newRatio = canvasRatio / documentRatio;
newRatio = 1-documentRatio / canvasRatio;*/
}
}
//----------------------------------
//
// Documentation Utility
//
//----------------------------------
public static var docsURL:String = "http://flex.apache.org/asdoc/";
public static var docsURL2:String = "http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/";
/**
* Returns the URL to the help document online based on MetaData passed to it.
* */
public static function getURLToHelp(metadata:MetaData, useBackupURL:Boolean = true):String {
var path:String = "";
var currentClass:String;
var sameClass:Boolean;
var prefix:String = "";
var url:String;
var packageName:String;
var declaredBy:String;
var backupURLNeeded:Boolean;
if (metadata && metadata.declaredBy) {
declaredBy = metadata.declaredBy;
currentClass = declaredBy.replace(/::|\./g, "/");
if (declaredBy.indexOf(".")!=-1) {
packageName = declaredBy.split(".")[0];
if (packageName=="flash") {
backupURLNeeded = true;
}
}
if (metadata is StyleMetaData) {
prefix = "style:";
}
else if (metadata is EventMetaData) {
prefix = "event:";
}
path = currentClass + ".html#" + prefix + metadata.name;
}
if (useBackupURL && backupURLNeeded) {
url = docsURL2 + path;
}
else {
url = docsURL + path;
}
return url;
}
//----------------------------------
//
// Component Management
//
//----------------------------------
/**
* Collection of visual elements that can be added or removed to
* */
[Bindable]
public static var componentDefinitions:ArrayCollection = new ArrayCollection();
/**
* Cache for component icons
* */
[Bindable]
public static var contentCache:ContentCache = new ContentCache();
/**
* Add the named component class to the list of available components
* */
public static function addComponentType(name:String, className:String, classType:Object, inspectors:Array = null, icon:Object = null, defaultProperties:Object=null, defaultStyles:Object=null, enabled:Boolean = true):Boolean {
var definition:ComponentDefinition;
var length:uint = componentDefinitions.length;
var item:ComponentDefinition;
for (var i:uint;i<length;i++) {
item = ComponentDefinition(componentDefinitions.getItemAt(i));
// check if it exists already
if (item && item.classType==classType) {
return false;
}
}
definition = new ComponentDefinition();
definition.name = name;
definition.icon = icon;
definition.className = className;
definition.classType = classType;
definition.defaultStyles = defaultStyles;
definition.defaultProperties = defaultProperties;
definition.inspectors = inspectors;
definition.enabled = enabled;
componentDefinitions.addItem(definition);
return true;
}
/**
* Remove the named component class
* */
public static function removeComponentType(className:String):Boolean {
var definition:ComponentDefinition;
var length:uint = componentDefinitions.length;
var item:ComponentDefinition;
for (var i:uint;i<length;i++) {
item = ComponentDefinition(componentDefinitions.getItemAt(i));
if (item && item.classType==className) {
componentDefinitions.removeItemAt(i);
}
}
return true;
}
/**
* Get the component by class name
* */
public static function getComponentType(className:String, fullyQualified:Boolean = false):ComponentDefinition {
var definition:ComponentDefinition;
var length:uint = componentDefinitions.length;
var item:ComponentDefinition;
for (var i:uint;i<length;i++) {
item = ComponentDefinition(componentDefinitions.getItemAt(i));
if (fullyQualified) {
if (item && item.className==className) {
return item;
}
}
else {
if (item && item.name==className) {
return item;
}
}
}
return null;
}
/**
* Get the component by class name
* */
public static function getDynamicComponentType(className:String, fullyQualified:Boolean = false):ComponentDefinition {
var definition:ComponentDefinition;
var length:uint = componentDefinitions.length;
var item:ComponentDefinition;
for (var i:uint;i<length;i++) {
item = ComponentDefinition(componentDefinitions.getItemAt(i));
if (fullyQualified) {
if (item && item.className==className) {
return item;
}
}
else {
if (item && item.name==className) {
return item;
}
}
}
var hasDefinition:Boolean = ApplicationDomain.currentDomain.hasDefinition(className);
if (hasDefinition) {
addComponentType(className, className, null, null);
item = getComponentType(className, fullyQualified);
return item;
}
return null;
}
/**
* Removes all components. If components were removed then returns true.
* */
public static function removeAllComponents():Boolean {
var length:uint = componentDefinitions.length;
if (length) {
componentDefinitions.removeAll();
return true;
}
return false;
}
/**
* Add an asset
* */
public function addAssets(data:Array, dispatchEvents:Boolean = true):void {
var length:int;
var added:Boolean;
if (data) {
length = data.length;
for (var i:int;i<length;i++) {
addAsset(data[i], dispatchEvents);
}
}
}
/**
* Add an asset
* */
public function addAsset(data:DocumentData, dispatchEvent:Boolean = true):void {
var length:int = assets.length;
var found:Boolean;
var item:DocumentData;
for (var i:int;i<length;i++) {
item = assets.getItemAt(i) as DocumentData;
if (item.id==data.id && item.id!=null) {
found = true;
break;
}
}
if (!found) {
assets.addItem(data);
}
if (!found && dispatchEvent) {
dispatchAssetAddedEvent(data);
}
}
/**
* Remove an asset
* */
public function removeAsset(iDocumentData:IDocumentData, locations:String = null, dispatchEvents:Boolean = true):Boolean {
if (locations==null) locations = DocumentData.REMOTE_LOCATION;
var remote:Boolean = getIsRemoteLocation(locations);
var index:int = assets.getItemIndex(iDocumentData);
var removedInternally:Boolean;
if (index!=-1) {
assets.removeItemAt(index);
removedInternally = true;
}
if (remote && iDocumentData && iDocumentData.id) {
// we need to create service
if (deleteAttachmentService==null) {
deleteAttachmentService = new WPService();
deleteAttachmentService.addEventListener(WPService.RESULT, deleteDocumentResultsHandler, false, 0, true);
deleteAttachmentService.addEventListener(WPService.FAULT, deleteDocumentFaultHandler, false, 0, true);
}
deleteAttachmentService.host = getWPURL();
deleteDocumentInProgress = true;
deleteAttachmentService.deleteAttachment(int(iDocumentData.id), true);
}
/*else if (remote) { // document not saved yet because no ID
if (dispatchEvents) {
dispatchAssetRemovedEvent(iDocumentData, removedInternally);
return removedInternally;
}
}
else {
if (dispatchEvents) {
dispatchAssetRemovedEvent(iDocumentData, removedInternally);
return removedInternally;
}
}*/
dispatchAssetRemovedEvent(iDocumentData, removedInternally);
return removedInternally;
}
/**
* The canvas border.
* */
public var canvasBorder:Object;
/**
* The canvas background.
* */
public var canvasBackground:Object;
/**
* The canvas scroller.
* */
public var canvasScroller:Scroller;
/**
* Sets the canvas and canvas parent. Not sure if going to be used.
* May use canvas property on document.
* */
public function setCanvas(canvasBorder:Object, canvasBackground:Object, canvasScroller:Scroller, dispatchEvent:Boolean = true, cause:String = ""):void {
//if (this.canvasBackground==canvasBackground) return;
this.canvasBorder = canvasBorder;
this.canvasBackground = canvasBackground;
this.canvasScroller = canvasScroller;
if (dispatchEvent) {
instance.dispatchCanvasChangeEvent(canvasBackground, canvasBorder, canvasScroller);
}
}
/**
* Sets the document
* */
public function setProject(value:IProject, dispatchEvent:Boolean = true, cause:String = ""):void {
selectedProject = value;
/*if (_projects.length == 1 && projects==value) return;
_projects = null;// without this, the contents of the array would change across all instances
_projects = [];
if (value) {
_projects[0] = value;
}*/
if (dispatchEvent) {
instance.dispatchProjectChangeEvent(selectedProject);
}
}
/**
* Selects the target
* */
public function setProjects(value:*, dispatchEvent:Boolean = true, cause:String = ""):void {
value = ArrayUtil.toArray(value);
// remove listeners from previous documents
var n:int = _projects.length;
for (var i:int = n - 1; i >= 0; i--) {
if (_projects[i] == null) {
continue;
}
//removeHandlers(_projects[i]);
}
// Strip out null values.
// Binding will trigger again when the null projects are created.
n = value.length;
for (i = n - 1; i >= 0; i--) {
if (value[i] == null) {
value.splice(i,1);
continue;
}
//addHandlers(value[i]);
}
_projects = value;
if (dispatchEvent) {
instance.dispatchProjectsSetEvent(projects);
}
}
/**
* Sets the current document
* */
public function setDocument(value:IDocument, dispatchEvent:Boolean = true, cause:String = ""):void {
if (selectedDocument != value) {
selectedDocument = value;
}
var container:IDocumentContainer = documentsContainerDictionary[value] as IDocumentContainer;
if (container) {
toolLayer = container.toolLayer;
canvasBorder = container.canvasBorder;
canvasBackground= container.canvasBackground;
canvasScroller = container.canvasScroller;
}
history = selectedDocument ? selectedDocument.history : null;
history ? history.refresh() : void;
historyIndex = getHistoryIndex();
if (dispatchEvent) {
instance.dispatchDocumentChangeEvent(selectedDocument);
}
}
/**
* Selects the target
* */
public function setDocuments(value:*, dispatchEvent:Boolean = true, cause:String = ""):void {
value = ArrayUtil.toArray(value);
// remove listeners from previous documents
var n:int = _documents.length;
for (var i:int = n - 1; i >= 0; i--) {
if (_documents[i] == null) {
continue;
}
//removeHandlers(_documents[i]);
}
// Strip out null values.
// Binding will trigger again when the null documents are created.
n = value.length;
for (i = n - 1; i >= 0; i--) {
if (value[i] == null) {
value.splice(i,1);
continue;
}
//addHandlers(value[i]);
}
_documents = value;
if (dispatchEvent) {
instance.dispatchDocumentsSetEvent(documents);
}
}
/**
* Selects the target
* */
public function setTarget(value:*, dispatchEvent:Boolean = true, cause:String = ""):void {
if (_targets.length == 1 && target==value) return;
_targets = null;// without this, the contents of the array would change across all instances
_targets = [];
if (value) {
_targets[0] = value;
}
if (dispatchEvent) {
instance.dispatchTargetChangeEvent(target);
}
}
/**
* Selects the target
* */
public function setTargets(value:*, dispatchEvent:Boolean = true, cause:String = ""):void {
value = ArrayUtil.toArray(value);
// remove listeners from previous targets
var n:int = _targets.length;
for (var i:int = n - 1; i >= 0; i--) {
if (_targets[i] == null) {
continue;
}
//removeHandlers(_targets[i]);
}
// Strip out null values.
// Binding will trigger again when the null targets are created.
n = value.length;
for (i = n - 1; i >= 0; i--) {
if (value[i] == null) {
value.splice(i,1);
continue;
}
//addHandlers(value[i]);
}
_targets = value;
if (dispatchEvent) {
instance.dispatchTargetChangeEvent(_targets, true);
}
}
/**
* Deselects the passed in targets
* */
public function desetTargets(value:*, dispatchEvent:Boolean = true, cause:String = ""):void {
value = ArrayUtil.toArray(value);
throw new Error("not done");
// go through current targets and remove any that match the ones in the values
// remove listeners from previous targets
var targetsLength:int = _targets.length;
var valuesLength:int = value ? value.length : 0;
for (var i:int=0;i<targetsLength;i++) {
for (var j:int=0;j<valuesLength;j++) {
if (value[j]==_targets[i]) {
_targets.splice(i,1);
continue;
}
}
}
if (dispatchEvent) {
instance.dispatchTargetChangeEvent(_targets, true);
}
}
/**
* Deselects the target
* */
public function deselectedTarget(dispatchEvent:Boolean = true, cause:String = ""):void {
// go through current targets and remove any that match the ones in the values
setTarget(null, dispatchEvent, cause);
}
/**
* Deselects the target
* */
public static function clearTarget(dispatchEvent:Boolean = true, cause:String = ""):void {
setTarget(null, dispatchEvent, cause);
}
/**
* Selects the target
* */
public static function setTarget(value:DisplayObject, dispatchEvent:Boolean = true, cause:String = ""):void {
instance.setTarget(value, dispatchEvent, cause);
}
/**
* Selects the target
* */
public static function setTargets(value:Object, dispatchEvent:Boolean = true, cause:String = ""):void {
instance.setTargets(value, dispatchEvent, cause);
}
/**
* Selects the document
* */
public static function setDocuments(value:Object, dispatchEvent:Boolean = false, cause:String = ""):void {
instance.setDocuments(value, dispatchEvent, cause);
}
/**
* Deselects the documents
* */
public static function desetDocuments(dispatchEvent:Boolean = true, cause:String = ""):void {
instance.setDocuments(null, dispatchEvent, cause);
}
/**
* Gets the display list of the current document
* */
public static function getComponentDisplayList():ComponentDescription {
return IDocumentContainer(instance.selectedDocument).componentDescription;
}
//----------------------------------
// Clipboard
//----------------------------------
/**
* Cut item
* */
public function cutItem(item:Object):void {
//Clipboard.generalClipboard.setData(ClipboardFormats.HTML_FORMAT, );
cutData = item;
copiedData = null;
}
/**
* Copy item
* */
public function copyItem(item:Object, format:String = null, handler:Function = null):void {
//Clipboard.generalClipboard.setData(ClipboardFormats.HTML_FORMAT, );
cutData = null;
copiedData = item;
var clipboard:Clipboard = Clipboard.generalClipboard;
var serializable:Boolean = true;
format = format ? format : "Object";
handler = handler!=null ? handler : setClipboardDataHandler;
if (true) {
clipboard.clear();
}
try {
if (item is String) {
clipboard.setDataHandler(format, handler, serializable);
}
else {
clipboard.setDataHandler(format, handler, serializable);
}
/*
if (action.successEffect) {
playEffect(action.successEffect);
}
if (action.hasEventListener(CopyToClipboard.SUCCESS)) {
dispatchActionEvent(new Event(CopyToClipboard.SUCCESS));
}*/
}
catch (error:ErrorEvent) {
/*
if (action.errorEffect) {
playEffect(action.errorEffect);
}
if (action.hasEventListener(CopyToClipboard.ERROR)) {
dispatchActionEvent(new Event(CopyToClipboard.ERROR));
}*/
}
}
/**
* Set clipboard data handler
* */
public function setClipboardDataHandler():* {
/*Format Return Type
ClipboardFormats.TEXT_FORMAT String
ClipboardFormats.HTML_FORMAT String
ClipboardFormats.URL_FORMAT String (AIR only)
ClipboardFormats.RICH_TEXT_FORMAT ByteArray
ClipboardFormats.BITMAP_FORMAT BitmapData (AIR only)
ClipboardFormats.FILE_LIST_FORMAT Array of File (AIR only)
ClipboardFormats.FILE_PROMISE_LIST_FORMAT Array of File (AIR only)
Custom format name Non-void*/
if (copiedData) {
return copiedData;
}
else if (cutData) {
return cutData;
}
//Clipboard.generalClipboard.setData(ClipboardFormats.HTML_FORMAT, );
}
/**
* Copy item
* */
public function pasteItem(destination:Object):void {
//Clipboard.generalClipboard.setData(ClipboardFormats.HTML_FORMAT, );
}
/**
* Set attributes on a component object
* */
public static function setAttributesOnComponent(elementInstance:Object, node:XML, dispatchEvents:Boolean = false):void {
var attributeName:String;
var elementName:String = node.localName();
//var domain:ApplicationDomain = ApplicationDomain.currentDomain;
//var componentDefinition:ComponentDefinition = Radiate.getComponentType(elementName);
//var className:String =componentDefinition ? componentDefinition.className :null;
//var classType:Class = componentDefinition ? componentDefinition.classType as Class :null;
//var elementInstance:Object = componentDescription.instance;
for each (var attribute:XML in node.attributes()) {
attributeName = attribute.name().toString();
//Radiate.log.info(" found attribute: " + attributeName);
// TODO we should check if an attribute is an property, style or event using the component definition
// We can do it this way now since we are only working with styles and properties
// check if property
if (attributeName in elementInstance) {
//Radiate.log.info(" setting property: " + attributeName);
setProperty(elementInstance, attributeName, attribute.toString(), null, false, dispatchEvents);
}
// could be style or event
else {
if (elementInstance is IStyleClient) {
//Radiate.log.info(" setting style: " + attributeName);
setStyle(elementInstance, attributeName, attribute.toString(), null, false, dispatchEvents);
}
}
}
}
/**
* Returns true if the property was changed. Use setProperties for
* setting multiple properties.<br/><br/>
*
* Usage:<br/>
* <pre>Radiate.setProperty(myButton, "x", 40);</pre>
* <pre>Radiate.setProperty([myButton,myButton2], "x", 40);</pre>
* */
public static function clearStyle(target:Object, style:String, description:String = null):Boolean {
return setStyle(target, style, undefined, description, true);
}
/**
* Returns true if the property was changed. Use setProperties for
* setting multiple properties.<br/><br/>
*
* Usage:<br/>
* <pre>Radiate.setProperty(myButton, "x", 40);</pre>
* <pre>Radiate.setProperty([myButton,myButton2], "x", 40);</pre>
* */
public static function setStyle(target:Object, style:String, value:*, description:String = null, keepUndefinedValues:Boolean = false, dispatchEvents:Boolean = true):Boolean {
var targets:Array = ArrayUtil.toArray(target);
var styleChanges:Array;
var historyEvents:Array;
styleChanges = createPropertyChange(targets, null, style, value, description);
if (!keepUndefinedValues) {
styleChanges = stripUnchangedValues(styleChanges);
}
if (changesAvailable(styleChanges)) {
applyChanges(targets, styleChanges, null, style);
//LayoutManager.getInstance().validateNow(); // applyChanges calls this
historyEvents = createHistoryEvents(targets, styleChanges, null, style, value);
updateComponentStyles(targets, styleChanges);
addHistoryEvents(historyEvents, description);
if (dispatchEvents) {
instance.dispatchPropertyChangeEvent(targets, styleChanges, ArrayUtil.toArray(style));
}
return true;
}
return false;
}
/**
* Returns true if the property was changed. Use setProperties for
* setting multiple properties.<br/><br/>
*
* Usage:<br/>
* <pre>Radiate.setProperty(myButton, "x", 40);</pre>
* <pre>Radiate.setProperty([myButton,myButton2], "x", 40);</pre>
* */
public static function setProperty(target:Object, property:String, value:*, description:String = null, keepUndefinedValues:Boolean = false, dispatchEvents:Boolean = true):Boolean {
var targets:Array = ArrayUtil.toArray(target);
var propertyChanges:Array;
var historyEvents:Array;
propertyChanges = createPropertyChange(targets, property, null, value, description);
if (!keepUndefinedValues) {
propertyChanges = stripUnchangedValues(propertyChanges);
}
if (changesAvailable(propertyChanges)) {
applyChanges(targets, propertyChanges, property, null);
//LayoutManager.getInstance().validateNow(); // applyChanges calls this
//addHistoryItem(propertyChanges, description);
historyEvents = createHistoryEvents(targets, propertyChanges, property, null, value);
addHistoryEvents(historyEvents, description);
updateComponentProperties(targets, propertyChanges);
if (dispatchEvents) {
instance.dispatchPropertyChangeEvent(targets, propertyChanges, ArrayUtil.toArray(property));
}
if (dispatchEvents) {
if (targets.indexOf(instance.selectedDocument.instance)!=-1 && ArrayUtils.containsAny(notableApplicationProperties, [property])) {
instance.dispatchDocumentSizeChangeEvent(targets);
}
}
return true;
}
return false;
}
/**
* Properties on the application to listen for for document size change event
* */
public static var notableApplicationProperties:Array = ["width","height","scaleX","scaleY"];
/**
* Returns true if the property(s) were changed.<br/><br/>
*
* Usage:<br/>
* <pre>setProperties([myButton,myButton2], ["x","y"], {x:40,y:50});</pre>
* <pre>setProperties(myButton, "x", 40);</pre>
* <pre>setProperties(button, ["x", "left"], {x:50,left:undefined});</pre>
*
* @see setStyle()
* @see setStyles()
* @see setProperty()
* */
public static function setProperties(target:Object, properties:Array, value:*, description:String = null, keepUndefinedValues:Boolean = false):Boolean {
var propertyChanges:Array;
var historyEvents:Array;
var targets:Array;
targets = ArrayUtil.toArray(target);
properties = ArrayUtil.toArray(properties);
propertyChanges = createPropertyChanges(targets, properties, null, value, description, false);
if (!keepUndefinedValues) {
propertyChanges = stripUnchangedValues(propertyChanges);
}
if (changesAvailable(propertyChanges)) {
applyChanges(targets, propertyChanges, properties, null);
//LayoutManager.getInstance().validateNow();
//addHistoryItem(propertyChanges);
historyEvents = createHistoryEvents(targets, propertyChanges, properties, null, value);
addHistoryEvents(historyEvents, description);
updateComponentProperties(targets, propertyChanges);
instance.dispatchPropertyChangeEvent(targets, propertyChanges, properties);
if (targets.indexOf(instance.selectedDocument)!=-1 && ArrayUtils.containsAny(notableApplicationProperties, properties)) {
instance.dispatchDocumentSizeChangeEvent(targets);
}
return true;
}
return false;
}
/**
* Returns true if the property(s) were changed.<br/><br/>
*
* Usage:<br/>
* <pre>setProperties([myButton,myButton2], ["x","y"], {x:40,y:50});</pre>
* <pre>setProperties(myButton, "x", 40);</pre>
* <pre>setProperties(button, ["x", "left"], {x:50,left:undefined});</pre>
*
* @see setStyle()
* @see setProperty()
* @see setProperties()
* */
public static function setStyles(target:Object, styles:Array, value:*, description:String = null, keepUndefinedValues:Boolean = false):Boolean {
var stylesChanges:Array;
var historyEvents:Array;
var targets:Array;
targets = ArrayUtil.toArray(target);
styles = ArrayUtil.toArray(styles);
stylesChanges = createPropertyChanges(targets, styles, null, value, description, false);
if (!keepUndefinedValues) {
stylesChanges = stripUnchangedValues(stylesChanges);
}
if (changesAvailable(stylesChanges)) {
applyChanges(targets, stylesChanges, null, styles);
//LayoutManager.getInstance().validateNow();
historyEvents = createHistoryEvents(targets, stylesChanges, null, styles, value);
addHistoryEvents(historyEvents, description);
updateComponentStyles(targets, stylesChanges);
instance.dispatchPropertyChangeEvent(targets, stylesChanges, styles);
return true;
}
return false;
}
/**
* Updates the properties on a component description
* */
public static function updateComponentProperties(targets:Array, propertyChanges:Array):void {
var descriptor:ComponentDescription;
var targetLength:int = targets.length;
var changesLength:int = propertyChanges.length;
var propertyChange:Object;
var target:Object;
for (var i:int;i<targetLength;i++) {
target = targets[i];
descriptor = instance.selectedDocument.descriptionsDictionary[target];
for (var j:int=0;j<changesLength;j++) {
propertyChange = propertyChanges[j];
if (descriptor) {
descriptor.properties = ObjectUtils.merge(propertyChange.end, descriptor.properties);
}
}
}
}
/**
* Updates the styles on a component description
* */
public static function updateComponentStyles(targets:Array, propertyChanges:Array):void {
var descriptor:ComponentDescription;
var targetLength:int = targets.length;
var changesLength:int = propertyChanges.length;
var propertyChange:Object;
var target:Object;
for (var i:int;i<targetLength;i++) {
target = targets[i];
descriptor = instance.selectedDocument.descriptionsDictionary[target];
for (var j:int=0;j<changesLength;j++) {
propertyChange = propertyChanges[j];
if (descriptor) {
descriptor.styles = ObjectUtils.merge(propertyChange.end, descriptor.styles);
}
}
// remove nulls and undefined values
}
}
/**
* Gets the value translated into a type.
* */
public static function getTypedValue(value:*, valueType:*):* {
return TypeUtils.getTypedValue(value, valueType);
}
/**
* Move a component in the display list and sets any properties
* such as positioning<br/><br/>
*
* Usage:<br/>
* <pre>Radiate.moveElement(new Button(), parentComponent, [], null);</pre>
*
* Usage:<br/>
* <pre>Radiate.moveElement(radiate.target, null, ["x"], 15);</pre>
* */
public static function moveElement(items:*,
destination:Object,
properties:Array,
styles:Array,
values:Object,
description:String = RadiateEvent.MOVE_ITEM,
position:String = AddItems.LAST,
relativeTo:Object = null,
index:int = -1,
propertyName:String = null,
isArray:Boolean = false,
isStyle:Boolean = false,
vectorClass:Class = null,
keepUndefinedValues:Boolean = true):String {
var visualElement:IVisualElement;
var moveItems:AddItems;
var childIndex:int;
var propertyChangeChange:PropertyChanges;
var changes:Array;
var historyEvents:Array;
var isSameOwner:Boolean;
var isSameParent:Boolean;
var removeBeforeAdding:Boolean;
var currentIndex:int;
var movingIndexWithinParent:Boolean;
items = ArrayUtil.toArray(items);
var item:Object = items ? items[0] : null;
var itemOwner:Object = item ? item.owner : null;
visualElement = item as IVisualElement;
var visualElementParent:Object = visualElement ? visualElement.parent : null;
var visualElementOwner:IVisualElementContainer = itemOwner as IVisualElementContainer;
var applicationGroup:GroupBase = destination is Application ? Application(destination).contentGroup : null;
isSameParent = visualElementParent && (visualElementParent==destination || visualElementParent==applicationGroup);
isSameOwner = visualElementOwner && visualElementOwner==destination;
// set default description
if (!description) {
description = ADD_ITEM_DESCRIPTION;
}
// if it's a basic layout then don't try to add it
// NO DO ADD IT bc we may need to swap indexes
if (destination is IVisualElementContainer) {
//destinationGroup = destination as GroupBase;
if (destination.layout is BasicLayout) {
// does not support multiple items?
// check if group parent and destination are the same
if (item && itemOwner==destination) {
//trace("can't add to the same owner in a basic layout");
isSameOwner = true;
//return SAME_OWNER;
}
// check if group parent and destination are the same
// NOTE: if the item is an element on application this will fail
if (item && visualElementParent && (visualElementParent==destination || visualElementParent==applicationGroup)) {
//trace("can't add to the same parent in a basic layout");
isSameParent = true;
//return SAME_PARENT;
}
}
// if element is already child of layout container and there is only one element
else if (items && destination is IVisualElementContainer
&& destination.numElements==1
&& visualElementParent
&& (visualElementParent==destination || visualElementParent==applicationGroup)) {
isSameParent = true;
isSameOwner = true;
//trace("can't add to the same parent in a basic layout");
//return SAME_PARENT;
}
}
// if destination is null then we assume we are moving
// WRONG! null should mean remove
else {
//isSameParent = true;
//isSameOwner = true;
}
// set default
if (!position) {
position = AddItems.LAST;
}
// if destination is not a basic layout Group and the index is set
// then find and override position and set the relative object
// so we can position the target in the drop location point index
if (destination is IVisualElementContainer
&& !relativeTo
&& index!=-1
&& destination.numElements>0) {
// add as first item
if (index==0) {
position = AddItems.FIRST;
}
// get relative to object
else if (index<=destination.numElements) {
visualElement = items is Array && (items as Array).length>0 ? items[0] as IVisualElement : items as IVisualElement;
// if element is already child of container account for removal of element before add
if (visualElement && visualElement.parent == destination) {
childIndex = destination.getElementIndex(visualElement);
index = childIndex < index ? index-1: index;
if (index<=0) {
position = AddItems.FIRST;
}
else {
relativeTo = destination.getElementAt(index-1);
position = AddItems.AFTER;
}
}
// add as last item
else if (index>=destination.numElements) {
// we need to remove first or we get an error in AddItems
// or we can set relativeTo item and set AFTER
if (isSameParent && destination.numElements>1) {
removeBeforeAdding = true;
relativeTo = destination.getElementAt(destination.numElements-1);
position = AddItems.AFTER;
}
else if (isSameParent) {
removeBeforeAdding = true;
position = AddItems.LAST;
}
else {
position = AddItems.LAST;
}
}
// add after first item
else if (index>0) {
relativeTo = destination.getElementAt(index-1);
position = AddItems.AFTER;
}
}
// check if moving to another index within the same parent
if (visualElementOwner && visualElement) {
currentIndex = visualElementOwner.getElementIndex(visualElement);
if (currentIndex!=index) {
movingIndexWithinParent = true;
}
}
}
// create a new AddItems instance and add it to the changes
moveItems = new AddItems();
moveItems.items = items;
moveItems.destination = destination;
moveItems.position = position;
moveItems.relativeTo = relativeTo;
moveItems.propertyName = propertyName;
moveItems.isArray = isArray;
moveItems.isStyle = isStyle;
moveItems.vectorClass = vectorClass;
// add properties that need to be modified
if (properties && properties.length>0 ||
styles && styles.length>0) {
changes = createPropertyChanges(items, properties, styles, values, description, false);
// get the property change part
propertyChangeChange = changes[0];
}
else {
changes = [];
}
// constraints use undefined values
// so if we use constraints do not strip out values
if (!keepUndefinedValues) {
changes = stripUnchangedValues(changes);
}
// attempt to add or move and set the properties
try {
// insert moving of items before it
// if it's the same owner we don't want to run add items
// but if it's a vgroup or hgroup does this count
if ((!isSameParent && !isSameOwner) || movingIndexWithinParent) {
changes.unshift(moveItems); //add before other changes
}
if (changes.length==0) {
Radiate.log.info("Move: Nothing to change or add");
return "Nothing to change or add";
}
// store changes
historyEvents = createHistoryEvents(items, changes, properties, styles, values, description, RadiateEvent.MOVE_ITEM);
// try moving
if ((!isSameParent && !isSameOwner) || movingIndexWithinParent) {
// this is to prevent error in AddItem when adding to the last position
// and we get an index is out of range.
//
// for example, if an element is at index 0 and there are 3 elements
// then addItem will get the last index.
// but since the parent is the same the addElement call removes
// the element. the max index is reduced by one and previously
// determined last index is now out of range.
// AddItems was not meant to add an element that has already been added
// so we remove it before hand so addItems can add it again.
if (removeBeforeAdding) {
visualElementOwner.removeElement(visualElement);
}
moveItems.apply(moveItems.destination as UIComponent);
if (moveItems.destination is SkinnableContainer && !SkinnableContainer(moveItems.destination).deferredContentCreated) {
//Radiate.log.error("Not added because deferred content not created.");
var factory:DeferredInstanceFromFunction = new DeferredInstanceFromFunction(deferredInstanceFromFunction);
SkinnableContainer(moveItems.destination).mxmlContentFactory = factory;
SkinnableContainer(moveItems.destination).createDeferredContent();
SkinnableContainer(moveItems.destination).removeAllElements();
moveItems.apply(moveItems.destination as UIComponent);
}
LayoutManager.getInstance().validateNow();
}
// try setting properties
if (changesAvailable([propertyChangeChange])) {
applyChanges(items, [propertyChangeChange], properties, styles);
LayoutManager.getInstance().validateNow();
}
// add to history
addHistoryEvents(historyEvents);
// check for changes before dispatching
if (changes.indexOf(moveItems)!=-1) {
instance.dispatchMoveEvent(items, changes, properties);
}
setTargets(items, true);
if (properties) {
instance.dispatchPropertyChangeEvent(items, changes, properties);
}
return MOVED; // we assume moved if it got this far - needs more checking
}
catch (error:Error) {
// this is clunky - needs to be upgraded
Radiate.log.error("Move error: " + error.message);
removeHistoryEvent(changes);
removeHistoryItem(changes);
return String(error.message);
}
return ADD_ERROR;
}
/**
* Adds a component to the display list.
* It should not have a parent or owner! If it does
* it will return an error message
* Returns true if the component was added
*
* Usage:
* Radiate.addElement(new Button(), event.targetCandidate);
* */
public static function addElement(items:*,
destination:Object,
properties:Array = null,
styles:Array = null,
values:Object = null,
description:String = RadiateEvent.ADD_ITEM,
position:String = AddItems.LAST,
relativeTo:Object = null,
index:int = -1,
propertyName:String = null,
isArray:Boolean = false,
isStyle:Boolean = false,
vectorClass:Class = null,
keepUndefinedValues:Boolean = true):String {
var results:String = moveElement(items, destination, properties, styles, values,
description, position, relativeTo, index, propertyName,
isArray, isStyle, vectorClass, keepUndefinedValues);
var component:Object = ArrayUtil.toArray(items)[0];
// if text based or combo box we need to prevent
// interaction with cursor
if (component is TextBase || component is SkinnableTextBase) {
component.mouseChildren = false;
if ("textDisplay" in component && component.textDisplay) {
component.textDisplay.enabled = false;
}
}
if (component is ComboBox) {
if ("textInput" in component && component.textInput.textDisplay) {
component.textInput.textDisplay.enabled = false;
}
}
// we can't add elements if skinnablecontainer._deferredContentCreated is false
if (component is BorderContainer) {
/*var factory:DeferredInstanceFromFunction;
factory = new DeferredInstanceFromFunction(deferredInstanceFromFunction);
BorderContainer(component).mxmlContentFactory = factory;
BorderContainer(component).createDeferredContent();
BorderContainer(component).removeAllElements();*/
// we could probably also do this:
BorderContainer(component).addElement(new Label());
BorderContainer(component).removeAllElements();
}
// we need a custom FlexSprite class to do this
// do this after drop
if ("eventListeners" in component && !(component is GroupBase)) {
component.removeAllEventListeners();
}
return results;
}
/**
* Removes an element from the display list.<br/><br/>
*
* Usage:<br/>
* <pre>Radiate.removeElement(radiate.targets);</pre>
* */
public static function removeElement(items:*, description:String = RadiateEvent.REMOVE_ITEM):String {
var visualElement:IVisualElement;
var removeItems:AddItems;
var childIndex:int;
var propertyChangeChange:PropertyChanges;
var changes:Array;
var historyEvents:Array;
var isSameOwner:Boolean;
var isSameParent:Boolean;
var removeBeforeAdding:Boolean;
var currentIndex:int;
var movingIndexWithinParent:Boolean;
items = ArrayUtil.toArray(items);
var item:Object = items ? items[0] : null;
var itemOwner:Object = item ? item.owner : null;
visualElement = item as IVisualElement;
var visualElementParent:Object = visualElement ? visualElement.parent : null;
var visualElementOwner:IVisualElementContainer = itemOwner as IVisualElementContainer;
var applicationGroup:GroupBase = destination is Application ? Application(destination).contentGroup : null;
isSameParent = visualElementParent && (visualElementParent==destination || visualElementParent==applicationGroup);
isSameOwner = visualElementOwner && visualElementOwner==destination;
// set default description
if (!description) {
description = REMOVE_ITEM_DESCRIPTION;
}
/*
// if it's a basic layout then don't try to add it
// NO DO ADD IT bc we may need to swap indexes
if (destination is IVisualElementContainer) {
//destinationGroup = destination as GroupBase;
if (destination.layout is BasicLayout) {
// does not support multiple items?
// check if group parent and destination are the same
if (item && itemOwner==destination) {
//trace("can't add to the same owner in a basic layout");
isSameOwner = true;
//return SAME_OWNER;
}
// check if group parent and destination are the same
// NOTE: if the item is an element on application this will fail
if (item && visualElementParent && (visualElementParent==destination || visualElementParent==applicationGroup)) {
//trace("can't add to the same parent in a basic layout");
isSameParent = true;
//return SAME_PARENT;
}
}
// if element is already child of layout container and there is only one element
else if (items && destination is IVisualElementContainer
&& destination.numElements==1
&& visualElementParent
&& (visualElementParent==destination || visualElementParent==applicationGroup)) {
isSameParent = true;
isSameOwner = true;
//trace("can't add to the same parent in a basic layout");
//return SAME_PARENT;
}
}
// if destination is null then we assume we are moving
// WRONG! null should mean remove
else {
//isSameParent = true;
//isSameOwner = true;
}*/
// set default
/*if (!position) {
position = AddItems.LAST;
}*/
// if destination is not a basic layout Group and the index is set
// then find and override position and set the relative object
// so we can position the target in the drop location point index
/*if (destination is IVisualElementContainer
&& !relativeTo
&& index!=-1
&& destination.numElements>0) {
// add as first item
if (index==0) {
position = AddItems.FIRST;
}
// get relative to object
else if (index<=destination.numElements) {
visualElement = items is Array && (items as Array).length>0 ? items[0] as IVisualElement : items as IVisualElement;
// if element is already child of container account for removal of element before add
if (visualElement && visualElement.parent == destination) {
childIndex = destination.getElementIndex(visualElement);
index = childIndex < index ? index-1: index;
if (index<=0) {
position = AddItems.FIRST;
}
else {
relativeTo = destination.getElementAt(index-1);
position = AddItems.AFTER;
}
}
// add as last item
else if (index>=destination.numElements) {
// we need to remove first or we get an error in AddItems
// or we can set relativeTo item and set AFTER
if (isSameParent && destination.numElements>1) {
removeBeforeAdding = true;
relativeTo = destination.getElementAt(destination.numElements-1);
position = AddItems.AFTER;
}
else if (isSameParent) {
removeBeforeAdding = true;
position = AddItems.LAST;
}
else {
position = AddItems.LAST;
}
}
// add after first item
else if (index>0) {
relativeTo = destination.getElementAt(index-1);
position = AddItems.AFTER;
}
}
// check if moving to another index within the same parent
if (visualElementOwner && visualElement) {
currentIndex = visualElementOwner.getElementIndex(visualElement);
if (currentIndex!=index) {
movingIndexWithinParent = true;
}
}
}*/
if (visualElement is Application) {
log.info("You can't remove the design view");
return REMOVE_ERROR;
}
var destination:Object = item.owner;
var index:int = destination.getElementIndex(visualElement);
var position:String;
// create a new AddItems instance and add it to the changes
//moveItems = new AddItems();
//moveItems.items = items;
//moveItems.destination = destination;
//moveItems.position = position;
//moveItems.relativeTo = relativeTo;
//moveItems.propertyName = propertyName;
//moveItems.isArray = isArray;
//moveItems.isStyle = isStyle;
//moveItems.vectorClass = vectorClass;
changes = [];
// attempt to remove
try {
removeItems = createReverseAddItems(items[0]);
changes.unshift(removeItems);
// store changes
historyEvents = createHistoryEvents(items, changes, null, null, null, description, RadiateEvent.REMOVE_ITEM);
// try moving
//removeItems.apply(destination as UIComponent);
//removeItems.apply(null);
visualElementOwner.removeElement(visualElement);
//removeItems.remove(destination as UIComponent);
LayoutManager.getInstance().validateNow();
// add to history
addHistoryEvents(historyEvents);
// check for changes before dispatching
instance.dispatchRemoveItemsEvent(items, changes, null);
// select application - could be causing errors - should select previous targets??
setTargets(instance.selectedDocument.instance, true);
return REMOVED; // we assume moved if it got this far - needs more checking
}
catch (error:Error) {
// this is clunky - needs to be upgraded
Radiate.log.error("Remove error: " + error.message);
removeHistoryEvent(changes);
removeHistoryItem(changes);
return String(error.message);
}
return REMOVE_ERROR;
}
/**
* Required for creating BorderContainers
* */
protected static function deferredInstanceFromFunction():Array {
var label:Label = new Label();
return [label];
}
/**
* Creates an instance of the component in the descriptor and sets the
* default properties. We may need to use setActualSize type of methods here or when added.
* */
public static function createComponentForAdd(iDocument:IDocument, item:ComponentDefinition, setDefaults:Boolean = true):Object {
var classFactory:ClassFactory;
var component:Object;
var componentDescription:ComponentDescription = new ComponentDescription();
// Create component to drag
classFactory = new ClassFactory(item.classType as Class);
if (setDefaults) {
classFactory.properties = item.defaultProperties;
componentDescription.properties = item.defaultProperties;
componentDescription.defaultProperties = item.defaultProperties;
}
component = classFactory.newInstance();
for (var property:String in item.defaultProperties) {
setProperty(component, property, [item.defaultProperties[property]]);
}
componentDescription.instance = component;
componentDescription.name = item.name;
iDocument.descriptionsDictionary[component] = componentDescription;
if (component is Label) {
}
// working on grid
if (component is spark.components.Grid) {
spark.components.Grid(component).itemRenderer= new ClassFactory(DefaultGridItemRenderer);
spark.components.Grid(component).dataProvider = new ArrayCollection(["item 1", "item 2", "item 3"]);
}
// working on mx grid
if (component is mx.containers.Grid) {
mx.containers.Grid(component)
var grid:mx.containers.Grid = component as mx.containers.Grid;
var gridRow:GridRow = new GridRow();
var gridItem:GridItem = new GridItem();
var gridItem2:GridItem = new GridItem();
var gridButton:Button = new Button();
gridButton.width = 100;
gridButton.height = 100;
gridButton.label = "hello";
var gridButton2:Button = new Button();
gridButton2.width = 100;
gridButton2.height = 100;
gridButton2.label = "hello2";
gridItem.addElement(gridButton);
gridItem2.addElement(gridButton2);
gridRow.addElement(gridItem);
gridRow.addElement(gridItem2);
grid.addElement(gridRow);
}
// add fill to rect
if (component is Rect) {
var fill:SolidColor = new SolidColor();
fill.color = 0xf6f6f6;
Rect(component).fill = fill;
}
// we need a custom FlexSprite class to do this
// do this after drop
/*if ("eventListeners" in component) {
component.removeAllEventListeners();
}*/
// if text based or combo box we need to prevent
// interaction with cursor
if (component is TextBase || component is SkinnableTextBase) {
component.mouseChildren = false;
if ("textDisplay" in component && component.textDisplay) {
component.textDisplay.enabled = false;
}
}
if (component is LinkButton) {
LinkButton(component).useHandCursor = false;
}
/*
if (component is IFlexDisplayObject) {
//component.width = IFlexDisplayObject(component).measuredWidth;
//component.height = IFlexDisplayObject(component).measuredHeight;
}*/
if (component is GroupBase) {
DisplayObjectUtils.addGroupMouseSupport(component as GroupBase);
}
// we can't add elements if skinnablecontainer._deferredContentCreated is false
/*if (component is BorderContainer) {
BorderContainer(component).creationPolicy = ContainerCreationPolicy.ALL;
BorderContainer(component).initialize();
BorderContainer(component).createDeferredContent();
BorderContainer(component).initialize();
}*/
return component;
}
/**
* Exports an XML string for a project
* */
public function exportProject(project:IProject, format:String = "String"):String {
var projectString:String = project.toString();
return projectString;
}
/**
* Creates a project
* */
public function createProject(name:String = null):IProject {
var newProject:IProject = new Project();
newProject.name = name ? name : "Project " + Project.nameIndex;
newProject.host = getWPURL();
return newProject;
}
// Error #1047: Parameter initializer unknown or is not a compile-time constant.
// Occassionally a 1047 error shows up.
// This is from using a static var in the parameter as the default
// and is an error in FB - run clean and it will go away
/**
* Adds a project to the projects array. We should remove open project behavior.
* */
public function addProject(newProject:IProject, open:Boolean = false, locations:String = null, dispatchEvents:Boolean = true):IProject {
var found:Boolean = doesProjectExist(newProject.uid);
if (locations==null) locations = DocumentData.REMOTE_LOCATION;
if (!found) {
projects.push(newProject);
}
else {
return newProject;
}
// if no projects exist select the first one
/*if (!selectedProject) {
setProject(newProject, dispatchEvents);
}*/
if (dispatchEvents) {
dispatchProjectAddedEvent(newProject);
}
if (open) {
openProject(newProject, locations, dispatchEvents);// TODO project opened or changed
}
return newProject;
}
/**
* Opens the project. Right now this does not do much.
* */
public function openProject(iProject:IProject, locations:String = null, dispatchEvents:Boolean = true):Object {
var isAlreadyOpen:Boolean;
if (locations==null) locations = DocumentData.REMOTE_LOCATION;
isAlreadyOpen = isProjectOpen(iProject);
/*
if (dispatchEvents) {
dispatchProjectChangeEvent(iProject);
}*/
if (iProject as EventDispatcher) {
EventDispatcher(iProject).addEventListener(Project.PROJECT_OPENED, projectOpenResultHandler, false, 0, true);
}
// TODO open project documents
iProject.open(locations);
if (isAlreadyOpen) {
//setProject(iProject, dispatchEvents);
return true;
}
else {
iProject.isOpen = true;
}
// show project
//setProject(iProject, dispatchEvents);
return true;
}
/**
* Project opened result handler
* */
public function projectOpenResultHandler(event:Event):void {
var iProject:IProject = event.currentTarget as IProject;
// add assets
addAssets(iProject.assets);
if (iProject is EventDispatcher) {
EventDispatcher(iProject).removeEventListener(Project.PROJECT_OPENED, projectOpenResultHandler);
}
dispatchProjectOpenedEvent(iProject);
}
/**
* Opens the project. Right now this does not do much.
* */
public function openProjectFromMetaData(iProject:IProject, locations:String = null, dispatchEvents:Boolean = true):Object {
var isAlreadyOpen:Boolean;
if (locations==null) locations = DocumentData.REMOTE_LOCATION;
isAlreadyOpen = isProjectOpen(iProject);
/*
if (dispatchEvents) {
dispatchProjectChangeEvent(iProject);
}*/
if (iProject as EventDispatcher) {
EventDispatcher(iProject).addEventListener(Project.PROJECT_OPENED, projectOpenResultHandler, false, 0, true);
}
// TODO open project documents
iProject.openFromMetaData(locations);
if (isAlreadyOpen) {
//setProject(iProject, dispatchEvents);
return true;
}
else {
iProject.isOpen = true;
}
// show project
//setProject(iProject, dispatchEvents);
return true;
}
/**
* Checks if project is open.
* */
public function isProjectOpen(iProject:IProject):Boolean {
return iProject.isOpen;
}
/**
* Closes project if open.
* */
public function closeProject(iProject:IProject, dispatchEvents:Boolean = true):Boolean {
var length:int = iProject.documents.length;
log.info("Close project");
if (dispatchEvents) {
dispatchProjectClosingEvent(iProject);
}
for (var i:int=length;i--;) {
closeDocument(IDocument(iProject.documents[i]));
//removeDocument(IDocument(iProject.documents[i]));
}
iProject.close();
if (dispatchEvents) {
dispatchProjectClosedEvent(iProject);
}
return false;
}
/**
* Removes a project from the projects array. TODO Remove from server
* */
public function removeProject(iProject:IProject, locations:String = null, dispatchEvents:Boolean = true):Boolean {
// 1047: Parameter initializer unknown or is not a compile-time constant.
// Occassionally a 1047 error shows up.
// This is from using a static var in the parameter as the default
// and is an error in FB - run clean and it will go away
if (locations==null) locations = DocumentData.REMOTE_LOCATION;
var projectIndex:int = projects.indexOf(iProject);
var removedProject:IProject;
var remote:Boolean = getIsRemoteLocation(locations);
if (projectIndex!=-1) {
var removedProjects:Array = projects.splice(projectIndex, 1);
if (removedProjects[0]==iProject) {
log.info("Project removed successfully");
var length:int = iProject.documents.length;
for (var i:int=length;i--;) {
removeDocument(IDocument(iProject.documents[i]), locations, dispatchEvents);
}
}
}
if (remote && iProject && iProject.id) {
// we need to create service
if (deleteProjectService==null) {
var service:WPService = new WPService();
service = new WPService();
service.host = getWPURL();
service.addEventListener(WPService.RESULT, deleteProjectResultsHandler, false, 0, true);
service.addEventListener(WPService.FAULT, deleteProjectFaultHandler, false, 0, true);
deleteProjectService = service;
}
deleteProjectInProgress = true;
deleteProjectService.id = iProject.id;
deleteProjectService.deletePost();
}
else if (remote) {
if (dispatchEvents) {
dispatchProjectRemovedEvent(iProject);
dispatchProjectDeletedEvent(true, iProject);
}
return false;
}
// get first or last open document and select the project it's part of
if (!selectedProject) {
// to do
}
if (!remote && dispatchEvents) {
dispatchProjectRemovedEvent(iProject);
}
return true;
}
/**
* Create project from project data
* */
public function createProjectFromData(projectData:IProjectData):IProject {
var newProject:IProject = createProject();
newProject.unmarshall(projectData);
return newProject;
}
/**
* Create project from project XML data
* */
public function createProjectFromXML(projectData:XML):IProject {
var newProject:IProject = createProject();
newProject.unmarshall(projectData);
return newProject;
}
/**
* Create document from document data
* */
public function createDocumentDataFromMetaData(documentData:IDocumentMetaData, overwrite:Boolean = false):IDocumentData {
var newDocument:IDocumentData = new DocumentData();
newDocument.unmarshall(documentData);
return newDocument;
}
/**
* Create document from document data
* */
public function createDocumentFromData(documentData:IDocumentData, overwrite:Boolean = false):IDocument {
var newDocument:IDocument = createDocument(documentData.name, documentData.type);
newDocument.unmarshall(documentData);
return newDocument;
}
/**
* Create document from document meta data
* */
public function createDocumentFromMetaData(documentMetaData:IDocumentMetaData, overwrite:Boolean = false):IDocument {
var documentData:IDocumentData = createDocumentDataFromMetaData(documentMetaData, overwrite);
var iDocument:IDocument = createDocumentFromData(documentData, overwrite);
return iDocument;
}
/**
* Open saved documents if they exist or open a blank document
* */
public function openInitialProjects():void {
/*
if (savedData && (savedData.projects.length>0 || savedData.documents.length>0)) {
restoreSavedData(savedData);
}
else {
createBlankDemoDocument();
}
*/
if (!isUserLoggedIn) {
if (savedData && (savedData.projects.length>0 || savedData.documents.length>0)) {
openLocalProjects(savedData);
}
else {
createBlankDemoDocument();
}
}
else {
getProjects();
getAttachments();
}
}
/**
* Creates a blank project
* */
public function createBlankDemoDocument(projectName:String = null, documentName:String = null, type:Class = null, open:Boolean = true, dispatchEvents:Boolean = false, select:Boolean = true):IDocument {
var newProject:IProject;
var newDocument:IDocument;
newProject = createProject(projectName); // create project
addProject(newProject); // add to projects array - shows up in application
newDocument = createDocument(documentName); // create document
addDocument(newDocument, newProject); // add to project and documents array - shows up in application
openProject(newProject); // should open documents - maybe we should do all previous steps in this function???
openDocument(newDocument, DocumentData.INTERNAL_LOCATION, true, true); // add to application and parse source code if any
setProject(newProject); // selects project
return newDocument;
}
/**
* Creates a document
* */
public function createDocument(name:String = null, Type:Object = null, project:IProject = null):IDocument {
var hasDefinition:Boolean;
var DocumentType:Object;
var iDocument:IDocument;
if (Type is String && Type!="null" && Type!="") {
hasDefinition = ApplicationDomain.currentDomain.hasDefinition(String(Type));
DocumentType = Document;
if (hasDefinition) {
DocumentType = ApplicationDomain.currentDomain.getDefinition(String(Type));
iDocument = new DocumentType();
}
else {
throw new Error("Type specified, '" + String(Type) + "' to create document is not found");
}
}
else if (Type is Class) {
iDocument = new Type();
}
else {
iDocument = new Document();
}
iDocument.name = name ? name : "Document";
iDocument.host = getWPURL();
//document.documentData = document.marshall();
return iDocument;
}
/**
* Adds a document to a project if set and adds it to the documents array
* */
public function addDocument(iDocument:IDocument, project:IProject = null, overwrite:Boolean = false, dispatchEvents:Boolean = true):IDocument {
var documentAlreadyExists:Boolean;
var length:int;
var documentAdded:Boolean;
documentAlreadyExists = doesDocumentExist(iDocument.uid);
// if not added already add to documents array
if (!documentAlreadyExists) {
documents.push(iDocument);
documentAdded = true;
}
if (documentAlreadyExists && overwrite) {
// check dates
// remove from documents
// remove from projects
// add to documents
// add to projects
var documentToRemove:IDocument = getDocumentByUID(iDocument.uid);
removeDocument(documentToRemove, DocumentData.LOCAL_LOCATION);// this is deleting the document
// should there be a remove (internally) and delete method?
//throw new Error("Document overwrite is not implemented yet");
documentAdded = true;
}
if (project) {
project.addDocument(iDocument, overwrite);
}
if (documentAdded && dispatchEvents) {
dispatchDocumentAddedEvent(iDocument);
}
return iDocument;
}
/**
* Reverts a document to its open state
* */
public function revertDocument(iDocument:IDocument, dispatchEvents:Boolean = true):Boolean {
// TODO
return false;
}
/**
* Removes a document from the documents array
* */
public function removeDocument(iDocument:IDocument, locations:String = null, dispatchEvents:Boolean = true):Boolean {
if (locations==null) locations = DocumentData.REMOTE_LOCATION;
var parentProject:IProject = iDocument.project;
var documentsIndex:int = parentProject.documents.indexOf(iDocument);
var removedDocument:IDocument;
var remote:Boolean = getIsRemoteLocation(locations);
if (documentsIndex!=-1) {
// add remove document to project
var removedDocuments:Array = parentProject.documents.splice(documentsIndex, 1);
if (removedDocuments[0]==iDocument) {
//log.info("Document removed successfully");
}
}
closeDocument(iDocument);
// check if document is open in tab navigator
/*if (isDocumentOpen(iDocument)) {
var closed:Boolean = closeDocument(iDocument);
log.info("Closed " + iDocument.name);
}*/
if (remote && iDocument && iDocument.id) {
// we need to create service
if (deleteDocumentService==null) {
deleteDocumentService = new WPService();
deleteDocumentService.addEventListener(WPService.RESULT, deleteDocumentResultsHandler, false, 0, true);
deleteDocumentService.addEventListener(WPService.FAULT, deleteDocumentFaultHandler, false, 0, true);
}
deleteDocumentService.host = getWPURL();
deleteDocumentInProgress = true;
deleteDocumentService.id = iDocument.id
deleteDocumentService.deletePost();
}
else if (remote) { // document not saved yet
if (dispatchEvents) {
dispatchDocumentRemovedEvent(iDocument);
return true;
}
}
else {
if (dispatchEvents) {
dispatchDocumentRemovedEvent(iDocument);
}
}
// get first or last open document and select the project it's part of
if (!this.selectedDocument) {
// to do
}
return true;
}
/**
* Opens the document from it's document data. If the document is already open it selects it.
*
* It returns the document container.
* */
public function openDocumentByData(data:IDocumentData, showDocument:Boolean = true, dispatchEvents:Boolean = true):Object {
var iDocument:IDocument = getDocumentByUID(data.uid);
if (!iDocument) {
iDocument = createDocumentFromData(data);
}
var result:Boolean = openDocument(iDocument, DocumentData.INTERNAL_LOCATION, showDocument, dispatchEvents);
return result;
}
/**
* Print
* */
public function print(data:Object, scaleType:String = FlexPrintJobScaleType.MATCH_WIDTH, printAsBitmap:Boolean = false):Object {
var flexPrintJob:FlexPrintJob = new FlexPrintJob();
var printableObject:IUIComponent;
var scaleX:Number;
var scaleY:Number;
if (data is IDocument) {
printableObject = IUIComponent(IDocument(data).instance)
}
else if (data is IUIComponent) {
printableObject = IUIComponent(data);
}
else {
Radiate.log.error("Printing failed: Object is not of accepted type.");
return false;
}
if (data && "scaleX" in data) {
scaleX = data.scaleX;
scaleY = data.scaleY;
}
flexPrintJob.printAsBitmap = printAsBitmap;
if (printAsBitmap && data is IBitmapDrawable) {
var imageBitmapData:BitmapData = ImageSnapshot.captureBitmapData(IBitmapDrawable(data));
var bitmapImage:BitmapImage = new BitmapImage();
bitmapImage.source = new Bitmap(imageBitmapData);
//data = bitmapImage;
}
// show OS print dialog
// printJobStarted is false if user cancels OS print dialog
var printJobStarted:Boolean = flexPrintJob.start();
// if user cancels print job and we continue then the stage disappears!
// so we exit out (ie we don't do the try statement)
// workaround if we set the scale it reappears
// so, scaleX and scaleY are set to NaN on the object when we try to print and it fails
if (!printJobStarted) {
log.error("Print job was not started");
dispatchPrintCancelledEvent(data, flexPrintJob);
return false;
}
try {
//log.info("Print width and height: " + flexPrintJob.pageWidth + "x" + flexPrintJob.pageHeight);
flexPrintJob.addObject(printableObject, scaleType);
flexPrintJob.send();
dispatchPrintCompleteEvent(data, flexPrintJob);
}
catch(e:Error) {
// CHECK scale X and scale Y to see if they are null - see above
if (data && "scaleX" in data && data.scaleX!=scaleX) {
data.scaleX = scaleX;
data.scaleY = scaleY;
}
// Printing failed: Error #2057: The page could not be added to the print job.
Radiate.log.error("Printing failed: " + e.message);
// TODO this should be print error event
dispatchPrintCancelledEvent(data, flexPrintJob);
return false;
}
return true;
}
/**
* Import code.
*
* TODO:
* - import mxml code to new document
* - import mxml code to existing document ovewrite current document
* - import document xml (wraps mxml application)
* - import mxml to a container or group
* */
public function importMXMLDocument(project:IProject, iDocument:IDocument, container:IVisualElement, code:String, dispatchEvents:Boolean = true):Boolean {
var result:Object;
var newDocument:Boolean;
if (!iDocument) {
iDocument = createDocument();
newDocument = true;
if (project) {
addDocument(iDocument, project);
}
}
if (!newDocument) {
iDocument.parseSource(code, container);
}
else {
iDocument.source = code;
result = openDocument(iDocument, DocumentData.INTERNAL_LOCATION, true, dispatchEvents);
}
return result;
}
/**
* Opens the document. If the document is already open it selects it.
* When the document loads (it's a blank application swf) then the mxml is parsed. Check the DocumentContainer class.
*
* It returns the document container.
* */
public function openDocument(iDocument:IDocument, locations:String = null, showDocumentInTab:Boolean = true, dispatchEvents:Boolean = true):Object {
var documentContainer:DocumentContainer;
var navigatorContent:NavigatorContent;
var openingEventDispatched:Boolean;
var containerTypeInstance:Object;
var isAlreadyOpen:Boolean;
var container:Object;
var documentIndex:int;
var previewName:String;
var index:int;
// NOTE: If the document is empty or all of the components are in the upper left hand corner
// and they have no properties then my guess is that the application was never fully loaded
// or activated. this happens with multiple documents opening too quickly where some
// do not seem to activate. you see them activate when you select their tab for the first time
// so then later if it hasn't activated, when the document is exported none of the components have
// their properties or styles set possibly because Flex chose to defer applying them.
// the solution is to make sure the application is fully loaded and activated
// and also store a backup of the document MXML.
// that could mean waiting to open new documents until existing documents have
// loaded. listen for the application complete event (or create a parse and import event)
// ...haven't had time to do any of this yet
isAlreadyOpen = isDocumentOpen(iDocument);
if (dispatchEvents) {
openingEventDispatched = dispatchDocumentOpeningEvent(iDocument);
if (!openingEventDispatched) {
//return false;
}
}
if (isAlreadyOpen) {
index = getDocumentTabIndex(iDocument);
if (showDocumentInTab) {
//showDocument(iDocument, false, false); // the next call will dispatch events
showDocument(iDocument, false, dispatchEvents); // the next call will dispatch events
setDocument(iDocument, dispatchEvents);
}
return documentsContainerDictionary[iDocument];
}
else {
iDocument.open(locations);
}
// TypeError: Error #1034: Type Coercion failed: cannot convert
// com.flexcapacitor.components::DocumentContainer@114065851 to
// mx.core.INavigatorContent
navigatorContent = new NavigatorContent();
navigatorContent.percentWidth = 100;
navigatorContent.percentHeight = 100;
navigatorContent.label = iDocument.name ? iDocument.name : "Untitled";
if (iDocument.containerType==null) {
documentContainer = new DocumentContainer();
documentContainer.percentWidth = 100;
documentContainer.percentHeight = 100;
documentsContainerDictionary[iDocument] = documentContainer;
navigatorContent.addElement(documentContainer);
documentContainer.iDocument = IDocument(iDocument);
}
else {
// custom container
containerTypeInstance = new iDocument.containerType();
//containerTypeInstance.id = document.name ? document.name : "";
containerTypeInstance.percentWidth = 100;
containerTypeInstance.percentHeight = 100;
documentsContainerDictionary[iDocument] = containerTypeInstance;
navigatorContent.addElement(containerTypeInstance as IVisualElement);
containerTypeInstance.iDocument = IDocument(iDocument);
}
if (documentsTabNavigator) {
//documentIndex = !isPreview ? 0 : getDocumentIndex(document) + 1;
documentsTabNavigator.addElement(navigatorContent);
}
documentIndex = getDocumentTabIndex(iDocument);
// show document
if (showDocumentInTab) {
showDocument(iDocument, false, dispatchEvents);
setDocument(iDocument, dispatchEvents);
}
return documentsContainerDictionary[iDocument];
}
/**
* Opens a preview of the document. If the document is already open it selects it.
*
* It returns the document container.
* */
public function openDocumentPreview(iDocument:IDocument, showDocument:Boolean = false, dispatchEvents:Boolean = true):Object {
var documentContainer:DocumentContainer;
var navigatorContent:NavigatorContent;
var isAlreadyOpen:Boolean;
var index:int;
var iframe:IFrame;
var containerTypeInstance:Object;
var container:Object;
var openingEventDispatched:Boolean;
var documentIndex:int;
var previewName:String;
isAlreadyOpen = isDocumentPreviewOpen(iDocument);
if (dispatchEvents) {
openingEventDispatched = dispatchDocumentOpeningEvent(iDocument, true);
if (!openingEventDispatched) {
//return false;
}
}
if (isAlreadyOpen) {
index = getDocumentPreviewIndex(iDocument);
if (showDocument) {
showDocumentAtIndex(index, false); // the next call will dispatch events
setDocument(iDocument, dispatchEvents);
}
return documentsPreviewDictionary[iDocument];
}
else {
iDocument.isPreviewOpen = true;
}
// TypeError: Error #1034: Type Coercion failed: cannot convert
// com.flexcapacitor.components::DocumentContainer@114065851 to
// mx.core.INavigatorContent
navigatorContent = new NavigatorContent();
navigatorContent.percentWidth = 100;
navigatorContent.percentHeight = 100;
navigatorContent.label = iDocument.name ? iDocument.name : "Untitled";
previewName = iDocument.name + " HTML";
navigatorContent.label = previewName;
if (iDocument.containerType) {
containerTypeInstance = new iDocument.containerType();
containerTypeInstance.id = iDocument.name ? iDocument.name : iframe.name; // should we be setting id like this?
containerTypeInstance.percentWidth = 100;
containerTypeInstance.percentHeight = 100;
navigatorContent.addElement(containerTypeInstance as IVisualElement);
documentsPreviewDictionary[iDocument] = containerTypeInstance;
}
else {
// show HTML page
iframe = new IFrame();
iframe.id = iDocument.name ? iDocument.name : iframe.name; // should we be setting id like this?
iframe.percentWidth = 100;
iframe.percentHeight = 100;
iframe.top = 20;
iframe.left = 20;
iframe.setStyle("backgroundColor", "#666666");
navigatorContent.addElement(iframe);
documentsPreviewDictionary[iDocument] = iframe;
}
// if preview add after original document location
documentIndex = getDocumentTabIndex(iDocument) + 1; // add after
documentsTabNavigator.addElementAt(navigatorContent, documentIndex);
// show document
if (showDocument) {
showDocumentAtIndex(documentIndex, dispatchEvents);
setDocument(iDocument, dispatchEvents);
}
return documentsPreviewDictionary[iDocument];
}
/**
* Checks if a document preview is open.
* @see isDocumentSelected
* */
public function isDocumentPreviewOpen(document:IDocument):Boolean {
var openTabs:Array = documentsTabNavigator.getChildren();
var tabCount:int = openTabs.length;
var tab:NavigatorContent;
var tabContent:Object;
var documentContainer:Object = documentsPreviewDictionary[document];
for (var i:int;i<tabCount;i++) {
tab = NavigatorContent(documentsTabNavigator.getChildAt(i));
tabContent = tab.numElements ? tab.getElementAt(0) : null;
if (tabContent && tabContent==documentContainer) {
return true;
}
}
return false;
}
/**
* Checks if document is open.
* @see isDocumentSelected
* */
public function isDocumentOpen(document:IDocument, isPreview:Boolean = false):Boolean {
var openTabs:Array;
var tabCount:int;
var tab:NavigatorContent;
var tabContent:Object;
var documentContainer:Object;
if (!documentsTabNavigator) {
return false;
}
openTabs = documentsTabNavigator.getChildren();
tabCount = openTabs.length;
documentContainer = isPreview ? documentsPreviewDictionary[document] : documentsContainerDictionary[document];
for (var i:int;i<tabCount;i++) {
tab = NavigatorContent(documentsTabNavigator.getChildAt(i));
tabContent = tab.numElements ? tab.getElementAt(0) : null;
if (tabContent && tabContent==documentContainer) {
return true;
}
}
return false;
}
/**
* Closes the current visible document regardless if it is a preview or not.
* @see isDocumentSelected
* */
public function closeVisibleDocument():Boolean {
var selectedDocument:IDocument = getDocumentAtIndex(documentsTabNavigator.selectedIndex);
var isPreview:Boolean = isPreviewDocumentVisible();
return closeDocument(selectedDocument, isPreview);
}
/**
* Closes document if open.
* @see isDocumentSelected
* */
public function closeDocument(iDocument:IDocument, isPreview:Boolean = false):Boolean {
var openTabs:Array = documentsTabNavigator.getChildren();
var tabCount:int = openTabs.length;
var navigatorContent:NavigatorContent;
var navigatorContentDocumentContainer:Object;
var documentContainer:Object = isPreview ? documentsPreviewDictionary[iDocument] : documentsContainerDictionary[iDocument];
// third attempt
// second attempt
if (documentContainer && documentContainer.owner) {
// ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
// at flash.display::DisplayObjectContainer/getChildIndex()
//var index:int = documentsTabNavigator.getChildIndex(documentContainer.owner as DisplayObject);
var contains:Boolean = documentsTabNavigator.contains(documentContainer.owner as DisplayObject);
if (contains) {
documentsTabNavigator.removeChild(documentContainer.owner);
// close previews when the main document is closed
if (!isPreview) {
documentContainer = documentsPreviewDictionary[iDocument];
if (documentContainer) {
documentsTabNavigator.removeChild(documentContainer.owner);
}
iDocument.close();
//removeDocument(iDocument);
//var documentContainer:Object = isPreview ? documentsPreviewDictionary[iDocument] : documentsDictionary[iDocument];
delete documentsContainerDictionary[iDocument];
delete documentsPreviewDictionary[iDocument];
}
else {
delete documentsPreviewDictionary[iDocument];
}
if (isPreview) {
// TODO we must remove HTML from IFrame (inline css from previous iframes previews affects current preview)
}
documentsTabNavigator.validateNow();
}
}
return true;
// first attempt
//log.info("Closing " + iDocument.name);
for (var i:int;i<tabCount;i++) {
navigatorContent = NavigatorContent(documentsTabNavigator.getChildAt(i));
navigatorContentDocumentContainer = navigatorContent.numElements ? navigatorContent.getElementAt(0) : null;
//log.info(" Checking tab " + tab.label);
if (iDocument.name==navigatorContent.label) {
//log.info(" Name Match " + iDocument.name);
if (IDocumentContainer(navigatorContentDocumentContainer).iDocument==iDocument) {
documentsTabNavigator.removeChild(navigatorContent);
documentsTabNavigator.validateNow();
return true;
}
}
// oddly enough after we remove one child using the code below (note: see update)
// the documentContainer in the documentsDictionary is no longer
// connected with the correct document data
// if we do this one at a time and remove one per second
// then it works but not many documents at a time (see removeProject)
// so instead we are checking by name and then document reference
// in the code above this
// Update: May have spoken too soon - could be problem because document
// was used as a variable name and it scoped to document on the UIComponent class :(
if (navigatorContentDocumentContainer && navigatorContentDocumentContainer==documentContainer) {
documentsTabNavigator.removeChild(navigatorContent);
documentsTabNavigator.validateNow();
return true;
}
}
return false;
}
/**
* Checks if document is open and selected
* */
public function isDocumentSelected(document:Object, isPreview:Boolean = false):Boolean {
var openTabs:Array = documentsTabNavigator.getChildren();
var tabCount:int = openTabs.length;
var tab:NavigatorContent;
var tabContent:Object;
var documentIndex:int = -1;
var documentContainer:Object = isPreview ? documentsPreviewDictionary[document] : documentsContainerDictionary[document];
for (var i:int;i<tabCount;i++) {
tab = NavigatorContent(documentsTabNavigator.getChildAt(i));
tabContent = tab.numElements ? tab.getElementAt(0) : null;
if (tabContent && tabContent==documentContainer) {
documentIndex = i;
break;
}
}
if (documentsTabNavigator.selectedIndex==documentIndex) {
return true;
}
return false;
}
/**
* Get visible document in documents tab navigator
* */
public function getVisibleDocument():IDocument {
var selectedTab:NavigatorContent = documentsTabNavigator ? documentsTabNavigator.selectedChild as NavigatorContent : null;
var tabContent:Object = selectedTab && selectedTab.numElements ? selectedTab.getElementAt(0) : null;
if (tabContent is IDocumentContainer) {
var iDocument:IDocument = IDocumentContainer(tabContent).iDocument;
return iDocument;
}
return null;
}
/**
* Get the index of the document in documents tab navigator
* */
public function getDocumentTabIndex(document:Object, isPreview:Boolean = false):int {
var openTabs:Array = documentsTabNavigator.getChildren();
var tabCount:int = openTabs.length;
var tab:NavigatorContent;
var documentContainer:Object = isPreview ? documentsPreviewDictionary[document] : documentsContainerDictionary[document];
var tabContent:Object;
for (var i:int;i<tabCount;i++) {
tab = NavigatorContent(documentsTabNavigator.getChildAt(i));
tabContent = tab.numElements ? tab.getElementAt(0) : null;
if (tabContent && tabContent==documentContainer) {
return i;
}
}
return -1;
}
/**
* Get the index of the document preview in documents tab navigator
* */
public function getDocumentPreviewIndex(document:Object):int {
var openTabs:Array = documentsTabNavigator.getChildren();
var tabCount:int = openTabs.length;
var tab:NavigatorContent;
var documentContainer:Object = documentsPreviewDictionary[document];
var tabContent:Object;
for (var i:int;i<tabCount;i++) {
tab = NavigatorContent(documentsTabNavigator.getChildAt(i));
tabContent = tab.numElements ? tab.getElementAt(0) : null;
if (tabContent && tabContent==documentContainer) {
return i;
}
}
return -1;
}
/**
* Get the document for the given application
* */
public function getDocumentForApplication(application:Application):IDocument {
var document:IDocument;
for each (document in documentsContainerDictionary) {
if (document.instance === application) {
return document;
break;
}
}
return null;
}
/**
* Gets the document container for the document preview.
* For example, a document can be previewed as an HTML page.
* If we want to get the document that is previewing HTML then
* we need to get the container of the preview.
* */
public function getDocumentPreview(document:Object):Object {
var documentContainer:Object = documentsPreviewDictionary[document];
return documentContainer;
}
/**
* Returns if the visible document is a preview
* */
public function isPreviewDocumentVisible():Boolean {
var tabContainer:NavigatorContent = documentsTabNavigator.selectedChild as NavigatorContent;
var tabContent:Object = tabContainer && tabContainer.numElements ? tabContainer.getElementAt(0) : null;
var isPreview:Boolean;
isPreview = DictionaryUtils.containsValue(documentsPreviewDictionary, tabContent);
//if (!isDocument) {
// isDocument = DictionaryUtils.containsValue(documentsPreviewDictionary, tabContainer);
//}
return isPreview;
}
/**
* Selects the document in the tab navigator
* */
public function showDocument(iDocumentData:IDocumentData, isPreview:Boolean = false, dispatchEvent:Boolean = true):Boolean {
var documentIndex:int = getDocumentTabIndex(iDocumentData, isPreview);
var result:Boolean;
if (documentIndex!=-1) {
result = showDocumentAtIndex(documentIndex, dispatchEvent);
}
return result;
}
/**
* Selects the document at the specifed index
* */
public function showDocumentAtIndex(index:int, dispatchEvent:Boolean = true):Boolean {
var openTabs:Array = documentsTabNavigator.getChildren();
var tabCount:int = openTabs.length;
var tab:NavigatorContent;
var tabContent:Object;
var document:IDocument;
documentsTabNavigator.selectedIndex = index;
tab = NavigatorContent(documentsTabNavigator.selectedChild);
tabContent = tab && tab.numElements ? tab.getElementAt(0) : null;
if (tabContent && tabContent is DocumentContainer && dispatchEvent) {
document = getDocumentAtIndex(index);
dispatchDocumentChangeEvent(DocumentContainer(tabContent).iDocument);
}
return documentsTabNavigator.selectedIndex == index;
}
/**
* Get the document at the index in the tab navigator
* */
public function getDocumentAtIndex(index:int):IDocument {
var openTabs:Array = documentsTabNavigator.getChildren();
var tabCount:int = openTabs.length;
var tab:NavigatorContent;
var tabContent:Object;
var document:IDocument;
if (index<0) {
return null;
}
tab = index < openTabs.length ? openTabs[index] : null;
tabContent = tab.numElements ? tab.getElementAt(0) : null;
for (var key:* in documentsContainerDictionary) {
if (documentsContainerDictionary[key] === tabContent) {
return key;
}
}
for (key in documentsPreviewDictionary) {
if (documentsPreviewDictionary[key] === tabContent) {
return key;
}
}
return null;
}
/**
* Get document by UID
* */
public function getDocumentByUID(id:String):IDocument {
var length:int = documents.length;
var iDocument:IDocument;
for (var i:int;i<length;i++) {
iDocument = IDocument(documents[i]);
if (id==iDocument.uid) {
return iDocument;
}
}
return null;
}
/**
* Check if document exists in documents array
* */
public function doesDocumentExist(id:String):Boolean {
var length:int = documents.length;
var iDocument:IDocument;
for (var i:int;i<length;i++) {
iDocument = IDocument(documents[i]);
if (id==iDocument.uid) {
return true;
}
}
return false;
}
/**
* Check if project exists in projects array. Pass in the UID not ID.
* */
public function doesProjectExist(uid:String):Boolean {
var length:int = projects.length;
var iProject:IProject;
for (var i:int;i<length;i++) {
iProject = IProject(projects[i]);
if (uid==iProject.uid) {
return true;
}
}
return false;
}
/**
* Get project by UID
* */
public function getProjectByUID(id:String):IProject {
var length:int = projects.length;
var iProject:IProject;
for (var i:int;i<length;i++) {
iProject = IProject(projects[i]);
if (id==iProject.uid) {
return iProject;
}
}
return null;
}
/**
* Get first project that owns this document
* */
public function getDocumentProject(iDocument:IDocument):IProject {
var projectsList:Array = getDocumentProjects(iDocument);
var iProject:IProject;
if (projectsList.length>0) {
iProject = projectsList.shift();
}
return iProject;
}
/**
* Get a list of projects that own this document
* */
public function getDocumentProjects(iDocument:IDocument):Array {
var documentsLength:int;
var projectDocument:IDocument;
var projectLength:int = projects.length;
var iProject:IProject;
var projectDocuments:Array;
var projectsList:Array = [];
for (var A:int;A<length;A++) {
iProject = IProject(projects[A]);
projectDocuments = iProject.documents;
for (var B:int;B<documentsLength;B++) {
projectDocument = IDocument(projectDocuments[B]);
if (projectDocuments.uid==iDocument.uid) {
projectsList.push(iProject);
}
}
}
return projectsList;
}
/**
* Rename document
* */
public function renameDocument(iDocument:IDocument, name:String):void {
var tab:NavigatorContent;
// todo check if name already exists
iDocument.name = name;
tab = getNavigatorByDocument(iDocument);
if (iDocument.instance is Application) {
setProperty(iDocument.instance, "pageTitle", name);
}
if (tab) {
tab.label = iDocument.name;
}
dispatchDocumentRenameEvent(iDocument, name);
}
/**
*
* */
public function getNavigatorByDocument(iDocument:IDocument, isPreview:Boolean = false):NavigatorContent {
var openTabs:Array = documentsTabNavigator.getChildren();
var tabCount:int = openTabs.length;
var tab:NavigatorContent;
var tabContent:Object;
var documentContainer:Object = isPreview ? documentsPreviewDictionary[iDocument] : documentsContainerDictionary[iDocument];
for (var i:int;i<tabCount;i++) {
tab = NavigatorContent(documentsTabNavigator.getChildAt(i));
tabContent = tab.numElements ? tab.getElementAt(0) : null;
if (tabContent && tabContent==documentContainer) {
return tab;
}
}
return null;
}
//----------------------------------
//
// Persistant Data Management
//
//----------------------------------
/**
* Creates the saved data
* */
public static function createSavedData():Boolean {
var result:Object = SharedObjectUtils.getSharedObject(SAVED_DATA_NAME);
var so:SharedObject;
if (result is SharedObject) {
so = SharedObject(result);
if (so.data) {
if (SAVED_DATA_NAME in so.data && so.data[SAVED_DATA_NAME]!=null) {
savedData = SavedData(so.data[SAVED_DATA_NAME]);
//log.info("createSavedData:"+ObjectUtil.toString(savedData));
}
// does not contain property
else {
savedData = new SavedData();
}
}
// data is null
else {
savedData = new SavedData();
}
}
else {
log.error("Could not get saved data. " + ObjectUtil.toString(result));
}
return true;
}
/**
* Creates the settings data
* */
public static function createSettingsData():Boolean {
var result:Object = SharedObjectUtils.getSharedObject(SETTINGS_DATA_NAME);
var so:SharedObject;
if (result is SharedObject) {
so = SharedObject(result);
if (so.data) {
if (SETTINGS_DATA_NAME in so.data && so.data[SETTINGS_DATA_NAME]!=null) {
settings = Settings(so.data[SETTINGS_DATA_NAME]);
}
// does not contain settings property
else {
settings = new Settings();
}
}
// data is null
else {
settings = new Settings();
}
}
else {
log.error("Could not get saved settings data. " + ObjectUtil.toString(result));
}
return true;
}
/**
* Get saved data
* */
public function getSavedData():Boolean {
var result:Object = SharedObjectUtils.getSharedObject(SAVED_DATA_NAME);
var so:SharedObject;
var data:SavedData;
if (result is SharedObject) {
so = SharedObject(result);
if (so.data) {
if (SAVED_DATA_NAME in so.data) {
data = SavedData(so.data[SAVED_DATA_NAME]);
openLocalProjects(data);
}
}
}
else {
log.error("Could not get saved data. " + ObjectUtil.toString(result));
}
return result;
}
/**
* Create new document.
* */
public function createNewDocument(name:String = null, type:Object = null, project:IProject = null):void {
var newDocument:IDocument;
var length:int;
newDocument = createDocument(name, type);
addDocument(newDocument, selectedProject, true, true);
openDocument(newDocument, DocumentData.INTERNAL_LOCATION, true);
/*
if (project) {
project.addDocument(iDocument, overwrite);
}
if (documentAdded && dispatchEvents) {
dispatchDocumentAddedEvent(iDocument);
}
if (!selectedProject) {
project = createProject(); // create project
addProject(project); // add to projects array - shows up in application
}
else {
project = selectedProject;
}
newDocument = createDocument(name, type); // create document
addDocument(newDocument, project); // add to project and documents array - shows up in application
//openProject(newProject); // should open documents - maybe we should do all previous steps in this function???
openDocument(newDocument, true, true); // add to application and parse source code if any
setProject(project); // selects project
setDocument(newDocument);*/
}
/**
* Create new project.
* */
public function createNewProject(name:String = null, type:Object = null, project:IProject = null):void {
var newProject:IProject;
newProject = createProject(); // create project
addProject(newProject); // add to projects array - shows up in application
openProject(newProject); // should open documents - maybe we should do all previous steps in this function???
setProject(newProject); // selects project
}
/**
* Create and add saved documents of array of type IDocumentData.
* */
public function createAndAddDocumentsData(documentsData:Array, add:Boolean = true):Array {
var potentialDocuments:Array = [];
var iDocumentMetaData:IDocumentMetaData;
var iDocumentData:IDocumentData;
var iDocument:IDocument;
var length:int;
// get documents and add them to the documents array
// TRYING TO NOT create documents until they are needed
// but then we have issues when we want to save
if (documentsData && documentsData.length>0) {
length = documentsData.length;
for (var i:int;i<length;i++) {
// TypeError: Error #1034: Type Coercion failed: cannot convert com.flexcapacitor.model::DocumentMetaData
// to com.flexcapacitor.model.IDocumentData. check export and marshall options
// saved as wrong data type
iDocumentData = IDocumentData(documentsData[i]);
// document doesn't exist - add it
if (getDocumentByUID(iDocumentData.uid)==null) {
iDocument = createDocumentFromData(iDocumentData);
potentialDocuments.push(iDocument);
if (add) {
addDocument(iDocument);
}
}
else {
log.info("Document " + iDocumentData.name + " is already open.");
}
}
}
return potentialDocuments;
}
/**
* Create projects from array of type IProjectData
* */
public function createAndAddProjectsData(projectsData:Array, add:Boolean = true):Array {
var iProjectData:IProjectData;
var potentialProjects:Array = [];
var length:int;
var iProject:IProject;
// get projects and add them to the projects array
if (projectsData && projectsData.length>0) {
length = projectsData.length;
for (var i:int;i<length;i++) {
iProjectData = IProjectData(projectsData[i]);
// project doesn't exist - add it
if (getProjectByUID(iProjectData.uid)==null) {
iProject = createProjectFromData(iProjectData);
potentialProjects.push(iProject);
if (add) {
addProject(iProject);
}
}
else {
log.info("Project " + iProjectData.name + " is already open.");
}
}
}
return potentialProjects;
}
/**
* Restores projects and documents from local store
* Add all saved projects to projects array
* Add all saved documents to documents array
* Add documents to projects
* Open previously open projects
* Open previously open documents
* Select previously selected project
* Select previously selected document
* */
public function openLocalProjects(data:SavedData):void {
var projectsDataArray:Array;
var potentialProjects:Array = [];
var potentialDocuments:Array = [];
var savedDocumentsDataArray:Array;
var potentialProjectsLength:int;
var iProject:IProject;
/*
var iProjectData:IProjectData;
var iDocumentData:IDocumentData;
var iDocumentMetaData:IDocumentMetaData;
var iDocument:IDocument;
var iProjectDocument:IDocument;
var iProjectDocumentsArray:Array;
var iProjectDocumentsLength:int;
var potentialDocumentsLength:int;
var documentsDataArrayLength:int;*/
// get list of projects and list of documents
if (data) {
// get projects and add them to the projects array
projectsDataArray = data.projects;
potentialProjects = createAndAddProjectsData(data.projects);
// get documents and add them to the documents array
// TRYING TO NOT create documents until they are needed
// but then we have issues when we want to save or export
createAndAddDocumentsData(data.documents);
//savedDocumentsDataArray = data.documents; // should be potential documents?
// go through projects and add documents to them
if (potentialProjects.length>0) {
potentialProjectsLength = potentialProjects.length;
// loop through potentialProjectsLength objects
for (var i:int;i<length;i++) {
iProject = IProject(potentialProjects[i]);
iProject.importDocumentInstances(documents);
}
}
openPreviouslyOpenProjects();
openPreviouslyOpenDocuments();
showPreviouslyOpenProject();
showPreviouslyOpenDocument();
}
else {
// no saved data
log.info("No saved data to restore");
}
}
/**
* Show previously opened project
* */
public function showPreviouslyOpenProject():void {
var iProject:IProject;
// Select last selected project
if (settings.selectedProject) {
iProject = getProjectByUID(settings.selectedProject.uid);
if (iProject && iProject.isOpen) {
log.info("Opening selected project " + iProject.name);
setProject(iProject);
}
}
else {
if (selectedProject==null && projects && projects.length>0) {
setProject(projects[0]);
}
}
}
/**
* Show previously opened document
* */
public function showPreviouslyOpenDocument():void {
var openDocuments:Array = settings.openDocuments;
var iDocumentMetaData:IDocumentMetaData;
var iDocument:IDocument;
// Showing previously selected document
if (settings.selectedDocument) {
iDocument = getDocumentByUID(settings.selectedDocument.uid);
if (iDocument && iDocument.isOpen) {
log.info("Showing previously selected document " + iDocument.name);
showDocument(iDocument);
setDocument(iDocument);
}
}
}
/**
* Open previously opened documents
* */
public function openPreviouslyOpenDocuments(project:IProject = null):void {
var openDocuments:Array = settings.openDocuments;
var iDocumentMetaData:IDocumentMetaData;
var iDocument:IDocument;
// open previously opened documents
for (var i:int;i<openDocuments.length;i++) {
iDocumentMetaData = IDocumentMetaData(openDocuments[i]);
iDocument = getDocumentByUID(iDocumentMetaData.uid);
if (iDocument) {
if (project && project.documents.indexOf(iDocument)!=-1) {
log.info("Opening project document " + iDocument.name);
openDocument(iDocument, DocumentData.INTERNAL_LOCATION, false, true);
}
else if (project==null) {
log.info("Opening document " + iDocument.name);
openDocument(iDocument, DocumentData.INTERNAL_LOCATION, false, true);
}
}
}
}
/**
* Open previously opened projects
* */
public function openPreviouslyOpenProjects(locations:String = null):void {
if (locations==null) locations = DocumentData.REMOTE_LOCATION;
var openProjects:Array = settings.openProjects;
var iProject:IProject;
var iProjectData:IProjectData;
var openItemlength:int = openProjects.length;
// open previously opened projects
for (var i:int;i<openItemlength;i++) {
iProjectData = IProjectData(openProjects[i]);
iProject = getProjectByUID(iProjectData.uid);
if (iProject) {
log.info("Opening project " + iProject.name);
openProject(iProject, locations, true);
}
}
}
/**
* Get saved settings data
* */
public function getSettingsData():Boolean {
var result:Object = SharedObjectUtils.getSharedObject(SETTINGS_DATA_NAME);
var so:SharedObject;
if (result is SharedObject) {
so = SharedObject(result);
if (so.data) {
if (SETTINGS_DATA_NAME in so.data) {
settings = Settings(so.data[SETTINGS_DATA_NAME]);
}
}
}
else {
log.error("Could not get saved data. " + ObjectUtil.toString(result));
}
return result;
}
/**
* Removed saved data
* */
public function removeSavedData():Boolean {
var result:Object = SharedObjectUtils.getSharedObject(SAVED_DATA_NAME);
var so:SharedObject;
if (result is SharedObject) {
so = SharedObject(result);
if (so.data) {
if (SAVED_DATA_NAME in so.data) {
so.clear();
log.info("Cleared saved data");
}
}
}
else {
log.error("Could not remove saved data. " + ObjectUtil.toString(result));
}
return result;
}
/**
* Removed saved settings
* */
public function removeSavedSettings():Boolean {
var result:Object = SharedObjectUtils.getSharedObject(SETTINGS_DATA_NAME);
var so:SharedObject;
if (result is SharedObject) {
so = SharedObject(result);
if (so.data) {
if (SETTINGS_DATA_NAME in so.data) {
so.clear(); // this clears the whole thing
log.info("Cleared settings data");
}
}
}
else {
log.error("Could not remove settings data. " + ObjectUtil.toString(result));
}
return result;
}
/**
* Save settings data
* */
public function saveSettings():Boolean {
var result:Object = SharedObjectUtils.getSharedObject(SETTINGS_DATA_NAME);
var so:SharedObject;
if (result is SharedObject) {
updateSettingsBeforeSave();
so = SharedObject(result);
so.setProperty(SETTINGS_DATA_NAME, settings);
so.flush();
//log.info("Saved Serrinfo: "+ ObjectUtil.toString(so.data));
}
else {
log.error("Could not save data. " + ObjectUtil.toString(result));
return false;
}
return true;
}
/**
* Save all projects and documents locally and remotely.
* Eventually, we will want to create a file options class that
* contains information on saving locally, to file, remotely, etc
* NOT FINISHED
* */
public function save(locations:String = null, options:Object = null):void {
if (locations==null) locations = DocumentData.REMOTE_LOCATION;
var local:Boolean = getIsLocalLocation(locations);
var remote:Boolean = getIsRemoteLocation(locations);
var localResult:Boolean;
if (local) {
local = saveProject(selectedProject, DocumentData.LOCAL_LOCATION);
}
if (remote) {
if (remote && selectedProject is ISavable) {
saveProjectInProgress = true
ISavable(selectedProject).save(DocumentData.REMOTE_LOCATION, options);
if (selectedProject is Project) {
Project(selectedProject).addEventListener(SaveResultsEvent.SAVE_RESULTS, projectSaveResults, false, 0, true);
}
}
}
if (local) {
// saved local successful
if (localResult) {
}
else {
// unsuccessful
}
}
if (remote) {
if (remote) {
}
else {
}
}
}
/**
* Save data
* */
public function saveDataLocally():Boolean {
var result:Object = SharedObjectUtils.getSharedObject(SAVED_DATA_NAME);
var so:SharedObject;
if (result is SharedObject) {
updateSavedDataBeforeSave();
so = SharedObject(result);
so.setProperty(SAVED_DATA_NAME, savedData);
try {
so.flush();
}
catch (error:Error) {
log.error(error.message);
return false;
}
}
else {
log.error("Could not save data. " + ObjectUtil.toString(result));
return false;
}
return true;
}
/**
* Project saved handler
* */
public function projectSaveResults(event:IServiceEvent):void {
var project:IProject = IProject(Event(event).currentTarget);
saveProjectInProgress = false;
if (project is EventDispatcher) {
EventDispatcher(project).removeEventListener(SaveResultsEvent.SAVE_RESULTS, projectSaveResults);
}
if (event is SaveResultsEvent && SaveResultsEvent(event).successful) {
setLastSaveDate();
}
dispatchProjectSavedEvent(IProject(Event(event).currentTarget));
}
/**
* Formatter for dates
* */
public var dateFormatter:DateTimeFormatter = new DateTimeFormatter();
/**
* Sets the last save date
* */
public function setLastSaveDate(date:Date = null):void {
dateFormatter.dateStyle = DateTimeStyle.MEDIUM;
if (!date) date = new Date();
lastSaveDate = dateFormatter.format(date);
}
/**
* Save project
* */
public function saveProject(project:IProject, locations:String = null):Boolean {
if (locations==null) locations = DocumentData.REMOTE_LOCATION;
//if (isUserLoggedIn && isUserConnected) {
saveProjectInProgress = false;
project.save(locations);
//}
if (project is EventDispatcher) {
EventDispatcher(project).addEventListener(SaveResultsEvent.SAVE_RESULTS, projectSaveResults, false, 0, true);
}
// TODO add support to save after response from server
// because ID's may have been added from new documents
var locallySaved:Boolean = saveProjectLocally(project);
//project.saveCompleteCallback = saveData;
return true;
}
/**
* Save project locally
* */
public function saveProjectLocally(project:IProject, saveProjectDocuments:Boolean = true):Boolean {
var result:Object = SharedObjectUtils.getSharedObject(SAVED_DATA_NAME);
var so:SharedObject;
if (result is SharedObject) {
// todo - implement saveProjectDocuments
updateSaveDataForProject(project);
so = SharedObject(result);
so.setProperty(SAVED_DATA_NAME, savedData);
so.flush();
//log.info("Saved Data: " + ObjectUtil.toString(so.data));
}
else {
log.error("Could not save data. " + ObjectUtil.toString(result));
//return false;
}
return true;
}
/**
* Save document. Uses constants, DocumentData.LOCAL_LOCATION, DocumentData.REMOTE_LOCATION, etc
* Separate them by ",".
* */
public function saveDocument(iDocument:IDocument, locations:String = null, options:Object = null):Boolean {
if (locations==null) locations = DocumentData.REMOTE_LOCATION;
var saveLocally:Boolean = getIsLocalLocation(locations);
var saveRemote:Boolean = getIsRemoteLocation(locations);
var saveLocallySuccessful:Boolean;
if (saveRemote && iDocument && iDocument is EventDispatcher) {
EventDispatcher(iDocument).addEventListener(SaveResultsEvent.SAVE_RESULTS, documentSaveResultsHandler, false, 0, true);
}
saveLocallySuccessful = iDocument.save(locations, options);
// TODO add support to save after response from server
// because ID's may have been added from new documents
//saveData();
//document.saveCompleteCallback = saveData;
//saveDocumentLocally(document);
return saveLocallySuccessful;
}
/**
* Returns true if location includes local shared object
* */
public function getIsLocalLocation(value:String):Boolean {
return value ? value.indexOf(DocumentData.LOCAL_LOCATION)!=-1 || value==DocumentData.ALL_LOCATIONS : false;
}
/**
* Returns true if location includes remote
* */
public function getIsRemoteLocation(value:String):Boolean {
return value ? value.indexOf(DocumentData.REMOTE_LOCATION)!=-1 || value==DocumentData.ALL_LOCATIONS : false;
}
/**
* Returns true if location includes file system
* */
public function getIsFileLocation(value:String):Boolean {
return value ? value.indexOf(DocumentData.FILE_LOCATION)!=-1 || value==DocumentData.ALL_LOCATIONS : false;
}
/**
* Returns true if location includes a database
* */
public function getIsDataBaseLocation(value:String):Boolean {
return value ? value.indexOf(DocumentData.FILE_LOCATION)!=-1 || value==DocumentData.ALL_LOCATIONS : false;
}
/**
* Returns true if location includes internal
* */
public function getIsInternalLocation(value:String):Boolean {
return value ? value.indexOf(DocumentData.INTERNAL_LOCATION)!=-1 || value==DocumentData.ALL_LOCATIONS : false;
}
/**
* Handles results from document save
* */
protected function documentSaveResultsHandler(event:SaveResultsEvent):void {
var document:IDocument = IDocument(event.currentTarget);
if (document is Document) {
Document(document).removeEventListener(SaveResultsEvent.SAVE_RESULTS, documentSaveResultsHandler);
}
setLastSaveDate();
if (event.successful) {
dispatchDocumentSaveCompleteEvent(document);
}
else {
dispatchDocumentSaveFaultEvent(document);
}
}
/**
* Save document
* */
public function saveAllDocuments(saveLocations:String = ""):Boolean {
var document:IDocument;
var project:IProject;
var length:int = documents.length;
for (var i:int;i<length;i++) {
document = documents[i];
if (document.isChanged) {
document.save(saveLocations);
// TODO add support to save after response from server
// because ID's may have been added from new documents
//saveData();
//document.saveCompleteCallback = saveData;
saveDocumentLocally(document);
}
}
length = projects.length;
for (i = 0;i<length;i++) {
project = projects[i];
if (project.isChanged) {
project.save();
// TODO add support to save after response from server
// because ID's may have been added from new documents
//saveData();
//document.saveCompleteCallback = saveData;
saveProjectLocally(project);
}
}
return true;
}
/**
* Save document as
* */
public function saveDocumentAs(document:IDocument, extension:String = "html"):void {
/*
document.save();
// TODO add support to save after response from server
// because ID's may have been added from new documents
//saveData();
//document.saveCompleteCallback = saveData;
saveDocumentLocally(document);*/
//return true;
}
/**
* Save file as
* */
public function saveFileAs(data:Object, name:String = "", extension:String = "html"):FileReference {
var fileName:String = name==null ? "" : name;
fileName = fileName.indexOf(".")==-1 && extension ? fileName + "." + extension : fileName;
// FOR SAVING A FILE (save as) WE MAY NOT NEED ALL THE LISTENERS WE ARE ADDING
// add listeners
var fileReference:FileReference = new FileReference();
addFileListeners(fileReference);
fileReference.save(data, fileName);
return fileReference;
}
/**
* Adds file save as listeners. Rename or refactor
* */
public function addFileListeners(dispatcher:IEventDispatcher):void {
dispatcher.addEventListener(Event.CANCEL, cancelFileSaveAsHandler, false, 0, true);
dispatcher.addEventListener(Event.COMPLETE, completeFileSaveAsHandler, false, 0, true);
}
/**
* Removes file save as listeners. Rename or refactor
* */
public function removeFileListeners(dispatcher:IEventDispatcher):void {
dispatcher.removeEventListener(Event.CANCEL, cancelFileSaveAsHandler);
dispatcher.removeEventListener(Event.COMPLETE, completeFileSaveAsHandler);
}
/**
* File save as complete
* */
public function completeFileSaveAsHandler(event:Event):void {
removeFileListeners(event.currentTarget as IEventDispatcher);
dispatchDocumentSaveCompleteEvent(selectedDocument);
}
/**
* Cancel file save as
* */
public function cancelFileSaveAsHandler(event:Event):void {
removeFileListeners(event.currentTarget as IEventDispatcher);
dispatchDocumentSaveAsCancelEvent(selectedDocument);
}
/**
* Get document locally
* */
public function getDocumentLocally(iDocumentData:IDocumentData):IDocumentData {
var result:Object = SharedObjectUtils.getSharedObject(SAVED_DATA_NAME);
var so:SharedObject;
if (result is SharedObject) {
so = SharedObject(result);
//var data:Object = savedData;
var documentsArray:Array = so.data.savedData.documents;
var length:int = documentsArray.length;
var documentData:IDocumentData;
var found:Boolean;
var foundIndex:int = -1;
for (var i:int;i<length;i++) {
documentData = IDocumentData(documentsArray[i]);
if (documentData.uid == iDocumentData.uid) {
found = true;
foundIndex = i;
break;
}
}
return documentData;
}
else {
log.error("Could not get saved data. " + ObjectUtil.toString(result));
}
return null;
}
/**
* Save document locally
* */
public function saveDocumentLocally(document:IDocumentData):Boolean {
var result:Object = SharedObjectUtils.getSharedObject(SAVED_DATA_NAME);
var so:SharedObject;
if (result is SharedObject) {
updateSaveDataForDocument(document);
so = SharedObject(result);
so.setProperty(SAVED_DATA_NAME, savedData);
so.flush();
//log.info("Saved Data: " + ObjectUtil.toString(so.data));
}
else {
log.error("Could not save data. " + ObjectUtil.toString(result));
//return false;
}
return true;
}
/**
* Get settings
* */
public function getSettings():Boolean {
return true;
}
/**
* Get the latest settings and copy them into the settings object
* */
public function updateSettingsBeforeSave():Settings {
// get selected document
// get selected project
// get open projects
// get open documents
// get all documents
// get all projects
// save workspace settings
// save preferences settings
settings.lastOpened = new Date().time;
//settings.modified = new Date().time;
settings.openDocuments = getOpenDocumentsSaveData(true);
settings.openProjects = getOpenProjectsSaveData(true);
settings.selectedProject = selectedProject ? selectedProject.toMetaData() : null;
settings.selectedDocument = selectedDocument ? selectedDocument.toMetaData() : null;
settings.saveCount++;
return settings;
}
/**
* Get the latest project and document data.
* */
public function updateSavedDataBeforeSave():SavedData {
// get selected document
// get selected project
// get open projects
// get open documents
// get all documents
// get all projects
// save workspace settings
// save preferences settings
savedData.modified = new Date().time;
//settings.modified = new Date().time;
savedData.documents = getSaveDataForAllDocuments();
savedData.projects = getSaveDataForAllProjects();
savedData.saveCount++;
//savedData.resources = getResources();
return savedData;
}
/**
* Get projects
* */
public function getProjects(status:String = WPService.STATUS_ANY, locations:String = null, count:int = 100):void {
if (locations==null) locations = DocumentData.REMOTE_LOCATION;
var loadLocally:Boolean = locations.indexOf(DocumentData.LOCAL_LOCATION)!=-1;
var loadRemote:Boolean = locations.indexOf(DocumentData.REMOTE_LOCATION)!=-1;
if (loadRemote) {
// we need to create service
if (getProjectsService==null) {
var service:WPService = new WPService();
service = new WPService();
service.host = getWPURL();
service.addEventListener(WPService.RESULT, getProjectsResultsHandler, false, 0, true);
service.addEventListener(WPService.FAULT, getProjectsFaultHandler, false, 0, true);
getProjectsService = service;
}
getProjectsInProgress = true;
getProjectsService.getProjects(status, count);
}
if (loadLocally) {
}
}
/**
* Get projects by user ID
* */
public function getProjectsByUser(id:int, status:String = WPService.STATUS_ANY, locations:String = null, count:int = 100):void {
if (locations==null) locations = DocumentData.REMOTE_LOCATION;
if (status==null) status = WPService.STATUS_ANY;
var loadLocally:Boolean = locations.indexOf(DocumentData.LOCAL_LOCATION)!=-1;
var loadRemote:Boolean = locations.indexOf(DocumentData.REMOTE_LOCATION)!=-1;
if (loadRemote) {
// we need to create service
if (getProjectsService==null) {
var service:WPService = new WPService();
service = new WPService();
service.host = getWPURL();
service.addEventListener(WPService.RESULT, getProjectsResultsHandler, false, 0, true);
service.addEventListener(WPService.FAULT, getProjectsFaultHandler, false, 0, true);
getProjectsService = service;
}
getProjectsInProgress = true;
getProjectsService.getProjectsByUser(id, status, count);
}
if (loadLocally) {
}
}
/**
* Login user
* */
public function login(username:String, password:String):void {
// we need to create service
if (loginService==null) {
loginService = new WPService();
loginService.addEventListener(WPService.RESULT, loginResultsHandler, false, 0, true);
loginService.addEventListener(WPService.FAULT, loginFaultHandler, false, 0, true);
}
loginService.host = getWPURL();
loginInProgress = true;
loginService.loginUser(username, password);
}
/**
* Logout user
* */
public function logout():void {
// we need to create service
if (logoutService==null) {
logoutService = new WPService();
logoutService.addEventListener(WPService.RESULT, logoutResultsHandler, false, 0, true);
logoutService.addEventListener(WPService.FAULT, logoutFaultHandler, false, 0, true);
}
logoutService.host = getWPURL();
logoutInProgress = true;
logoutService.logoutUser();
}
/**
* Register user
* */
public function register(username:String, email:String):void {
// we need to create service
if (registerService==null) {
registerService = new WPService();
registerService.addEventListener(WPService.RESULT, registerResultsHandler, false, 0, true);
registerService.addEventListener(WPService.FAULT, registerFaultHandler, false, 0, true);
}
registerService.host = getWPURL();
registerInProgress = true;
registerService.registerUser(username, email);
}
/**
* Register site
* */
public function registerSite(blogName:String = "", blogTitle:String = "", isPublic:Boolean = false):void {
// we need to create service
if (registerService==null) {
registerService = new WPService();
registerService.addEventListener(WPService.RESULT, registerResultsHandler, false, 0, true);
registerService.addEventListener(WPService.FAULT, registerFaultHandler, false, 0, true);
}
registerService.host = getWPURL();
registerInProgress = true;
registerService.registerSite(blogName, blogTitle, isPublic);
}
/**
* Register user and site
* */
public function registerUserAndSite(username:String, email:String, siteName:String = "", blogTitle:String = "", isPublic:Boolean = false, requireSiteName:Boolean = false):void {
// we need to create service
if (registerService==null) {
registerService = new WPService();
registerService.addEventListener(WPService.RESULT, registerResultsHandler, false, 0, true);
registerService.addEventListener(WPService.FAULT, registerFaultHandler, false, 0, true);
}
registerService.host = getWPURL();
registerInProgress = true;
if (!requireSiteName) {
if (siteName=="") {
siteName = username;
}
if (blogTitle=="") {
blogTitle = "A Radiate site";
}
}
registerService.registerUserAndSite(username, email, siteName, blogTitle, isPublic);
}
/**
* Request lost password. Sends an email with instructions.
* @param username or email address
* */
public function lostPassword(usernameOrEmail:String):void {
// we need to create service
if (lostPasswordService==null) {
lostPasswordService = new WPService();
lostPasswordService.addEventListener(WPService.RESULT, lostPasswordResultsHandler, false, 0, true);
lostPasswordService.addEventListener(WPService.FAULT, lostPasswordFaultHandler, false, 0, true);
}
lostPasswordService.host = getWPURL();
lostPasswordInProgress = true;
lostPasswordService.lostPassword(usernameOrEmail);
}
/**
* Reset or change password
* */
public function changePassword(key:String, username:String, password:String, password2:String):void {
// we need to create service
if (changePasswordService==null) {
changePasswordService = new WPService();
changePasswordService.addEventListener(WPService.RESULT, changePasswordResultsHandler, false, 0, true);
changePasswordService.addEventListener(WPService.FAULT, changePasswordFaultHandler, false, 0, true);
}
changePasswordService.host = getWPURL();
changePasswordInProgress = true;
changePasswordService.resetPassword(key, username, password, password2);
}
/**
* Get images from the server
* */
public function getAttachments(id:int = 0):void {
// get selected document
// we need to create service
if (getAttachmentsService==null) {
getAttachmentsService = new WPService();
getAttachmentsService.addEventListener(WPService.RESULT, getAttachmentsResultsHandler, false, 0, true);
getAttachmentsService.addEventListener(WPService.FAULT, getAttachmentsFaultHandler, false, 0, true);
}
getAttachmentsService.host = getWPURL();
if (id!=0) {
getAttachmentsService.id = String(id);
}
getAttachmentsInProgress = true;
getAttachmentsService.getAttachments(id);
}
/**
* Upload image to the server
* */
public function uploadAttachment(data:Object, id:String, fileName:String = null, dataField:String = null, contentType:String = null):void {
// get selected document
// we need to create service
if (uploadAttachmentService==null) {
uploadAttachmentService = new WPAttachmentService();
uploadAttachmentService.addEventListener(WPService.RESULT, uploadAttachmentResultsHandler, false, 0, true);
uploadAttachmentService.addEventListener(WPService.FAULT, uploadAttachmentFaultHandler, false, 0, true);
//uploadAttachmentService = service;
}
uploadAttachmentService.host = getWPURL();
if (id!=null) {
uploadAttachmentService.id = id;
}
uploadAttachmentInProgress = true;
if (data is FileReference) {
uploadAttachmentService.file = data as FileReference;
uploadAttachmentService.uploadAttachment();
}
else if (data) {
uploadAttachmentService.fileData = data as ByteArray;
if (fileName) {
uploadAttachmentService.fileName = fileName;
}
if (dataField) {
uploadAttachmentService.dataField = dataField;
}
if (contentType) {
uploadAttachmentService.contentType = contentType;
}
uploadAttachmentService.uploadAttachment();
}
else {
Radiate.log.warn("No data or file is available for upload. Please select the file to upload.");
}
}
/**
* Get projects
* */
public function getLoggedInStatus():void {
// get selected document
var service:WPService;
// we need to create service
if (getProjectsService==null) {
service = new WPService();
service.host = getWPURL();
service.addEventListener(WPService.RESULT, getLoggedInStatusResult, false, 0, true);
service.addEventListener(WPService.FAULT, getLoggedInStatusFault, false, 0, true);
getLoggedInStatusService = service;
}
getLoggedInStatusInProgress = true;
getLoggedInStatusService.getLoggedInUser();
}
/**
* Handles result to check if user is logged in
* */
protected function getLoggedInStatusResult(event:WPServiceEvent):void {
isUserConnected = true;
var data:Object = event.data;
updateUserInfo(data);
getLoggedInStatusInProgress = false;
dispatchLoginStatusEvent(isUserLoggedIn, data);
}
/**
* Updates the user information from data object from the server
* */
public function updateUserInfo(data:Object):void {
if (data && data is Object) {
isUserLoggedIn = data.loggedIn;
userAvatar = data.avatar;
userDisplayName = data.displayName ? data.displayName : "guest";
userID = data.id;
userEmail = data.contact;
user = data;
if ("blogs" in user) {
//userSites = user.blogs;
userSites = [];
for each (var blog:Object in user.blogs) {
userSites.push(blog);
}
if (userSites.length>0) {
userSitePath = userSites[0].path;
WP_USER_PATH = userSitePath;
WP_USER_PATH = WP_USER_PATH.replace(WP_PATH, "");
}
else {
userSitePath = "";
WP_USER_PATH = "";
}
}
}
}
/**
* Handles fault when checking if user is logged in
* */
protected function getLoggedInStatusFault(event:WPServiceEvent):void {
var data:Object = event.data;
isUserConnected = false;
//isUserLoggedIn = false;
getLoggedInStatusInProgress = false;
dispatchLoginStatusEvent(isUserLoggedIn, data);
}
/**
* Results from call to get projects
* */
public function getProjectsResultsHandler(event:IServiceEvent):void {
//Radiate.log.info("Retrieved list of projects");
var data:Object = event.data;
getProjectsInProgress = false;
dispatchGetProjectsListResultsEvent(data);
}
/**
* Open list of projects. Need to eventually convert from wordpress post data object to type classes.
* See getAttachmentsResultsHandler()
* */
public function openProjectsFromData(projectsData:Array):void {
var length:int;
var post:Object;
var project:IProject
var xml:XML;
var isValid:Boolean;
var firstProject:IProject;
var potentialProjects:Array;
length = projectsData.count;
for (var i:int;i<length;i++) {
post = potentialProjects.posts[i];
isValid = XMLUtils.isValidXML(post.content);
if (isValid) {
xml = new XML(post.content);
project = createProjectFromXML(xml);
addProject(project);
potentialProjects.push(project);
}
else {
log.info("Could not import project:" + post.title);
}
}
//potentialProjects = addSavedProjects(data.projects);
if (potentialProjects.length>0) {
openProject(potentialProjects[0]);
setProject(potentialProjects[0]);
}
}
/**
* Result from save fault
* */
public function getProjectsFaultHandler(event:IServiceEvent):void {
var data:Object = event.data;
Radiate.log.info("Could not get list of projects");
getProjectsInProgress = false;
dispatchGetProjectsListResultsEvent(data);
}
/**
* Result get attachments
* */
public function getAttachmentsResultsHandler(event:IServiceEvent):void {
Radiate.log.info("Retrieved list of attachments");
var data:Object = event.data;
var potentialAttachments:Array = [];
var length:int;
var object:Object;
var attachment:AttachmentData;
if (data && data.count>0) {
length = data.count;
for (var i:int;i<length;i++) {
object = data.attachments[i];
if (String(object.mime_type).indexOf("image/")!=-1) {
attachment = new ImageData();
attachment.unmarshall(object);
}
else {
attachment = new AttachmentData();
attachment.unmarshall(object);
}
potentialAttachments.push(attachment);
}
}
getAttachmentsInProgress = false;
attachments = potentialAttachments;
dispatchAttachmentsResultsEvent(true, attachments);
}
/**
* Result from attachments fault
* */
public function getAttachmentsFaultHandler(event:IServiceEvent):void {
Radiate.log.info("Could not get list of attachments");
getAttachmentsInProgress = false;
//dispatchEvent(saveResultsEvent);
dispatchAttachmentsResultsEvent(false, []);
}
/**
* Result upload attachment
* */
public function uploadAttachmentResultsHandler(event:IServiceEvent):void {
//Radiate.log.info("Upload attachment");
var data:Object = event.data;
var potentialAttachments:Array = [];
var successful:Boolean = data && data.status && data.status=="ok" ? true : false;
var length:int;
var object:Object;
var attachment:AttachmentData;
var asset:AttachmentData;
var remoteAttachments:Array = data && data.post && data.post.attachments ? data.post.attachments : [];
var containsName:Boolean;
var assetsLength:int;
if (remoteAttachments.length>0) {
length = remoteAttachments.length;
for (var i:int;i<length;i++) {
object = remoteAttachments[i];
if (String(object.mime_type).indexOf("image/")!=-1) {
attachment = new ImageData();
attachment.unmarshall(object);
}
else {
attachment = new AttachmentData();
attachment.unmarshall(object);
}
potentialAttachments.push(attachment);
//attachments = potentialAttachments;
assetsLength = assets.length;
j = 0;
for (var j:int;j<assetsLength;j++) {
asset = assets.getItemAt(j) as AttachmentData;
containsName = asset ? asset.name.indexOf(attachment.name)==0 : false;
// this is not very robust but since uploading only supports one at a time
// it should be fine. when supporting multiple uploading, keep
// track of items being uploaded
if (containsName && asset.id==null) {
asset.unmarshall(attachment);
var documentLength:int = documents.length;
k = 0;
for (var k:int;k<documentLength;k++) {
var iDocument:IDocument = documents[k] as IDocument;
if (iDocument) {
DisplayObjectUtils.walkDownComponentTree(iDocument.componentDescription, replaceBitmapData, [asset]);
}
}
break;
}
}
}
}
uploadAttachmentInProgress = false;
dispatchUploadAttachmentResultsEvent(successful, potentialAttachments, data.post);
}
/**
* Replaces occurances where the bitmapData in Image and BitmapImage have
* been uploaded to the server and we now want to point the image to a URL
* rather than bitmap data
* */
public function replaceBitmapData(component:ComponentDescription, imageData:ImageData):void {
var instance:Object;
if (imageData && component && component.instance) {
instance = component.instance;
if (instance is Image || instance is BitmapImage) {
if (instance.source == imageData.bitmapData) {
Radiate.setProperty(instance, "source", imageData.url);
}
}
}
}
/**
* Result from upload attachment fault
* */
public function uploadAttachmentFaultHandler(event:IServiceEvent):void {
Radiate.log.info("Upload attachment fault");
uploadAttachmentInProgress = false;
//dispatchEvent(saveResultsEvent);
dispatchUploadAttachmentResultsEvent(false, [], event.data);
}
/**
* Login results handler
* */
public function loginResultsHandler(event:IServiceEvent):void {
//Radiate.log.info("Login results");
var data:Object = event.data;
var loggedIn:Boolean;
if (data && data is Object) {
loggedIn = data.loggedIn==true;
updateUserInfo(data);
}
loginInProgress = false;
dispatchLoginResultsEvent(loggedIn, data);
}
/**
* Result from login fault
* */
public function loginFaultHandler(event:IServiceEvent):void {
var data:Object = event.data;
Radiate.log.info("Could not connect to the server to login. ");
loginInProgress = false;
dispatchLoginResultsEvent(false, data);
}
/**
* Logout results handler
* */
public function logoutResultsHandler(event:IServiceEvent):void {
Radiate.log.info("Logout results");
var data:Object = event.data;
var loggedOut:Boolean;
if (data && data is Object) {
loggedOut = data.loggedIn==false;
updateUserInfo(data);
}
logoutInProgress = false;
dispatchLogoutResultsEvent(loggedOut, data);
}
/**
* Result from logout fault
* */
public function logoutFaultHandler(event:IServiceEvent):void {
var data:Object = event.data;
Radiate.log.info("Could not connect to the server to logout. ");
logoutInProgress = false;
dispatchLogoutResultsEvent(false, data);
}
/**
* Register results handler
* */
public function registerResultsHandler(event:IServiceEvent):void {
//Radiate.log.info("Register results");
var data:Object = event.data;
var successful:Boolean;
if (data && data is Object && "created" in data) {
successful = data.created;
}
registerInProgress = false;
dispatchRegisterResultsEvent(successful, data);
}
/**
* Result from register fault
* */
public function registerFaultHandler(event:IServiceEvent):void {
var data:Object = event.data;
Radiate.log.info("Could not connect to the server to register. ");
registerInProgress = false;
dispatchRegisterResultsEvent(false, data);
}
/**
* Register results handler
* */
public function changePasswordResultsHandler(event:IServiceEvent):void {
//Radiate.log.info("Change password results");
var data:Object = event.data;
var successful:Boolean;
if (data && data is Object && "created" in data) {
successful = data.created;
}
changePasswordInProgress = false;
dispatchChangePasswordResultsEvent(successful, data);
}
/**
* Result from change password fault
* */
public function changePasswordFaultHandler(event:IServiceEvent):void {
var data:Object = event.data;
Radiate.log.info("Could not connect to the server. " + event.faultEvent.toString());
changePasswordInProgress = false;
dispatchChangePasswordResultsEvent(false, data);
}
/**
* Lost password results handler
* */
public function lostPasswordResultsHandler(event:IServiceEvent):void {
//Radiate.log.info("Change password results");
var data:Object = event.data;
var successful:Boolean;
if (data && data is Object && "created" in data) {
successful = data.created;
}
lostPasswordInProgress = false;
dispatchLostPasswordResultsEvent(successful, data);
}
/**
* Result from lost password fault
* */
public function lostPasswordFaultHandler(event:IServiceEvent):void {
var data:Object = event.data;
Radiate.log.info("Could not connect to the server. " + event.faultEvent.toString());
lostPasswordInProgress = false;
dispatchLostPasswordResultsEvent(false, data);
}
/**
* Delete project results handler
* */
public function deleteProjectResultsHandler(event:IServiceEvent):void {
//Radiate.log.info("Delete project results");
var data:Object = event.data;
var status:Boolean;
var successful:Boolean;
var error:String;
var message:String;
if (data && data is Object) {
//status = data.status==true;
}
deleteProjectInProgress = false;
if (data && data is Object && "status" in data) {
successful = data.status!="error";
}
//Include 'id' or 'slug' var in your request.
if (event.faultEvent is IOErrorEvent) {
message = "Are you connected to the internet? ";
if (event.faultEvent is IOErrorEvent) {
message = IOErrorEvent(event.faultEvent).text;
}
else if (event.faultEvent is SecurityErrorEvent) {
if (SecurityErrorEvent(event.faultEvent).errorID==2048) {
}
message += SecurityErrorEvent(event.faultEvent).text;
}
}
//dispatchProjectRemovedEvent(null);
dispatchProjectDeletedEvent(successful, data);
}
/**
* Result from delete project fault
* */
public function deleteProjectFaultHandler(event:IServiceEvent):void {
var data:Object = event.data;
Radiate.log.info("Could not connect to the server to delete the project. ");
deleteProjectInProgress = false;
dispatchProjectDeletedEvent(false, data);
}
/**
* Delete document results handler
* */
public function deleteDocumentResultsHandler(event:IServiceEvent):void {
//..Radiate.log.info("Delete document results");
var data:Object = event.data;
//var status:Boolean;
var successful:Boolean;
var error:String;
var message:String;
if (data && data is Object && "status" in data) {
successful = data.status!="error";
}
deleteDocumentInProgress = false;
deleteAttachmentInProgress = false;
//Include 'id' or 'slug' var in your request.
if (event.faultEvent is IOErrorEvent) {
message = "Are you connected to the internet? ";
if (event.faultEvent is IOErrorEvent) {
message = IOErrorEvent(event.faultEvent).text;
}
else if (event.faultEvent is SecurityErrorEvent) {
if (SecurityErrorEvent(event.faultEvent).errorID==2048) {
}
message += SecurityErrorEvent(event.faultEvent).text;
}
}
//status = message;
//dispatchDocumentRemovedEvent(null);
dispatchDocumentDeletedEvent(successful, data);
}
/**
* Result from delete project fault
* */
public function deleteDocumentFaultHandler(event:IServiceEvent):void {
var data:Object = event.data;
Radiate.log.info("Could not connect to the server to delete the document. ");
deleteDocumentInProgress = false;
dispatchDocumentDeletedEvent(false, data);
}
/**
* Check if the project has changed and mark changed if it is.
* */
public function checkIfProjectHasChanged(iProject:IProject):Boolean {
var isChanged:Boolean = iProject.checkProjectHasChanged();
return isChanged;
}
/**
* Updates the saved data with the changes from the document passed in
* */
public function updateSaveDataForDocument(iDocumentData:IDocumentData, metaData:Boolean = false):SavedData {
var documentsArray:Array = savedData.documents;
var length:int = documentsArray.length;
var documentMetaData:IDocumentMetaData;
var found:Boolean;
var foundIndex:int = -1;
for (var i:int;i<length;i++) {
documentMetaData = IDocumentMetaData(documentsArray[i]);
//Radiate.log.info("Exporting document " + iDocument.name);
if (documentMetaData.uid == iDocumentData.uid) {
found = true;
foundIndex = i;
}
}
if (found) {
if (metaData) {
documentsArray[foundIndex] = iDocumentData.toMetaData();
}
else {
documentsArray[foundIndex] = iDocumentData.marshall();
}
}
else {
if (metaData) {
documentsArray.push(iDocumentData.toMetaData());
}
else {
documentsArray.push(iDocumentData.marshall());
}
}
return savedData;
}
/**
* Updates the saved data with the changes from the project passed in
* */
public function updateSaveDataForProject(iProject:IProject, metaData:Boolean = false):SavedData {
var projectsArray:Array = savedData.projects;
var length:int = projectsArray.length;
var documentMetaData:IDocumentMetaData;
var found:Boolean;
var foundIndex:int = -1;
for (var i:int;i<length;i++) {
documentMetaData = IDocumentData(projectsArray[i]);
//Radiate.log.info("Exporting document " + iDocument.name);
if (documentMetaData.uid == iProject.uid) {
found = true;
foundIndex = i;
}
}
if (found) {
if (metaData) {
projectsArray[foundIndex] = iProject.toMetaData();
}
else {
projectsArray[foundIndex] = iProject.marshall();
}
}
else {
if (metaData) {
projectsArray.push(iProject.toMetaData());
}
else {
projectsArray.push(iProject.marshall());
}
}
return savedData;
}
/**
* Get a list of documents. If open is set to true then gets only open documents.
* */
public function getOpenDocumentsSaveData(metaData:Boolean = false):Array {
var documentsArray:Array = getSaveDataForAllDocuments(true, metaData);
return documentsArray;
}
/**
* Get a list of documents data for storage by project. If open is set to true then only returns open documents.
* */
public function getDocumentsSaveDataByProject(project:IProject, open:Boolean = false):Array {
var documentsArray:Array = project.getSavableDocumentsData(open);
return documentsArray;
}
/**
* Get a list of all documents data for storage. If open is set to
* true then only returns open documents.
* */
public function getSaveDataForAllDocuments(open:Boolean = false, metaData:Boolean = false):Array {
var length:int = projects.length;
var documentsArray:Array = [];
var iProject:IProject;
for (var i:int;i<length;i++) {
iProject = projects[i];
documentsArray = documentsArray.concat(iProject.getSavableDocumentsData(open, metaData));
}
return documentsArray;
}
/**
* Get a list of projects that are open.
* If meta data is true only returns meta data.
* */
public function getOpenProjectsSaveData(metaData:Boolean = false):Array {
var projectsArray:Array = getSaveDataForAllProjects(true, metaData);
return projectsArray;
}
/**
* Get an array of projects serialized for storage.
* If open is set to true then only returns open projects.
* If meta data is true then only returns meta data.
* */
public function getSaveDataForAllProjects(open:Boolean = false, metaData:Boolean = false):Array {
var projectsArray:Array = [];
var length:int = projects.length;
var iProject:IProject;
for (var i:int; i < length; i++) {
iProject = IProject(projects[i]);
if (open) {
if (iProject.isOpen) {
if (metaData) {
projectsArray.push(iProject.toMetaData());
}
else {
projectsArray.push(iProject.marshall());
}
}
}
else {
if (metaData) {
projectsArray.push(iProject.toMetaData());
}
else {
projectsArray.push(iProject.marshall());
}
}
}
return projectsArray;
}
/**
* Get an array of projects serialized for storage.
* If open is set to true then only returns open projects.
* If meta data is true then only returns meta data.
* */
public function saveProjectsRemotely(open:Boolean = false):Array {
var projectsArray:Array = [];
var length:int = projects.length;
var iProject:IProject;
for (var i:int; i < length; i++) {
iProject = IProject(projects[i]);
if (open) {
if (iProject.isOpen) {
iProject.save();
}
}
else {
iProject.save();
}
}
return projectsArray;
}
//----------------------------------
//
// History Management
//
//----------------------------------
// NOTE: THIS IS WRITTEN THIS WAY TO WORK WITH FLEX STATES AND TRANSITIONS
// there is probably a better way but I am attempting to use the flex sdk's
// own code to apply changes. we could extract that code, create commands,
// etc but it seemed like less work and less room for error at the time
// update oct 27, 2013
// i think it would be better to move these calls and data to the document class
// then different document types can handle undo, redo in the way that best
// makes sense to it's own needs.
// For example, an text editor will handle undo redo differently than
// a design or application document.
//
// and another way we could do history management is create a sequence and
// add actions to it (SetAction, AddItem, RemoveItem, etc)
// that would probably enable easy to use automation and playback
// if we had proxied these methods here we could have extended the default
// document and over wrote the methods to try the sequence method
public static var REMOVE_ITEM_DESCRIPTION:String = "Remove";
public static var ADD_ITEM_DESCRIPTION:String = "Add";
private static var BEGINNING_OF_HISTORY:String;
/**
* Collection of items in the property change history
* */
[Bindable]
public static var history:ArrayCollection = new ArrayCollection();
/**
* Dictionary of property change objects
* */
public static var historyEventsDictionary:Dictionary = new Dictionary(true);
/**
* Travel to the specified history index.
* Going to fast may cause some issues. Need to test thoroughly
* We may need to call validateNow somewhere and set usePhasedInstantiation?
* */
public static function goToHistoryIndex(index:int, dispatchEvents:Boolean = false):int {
var document:IDocument = instance.selectedDocument;
var newIndex:int = index;
var oldIndex:int = historyIndex;
var time:int = getTimer();
var currentIndex:int;
var difference:int;
var layoutManager:ILayoutManager = LayoutManager.getInstance();
var phasedInstantiation:Boolean = layoutManager.usePhasedInstantiation;
layoutManager.usePhasedInstantiation = false;
if (newIndex<oldIndex) {
difference = oldIndex - newIndex;
for (var i:int;i<difference;i++) {
currentIndex = undo(dispatchEvents, dispatchEvents);
}
}
else if (newIndex>oldIndex) {
difference = oldIndex<0 ? newIndex+1 : newIndex - oldIndex;
for (var j:int;j<difference;j++) {
currentIndex = redo(dispatchEvents, dispatchEvents);
}
}
layoutManager.usePhasedInstantiation = phasedInstantiation;
history.refresh();
historyIndex = getHistoryIndex();
instance.dispatchHistoryChangeEvent(historyIndex, oldIndex);
return currentIndex;
}
/**
* Undo last change. Returns the current index in the changes array.
* The property change object sets the property "reversed" to
* true.
* Going too fast causes some issues (call validateNow somewhere)?
* I think the issue with RangeError: Index 2 is out of range.
* is that the History List does not always do the first item in the
* List. So we need to add a first item that does nothing, like a
* open history event.
* OR we need to wait. If we could use callLater and not use validateNow
* I think it may solve some issues and not lock the UI
* */
public static function undo(dispatchEvents:Boolean = false, dispatchForApplication:Boolean = true):int {
var changeIndex:int = getPreviousHistoryIndex(); // index of next change to undo
var currentIndex:int = getHistoryIndex();
var historyLength:int = history.length;
var historyEvent:HistoryEventItem;
var currentDocument:IDocument = instance.selectedDocument;
var currentTargetDocument:Application = currentDocument.instance as Application;
var setStartValues:Boolean = true;
var historyItem:HistoryEvent;
var affectsDocument:Boolean;
var historyEvents:Array;
var dictionary:Dictionary;
var reverseItems:AddItems;
var eventTargets:Array;
var eventsLength:int;
var targetsLength:int;
var addItems:AddItems;
var added:Boolean;
var removed:Boolean;
var action:String;
var isInvalid:Boolean;
// no changes
if (!historyLength) {
return -1;
}
// all changes have already been undone
if (changeIndex<0) {
if (dispatchEvents && instance.hasEventListener(RadiateEvent.BEGINNING_OF_UNDO_HISTORY)) {
instance.dispatchEvent(new RadiateEvent(RadiateEvent.BEGINNING_OF_UNDO_HISTORY));
}
return -1;
}
// get current change to be redone
historyItem = history.length ? history.getItemAt(changeIndex) as HistoryEvent : null;
historyEvents = historyItem.historyEventItems;
eventsLength = historyEvents.length;
// loop through changes
for (var i:int=eventsLength;i--;) {
//changesLength = changes ? changes.length: 0;
historyEvent = historyEvents[i];
addItems = historyEvent.addItemsInstance;
action = historyEvent.action;//==RadiateEvent.MOVE_ITEM && addItems ? RadiateEvent.MOVE_ITEM : RadiateEvent.PROPERTY_CHANGE;
affectsDocument = dispatchForApplication && historyEvent.targets.indexOf(currentTargetDocument)!=-1;
// undo the add
if (action==RadiateEvent.ADD_ITEM) {
eventTargets = historyEvent.targets;
targetsLength = eventTargets.length;
dictionary = historyEvent.reverseAddItemsDictionary;
for (var j:int=0;j<targetsLength;j++) {
reverseItems = dictionary[eventTargets[j]];
addItems.remove(null);
// check if it's reverse or property changes
if (reverseItems) {
reverseItems.apply(reverseItems.destination as UIComponent);
// was it added - can be refactored
if (reverseItems.destination==null) {
added = true;
}
}
}
historyEvent.reversed = true;
if (dispatchEvents || (dispatchForApplication && affectsDocument)) {
instance.dispatchRemoveItemsEvent(historyEvent.targets, [historyEvent.propertyChanges], historyEvent.properties);
}
}
// undo the move - (most likely an add action with x and y changes)
if (action==RadiateEvent.MOVE_ITEM) {
eventTargets = historyEvent.targets;
targetsLength = eventTargets.length;
dictionary = historyEvent.reverseAddItemsDictionary;
for (j=0;j<targetsLength;j++) {
reverseItems = dictionary[eventTargets[j]];
// check if it's remove items or property changes
if (reverseItems) {
isInvalid = LayoutManager.getInstance().isInvalid();
if (isInvalid) {
LayoutManager.getInstance().validateNow();
LayoutManager.getInstance().isInvalid() ? Radiate.log.debug("Layout Manager is still invalid at note 1.") : 0;
}
addItems.remove(null);
isInvalid = LayoutManager.getInstance().isInvalid();
if (isInvalid) {
LayoutManager.getInstance().validateNow();
LayoutManager.getInstance().isInvalid() ? Radiate.log.debug("Layout Manager is still invalid at note 2.") : 0;
}
reverseItems.apply(reverseItems.destination as UIComponent);
if (dispatchEvents || (dispatchForApplication && affectsDocument)) {
instance.dispatchRemoveItemsEvent(historyEvent.targets, [historyEvent.propertyChanges], historyEvent.properties);
}
// was it added - note: can be refactored
if (reverseItems.destination==null) {
added = true;
}
}
else { // property change
applyChanges(historyEvent.targets, [historyEvent.propertyChanges], historyEvent.properties, historyEvent.styles,
setStartValues);
historyEvent.reversed = true;
if (dispatchEvents || (dispatchForApplication && affectsDocument)) {
instance.dispatchPropertyChangeEvent(historyEvent.targets, [historyEvent.propertyChanges], historyEvent.properties);
}
}
}
historyEvent.reversed = true;
}
// undo the remove
else if (action==RadiateEvent.REMOVE_ITEM) {
isInvalid = LayoutManager.getInstance().isInvalid();
if (isInvalid) {
LayoutManager.getInstance().validateNow();
LayoutManager.getInstance().isInvalid() ? Radiate.log.debug("Layout Manager is still invalid at note 3") : 0;
}
addItems.apply(addItems.destination as UIComponent);
historyEvent.reversed = true;
removed = true;
if (dispatchEvents || (dispatchForApplication && affectsDocument)) {
instance.dispatchAddEvent(historyEvent.targets, [historyEvent.propertyChanges], historyEvent.properties);
}
}
// undo the property changes
else if (action==RadiateEvent.PROPERTY_CHANGED) {
applyChanges(historyEvent.targets, [historyEvent.propertyChanges], historyEvent.properties, historyEvent.styles,
setStartValues);
historyEvent.reversed = true;
if (dispatchEvents || (dispatchForApplication && affectsDocument)) {
instance.dispatchPropertyChangeEvent(historyEvent.targets, [historyEvent.propertyChanges], historyEvent.properties);
}
}
}
historyItem.reversed = true;
// select the target
if (selectTargetOnHistoryChange) {
if (added) { // item was added and now unadded - select previous
if (currentIndex>0) {
instance.setTarget(HistoryEvent(history.getItemAt(currentIndex-1)).targets, true);
}
else {
instance.setTarget(currentTargetDocument, true);
}
}
else if (removed) {
instance.setTargets(historyEvent.targets, true);
}
else {
instance.setTargets(historyEvent.targets, true);
}
}
if (eventsLength) {
historyIndex = getHistoryIndex();
if (dispatchEvents || (dispatchForApplication && affectsDocument)) {
instance.dispatchHistoryChangeEvent(historyIndex, currentIndex);
}
return changeIndex-1;
}
return historyLength;
}
/**
* Redo last change. See notes in undo method.
* @see undo
* */
public static function redo(dispatchEvents:Boolean = false, dispatchForApplication:Boolean = true):int {
var currentDocument:IDocument = instance.selectedDocument;
var historyCollection:ArrayCollection = currentDocument.history;
var currentTargetDocument:Application = currentDocument.instance as Application; // should be typed
var historyLength:int = historyCollection.length;
var changeIndex:int = getNextHistoryIndex();
var currentIndex:int = getHistoryIndex();
var historyEvent:HistoryEventItem;
var historyItem:HistoryEvent;
var affectsDocument:Boolean;
var setStartValues:Boolean;
var historyEvents:Array;
var addItems:AddItems;
var isInvalid:Boolean;
var eventsLength:int;
var remove:Boolean;
var action:String;
// need to make sure everything is validated first
// think about doing the following:
// LayoutManager.getInstance().usePhasedInstantiation = false;
// LayoutManager.getInstance().isInvalid() ? Radiate.log.debug("Layout Manager is still invalid. Needs a fix.") : 0;
// also use in undo()
// no changes made
if (!historyLength) {
return -1;
}
// cannot redo any more changes
if (changeIndex==-1 || changeIndex>=historyLength) {
if (instance.hasEventListener(RadiateEvent.END_OF_UNDO_HISTORY)) {
instance.dispatchEvent(new RadiateEvent(RadiateEvent.END_OF_UNDO_HISTORY));
}
return historyLength-1;
}
// get current change to be redone
historyItem = historyCollection.length ? historyCollection.getItemAt(changeIndex) as HistoryEvent : null;
historyEvents = historyItem.historyEventItems;
eventsLength = historyEvents.length;
//changes = historyEvents;
for (var j:int;j<eventsLength;j++) {
historyEvent = HistoryEventItem(historyEvents[j]);
//changesLength = changes ? changes.length: 0;
addItems = historyEvent.addItemsInstance;
action = historyEvent.action;
affectsDocument = dispatchForApplication && historyEvent.targets.indexOf(currentTargetDocument)!=-1;
if (action==RadiateEvent.ADD_ITEM) {
isInvalid = LayoutManager.getInstance().isInvalid();
if (isInvalid) {
LayoutManager.getInstance().validateNow();
LayoutManager.getInstance().isInvalid() ? Radiate.log.debug("Layout Manager is still invalid at note 4.") : 0;
}
// redo the add
addItems.apply(addItems.destination as UIComponent);
historyEvent.reversed = false;
if (dispatchEvents || (dispatchForApplication && affectsDocument)) {
instance.dispatchAddEvent(historyEvent.targets, [historyEvent.propertyChanges], historyEvent.properties);
}
}
else if (action==RadiateEvent.MOVE_ITEM) {
// redo the move
if (addItems) {
// RangeError: Index 2 is out of range.
// we must validate
isInvalid = LayoutManager.getInstance().isInvalid();
if (isInvalid) {
LayoutManager.getInstance().validateNow();
LayoutManager.getInstance().isInvalid() ? Radiate.log.debug("Layout Manager is still invalid at note 5") : 0;
}
addItems.apply(addItems.destination as UIComponent);
historyEvent.reversed = false;
if (dispatchEvents || (dispatchForApplication && affectsDocument)) {
instance.dispatchMoveEvent(historyEvent.targets, [historyEvent.propertyChanges], historyEvent.properties);
}
}
else {
applyChanges(historyEvent.targets, [historyEvent.propertyChanges], historyEvent.properties, historyEvent.styles,
setStartValues);
historyEvent.reversed = false;
if (dispatchEvents || (dispatchForApplication && affectsDocument)) {
instance.dispatchPropertyChangeEvent(historyEvent.targets, [historyEvent.propertyChanges], historyEvent.properties);
}
}
}
else if (action==RadiateEvent.REMOVE_ITEM) {
isInvalid = LayoutManager.getInstance().isInvalid();
if (isInvalid) {
LayoutManager.getInstance().validateNow();
LayoutManager.getInstance().isInvalid() ? Radiate.log.debug("Layout Manager is still invalid at note 6") : 0;
}
// redo the remove
addItems.remove(addItems.destination as UIComponent);
historyEvent.reversed = false;
remove = true;
if (dispatchEvents || (dispatchForApplication && affectsDocument)) {
instance.dispatchRemoveItemsEvent(historyEvent.targets, [historyEvent.propertyChanges], historyEvent.properties);
}
}
else if (action==RadiateEvent.PROPERTY_CHANGED) {
applyChanges(historyEvent.targets, [historyEvent.propertyChanges], historyEvent.properties, historyEvent.styles,
setStartValues);
historyEvent.reversed = false;
if (dispatchEvents || (dispatchForApplication && affectsDocument)) {
instance.dispatchPropertyChangeEvent(historyEvent.targets, [historyEvent.propertyChanges], historyEvent.properties);
}
}
}
historyItem.reversed = false;
// select target
if (selectTargetOnHistoryChange) {
if (remove) {
instance.setTargets(currentTargetDocument, true);
}
else {
instance.setTargets(historyEvent.targets, true);
}
}
if (eventsLength) {
historyIndex = getHistoryIndex();
if (dispatchEvents || (dispatchForApplication && affectsDocument)) {
instance.dispatchHistoryChangeEvent(historyIndex, currentIndex);
}
return changeIndex;
}
return historyLength;
}
/**
* Apply changes to targets. You do not call this. Set properties through setProperties method.
*
* @param setStartValues applies the start values rather
* than applying the end values
*
* @param property string or array of strings containing the
* names of the properties to set or null if setting styles
*
* @param style string or araray of strings containing the
* names of the styles to set or null if setting properties
* */
public static function applyChanges(targets:Array, changes:Array, property:*, style:*, setStartValues:Boolean=false):Boolean {
var length:int = changes ? changes.length : 0;
var effect:SetAction = new SetAction();
var onlyPropertyChanges:Array = [];
var directApply:Boolean = true;
var isStyle:Boolean = style && style.length>0;
for (var i:int;i<length;i++) {
if (changes[i] is PropertyChanges) {
onlyPropertyChanges.push(changes[i]);
}
}
effect.targets = targets;
effect.propertyChangesArray = onlyPropertyChanges;
if (isStyle) {
effect.property = style;
}
effect.relevantProperties = ArrayUtil.toArray(property);
effect.relevantStyles = ArrayUtil.toArray(style);
// this works for styles and properties
// note: the property applyActualDimensions is used to enable width and height values to stick
if (directApply) {
effect.applyEndValuesWhenDone = false;
effect.applyActualDimensions = false;
if (setStartValues) {
effect.applyStartValues(onlyPropertyChanges, targets);
}
else {
effect.applyEndValues(onlyPropertyChanges, targets);
}
// Revalidate after applying
LayoutManager.getInstance().validateNow();
}
// this works for properties but not styles
// the style value is restored at the end
else {
effect.applyEndValuesWhenDone = false;
effect.play(targets, setStartValues);
effect.playReversed = false;
effect.end();
LayoutManager.getInstance().validateNow();
}
return true;
}
/**
* Removes properties changes for null or same value targets
* @private
*/
public static function stripUnchangedValues(propChanges:Array):Array {
// Go through and remove any before/after values that are the same.
for (var i:int = 0; i < propChanges.length; i++) {
if (propChanges[i].stripUnchangedValues == false)
continue;
for (var prop:Object in propChanges[i].start) {
if ((propChanges[i].start[prop] ==
propChanges[i].end[prop]) ||
(typeof(propChanges[i].start[prop]) == "number" &&
typeof(propChanges[i].end[prop])== "number" &&
isNaN(propChanges[i].start[prop]) &&
isNaN(propChanges[i].end[prop])))
{
delete propChanges[i].start[prop];
delete propChanges[i].end[prop];
}
}
}
return propChanges;
}
/**
* Checks if changes are available.
* */
public static function changesAvailable(changes:Array):Boolean {
var length:int = changes.length;
var changesAvailable:Boolean;
var item:PropertyChanges;
var name:String;
for (var i:int;i<length;i++) {
if (!(changes[i] is PropertyChanges)) continue;
item = changes[i];
for (name in item.start) {
changesAvailable = true;
return true;
}
for (name in item.end) {
changesAvailable = true;
return true;
}
}
return changesAvailable;
}
//private static var _historyIndex:int = -1;
/**
* Selects the target on undo and redo
* */
public static var selectTargetOnHistoryChange:Boolean = true;
private static var _historyIndex:int = -1;
/**
* Current history index.
* The history index is the index of last applied change. Or
* to put it another way the index of the last reversed change minus 1.
* If there are 10 total changes and one has been reversed then
* we would be at the 9th change. The history index would
* be 8 since 9-1 = 8 since the array is a zero based index.
*
* value -1 means no history
* value 0 means one item
* value 1 means two items
* value 2 means three items
* */
[Bindable]
public static function get historyIndex():int {
return _historyIndex;
//var document:IDocument = instance.selectedDocument;
//return document ? document.historyIndex : -1;
}
/**
* @private
*/
public static function set historyIndex(value:int):void {
var document:IDocument = instance.selectedDocument;
if (document.historyIndex==value) {
//
}
else {
document.historyIndex = value;
}
_historyIndex = value;
var totalItems:int = history ?
history.length : 0;
var hasItems:Boolean = totalItems>0;
// has forward history
if (hasItems && historyIndex+1<totalItems) {
canRedo = true;
}
else {
canRedo = false;
}
// has previous items
if (hasItems && historyIndex>-1) {
canUndo = true;
}
else {
canUndo = false;
}
}
/**
* Indicates if undo is available
* */
[Bindable]
public static var canUndo:Boolean;
/**
* Indicates if redo is available
* */
[Bindable]
public static var canRedo:Boolean;
/**
* Get the index of the next item that can be undone.
* If there are 10 changes and one has been reversed the
* history index would be 8 since 10-1=9-1=8 since the array is
* a zero based index.
* */
public static function getPreviousHistoryIndex():int {
var document:IDocument = instance.selectedDocument;
var length:int = document.history.length;
var historyItem:HistoryEvent;
var index:int;
for (var i:int;i<length;i++) {
historyItem = document.history.getItemAt(i) as HistoryEvent;
if (historyItem.reversed) {
return i-1;
}
}
return length-1;
}
/**
* Get the index of the next item that can be redone in the history array.
* If there are 10 changes and one has been reversed the
* next history index would be 9 since 10-1=9-1=8+1=9 since the array is
* a zero based index.
* */
public static function getNextHistoryIndex():int {
var document:IDocument = instance.selectedDocument;
var length:int = document.history.length;
var historyItem:HistoryEvent;
var index:int;
// start at the beginning and find the next item to redo
for (var i:int;i<length;i++) {
historyItem = document.history.getItemAt(i) as HistoryEvent;
if (historyItem.reversed) {
return i;
}
}
return length;
}
/**
* Get history index
* */
public static function getHistoryIndex():int {
var document:IDocument = instance.selectedDocument;
var length:int = document ? document.history.length : 0;
var historyItem:HistoryEvent;
var index:int;
// go through and find last item that is reversed
for (var i:int;i<length;i++) {
historyItem = document.history.getItemAt(i) as HistoryEvent;
if (historyItem.reversed) {
return i-1;
}
}
return length-1;
}
/**
* Returns the history event by index
* */
public function getHistoryItemAtIndex(index:int):HistoryEvent {
var document:IDocument = instance.selectedDocument;
var length:int = document ? document.history.length : 0;
var historyItem:HistoryEvent;
// no changes
if (!length) {
return null;
}
// all changes have already been undone
if (index<0) {
return null;
}
// get change
historyItem = document.history.length ? document.history.getItemAt(index) as HistoryEvent : null;
return historyItem;
}
/**
* Given a target or targets, property name and value
* returns an array of PropertyChange objects.
* Points to createPropertyChanges()
*
* @see createPropertyChanges()
* */
public static function createPropertyChange(targets:Array, property:String, style:String, value:*, description:String = ""):Array {
var values:Object = {};
var changes:Array;
if (property) {
values[property] = value;
}
else if (style) {
values[style] = value;
}
changes = createPropertyChanges(targets, ArrayUtil.toArray(property), ArrayUtil.toArray(style), values, description, false);
return changes;
}
/**
* Given a target or targets, properties and value object (name value pair)
* returns an array of PropertyChange objects.
* Value must be an object containing the properties mentioned in the properties array
* */
public static function createPropertyChanges(targets:Array, properties:Array, styles:Array, value:Object, description:String = "", storeInHistory:Boolean = true):Array {
var tempEffect:SetAction = new SetAction();
var propertyChanges:PropertyChanges;
var changes:Array;
var propertyOrStyle:String;
var isStyle:Boolean = styles && styles.length>0;
tempEffect.targets = targets;
tempEffect.property = isStyle ? styles[0] : properties[0];
tempEffect.relevantProperties = properties;
tempEffect.relevantStyles = styles;
// get start values for undo
changes = tempEffect.captureValues(null, true);
// This may be hanging on to bindable objects
// set the values to be set to the property
// ..later - what??? give an example
for each (propertyChanges in changes) {
// for properties
for each (propertyOrStyle in properties) {
// value may be an object with properties or a string
// because we accept an object containing the values with
// the name of the properties or styles
if (value && propertyOrStyle in value) {
propertyChanges.end[propertyOrStyle] = value[propertyOrStyle];
}
else {
propertyChanges.end[propertyOrStyle] = value;
}
}
// for styles
for each (propertyOrStyle in styles) {
// value may be an object with properties or a string
// because we accept an object containing the values with
// the name of the properties or styles
if (value && propertyOrStyle in value) {
propertyChanges.end[propertyOrStyle] = value[propertyOrStyle];
}
else {
propertyChanges.end[propertyOrStyle] = value;
}
}
}
// we should move this out
// add property changes array to the history dictionary
if (storeInHistory) {
return createHistoryEvents(targets, changes, properties, styles, value, description);
}
return [propertyChanges];
}
private static var _disableHistoryManagement:Boolean;
/**
* Disables history management. We do this when importing documents since
* it creates the document 5x faster.
* */
public static function get disableHistoryManagement():Boolean {
return _disableHistoryManagement;
}
/**
* @private
*/
[Bindable(event="disableHistoryManagement")]
public static function set disableHistoryManagement(value:Boolean):void {
if (_disableHistoryManagement == value) return;
_disableHistoryManagement = value;
}
/**
* Creates a history event in the history
* Changes can contain a property or style changes or add items
* */
public static function createHistoryEvents(targets:Array, changes:Array, properties:*, styles:*, value:*, description:String = null, action:String=RadiateEvent.PROPERTY_CHANGED, remove:Boolean = false):Array {
var factory:ClassFactory = new ClassFactory(HistoryEventItem);
var historyEvent:HistoryEventItem;
var events:Array = [];
var reverseAddItems:AddItems;
var change:Object;
var length:int;
if (disableHistoryManagement) return [];
// create property change objects for each
for (var i:int;i<changes.length;i++) {
change = changes[i];
historyEvent = factory.newInstance();
historyEvent.action = action;
historyEvent.targets = targets;
historyEvent.description = description;
// check for property change or add display object
if (change is PropertyChanges) {
historyEvent.properties = ArrayUtil.toArray(properties);
historyEvent.styles = ArrayUtil.toArray(styles);
historyEvent.propertyChanges = PropertyChanges(change);
}
else if (change is AddItems && !remove) {
historyEvent.addItemsInstance = AddItems(change);
length = targets.length;
// trying to add support for multiple targets - it's not all there yet
// probably not the best place to get the previous values or is it???
for (var j:int=0;j<length;j++) {
historyEvent.reverseAddItemsDictionary[targets[j]] = createReverseAddItems(targets[j]);
}
}
else if (change is AddItems && remove) {
historyEvent.removeItemsInstance = AddItems(change);
length = targets.length;
// trying to add support for multiple targets - it's not all there yet
// probably not the best place to get the previous values or is it???
for (j=0;j<length;j++) {
historyEvent.reverseRemoveItemsDictionary[targets[j]] = createReverseAddItems(targets[j]);
}
}
events[i] = historyEvent;
}
return events;
}
/**
* Creates a remove item from an add item.
* */
public static function createReverseAddItems(target:Object):AddItems {
var elementContainer:IVisualElementContainer;
var position:String = AddItems.LAST;
var visualElement:IVisualElement;
var reverseAddItems:AddItems;
var elementIndex:int = -1;
var propertyName:String;
var destination:Object;
var description:String;
var relativeTo:Object;
var vectorClass:Class;
var isStyle:Boolean;
var isArray:Boolean;
var index:int = -1;
if (!target) return null;
// create add items with current values we can revert back to
reverseAddItems = new AddItems();
reverseAddItems.destination = target.parent;
reverseAddItems.items = target;
destination = reverseAddItems.destination;
visualElement = target as IVisualElement;
// set default
if (!position) {
position = AddItems.LAST;
}
// Check for non basic layout destination
// if destination is not a basic layout
// find the position and set the relative object
if (destination is IVisualElementContainer
&& destination.numElements>0) {
elementContainer = destination as IVisualElementContainer;
index = elementContainer.getElementIndex(visualElement);
if (elementContainer is GroupBase
&& !(GroupBase(elementContainer).layout is BasicLayout)) {
// add as first item
if (index==0) {
position = AddItems.FIRST;
}
// get relative to object
else if (index<=elementContainer.numElements) {
// if element is already child of container account for remove of element before add
if (visualElement && visualElement.parent == destination) {
elementIndex = destination.getElementIndex(visualElement);
index = elementIndex < index ? index-1: index;
if (index<=0) {
position = AddItems.FIRST;
}
else {
relativeTo = destination.getElementAt(index-1);
position = AddItems.AFTER;
}
}
// add as last item
else if (index>=destination.numElements) {
position = AddItems.LAST;
}
// add after first item
else if (index>0) {
relativeTo = destination.getElementAt(index-1);
position = AddItems.AFTER;
}
}
}
}
reverseAddItems.destination = destination;
reverseAddItems.position = position;
reverseAddItems.relativeTo = relativeTo;
reverseAddItems.propertyName = propertyName;
reverseAddItems.isArray = isArray;
reverseAddItems.isStyle = isStyle;
reverseAddItems.vectorClass = vectorClass;
return reverseAddItems;
}
/**
* Stores a history event in the history events dictionary
* Changes can contain a property changes object or add items object
* */
public static function removeHistoryEvent(changes:Array):void {
var historyEvent:HistoryEventItem;
var change:Object;
// delete change objects
for each (change in changes) {
historyEventsDictionary[change] = null;
delete historyEventsDictionary[change];
}
}
/**
* Adds property change items to the history array
* */
public static function addHistoryItem(historyEventItem:HistoryEventItem, description:String = null):void {
addHistoryEvents(ArrayUtil.toArray(historyEventItem), description);
}
/**
* Adds property change items to the history array
* */
public static function addHistoryEvents(historyEvents:Array, description:String = null):void {
var document:IDocument = instance.selectedDocument;
var historyEvent:HistoryEvent;
var currentIndex:int = getHistoryIndex();
var length:int = document ? document.history.length : 0;
var historyTargets:Array;
if (disableHistoryManagement) return;
history.disableAutoUpdate();
// trim history
if (currentIndex!=length-1) {
for (var i:int = length-1;i>currentIndex;i--) {
historyEvent = document.history.removeItemAt(i) as HistoryEvent;
historyEvent.purge();
}
}
historyEvent = new HistoryEvent();
historyEvent.description = description ? HistoryEventItem(historyEvents[0]).description : description;
historyEvent.historyEventItems = historyEvents;
// we should remember to remove these references when truncating history
for (i=0;i<historyEvents.length;i++) {
historyTargets = HistoryEventItem(historyEvents[i]).targets;
for (var j:int=0;j<historyTargets.length;j++) {
if (historyEvent.targets.indexOf(historyTargets[j])==-1) {
historyEvent.targets.push(historyTargets[j]);
}
}
}
document.history.addItem(historyEvent);
document.historyIndex = getHistoryIndex();
document.history.enableAutoUpdate();
document.historyIndex = getHistoryIndex();
historyIndex = getHistoryIndex();
instance.dispatchHistoryChangeEvent(currentIndex+1, currentIndex);
}
/**
* Removes property change items in the history array
* */
public static function removeHistoryItem(changes:Array):void {
var document:IDocument = instance.selectedDocument;
var currentIndex:int = getHistoryIndex();
var itemIndex:int = document.history.getItemIndex(changes);
if (itemIndex>0) {
document.history.removeItemAt(itemIndex);
}
document.historyIndex = getHistoryIndex();
historyIndex = getHistoryIndex();
instance.dispatchHistoryChangeEvent(currentIndex-1, currentIndex);
}
/**
* Removes all history in the history array.
* Note: We should set the changes to null.
* */
public static function removeAllHistory():void {
var document:IDocument = instance.selectedDocument;
var currentIndex:int = getHistoryIndex();
document.history.removeAll();
document.history.refresh(); // we should loop through and run purge on each HistoryItem
instance.dispatchHistoryChangeEvent(-1, currentIndex);
}
/**
* Returns true if two objects are of the same class type
* */
public function isSameClassType(target:Object, target1:Object):Boolean {
return ClassUtils.isSameClassType(target, target1);
}
}
}
class SINGLEDOUBLE{}