Locking FLA’s under version control

We’ve recently moved over to SVN as our version control system. This system, among other features allows you to request a lock on specific files checked out from the version control system. This means nobody else on your team can check that file in until you have either finished editing and checked it in, or released the lock.

When it comes to FLA files this is great, as unlike actionscript source code, FLA files cannot be automatically merged and so having two people working on the same FLA at the same time creates all kinds of problems, with lost hours, and even lost work.

The problem with optional locking, is that you may not know a file has been locked until you go to check it in, at which point you may have worked on it for hours and so we are presented with the same problem, having to manually merge two versions of the same FLA file.

SVN solves this by allowing you to set the property svn:needs-lock on any file. This means that when a user checks the file out they receive it as read only, and to make it writeable they need to request a lock for the file, at which point their SVN client notifies them that somebody else has the file locked so they need to request that person checks the file in. It also allows you to set auto-props, which are properties to apply to all files of a certain type that are checked into the system. In our case any .FLA files.

This falls down in one respect though. If you are not opening the file from windows explorer (in the case of tortoiseSVN) where you would see the grey icon indicating that a file is read only, but rather from your IDEs recent documents menu, or from a tool that provides a different view to the file system such as FlashDevelop, it relies on whatever tool you use to edit that file telling you that a file is read only. Unfortunately Flash does not warn you when you open a read only FLA. It just opens the “save as” dialog when you try to save the file. This a potential point where you could be facing a file merge, or even worse, lost work.

To get around this I’ve put together a JSFL script that detects when you open a file and examines it’s properties for the read only attribute, then pops up a warning to get a lock from SVN before working on it. Hope people out there find this useful. To use it you need to save it to C:\Documents and Settings\username\Local Settings\Application Data\Adobe\Flash CS3\en\Configuration\Tools\checkReadOnly.jsfl

you can download it here

/**
* Check read only script
* Warns you about opening read only files in Flash IDE
* By Phil Douglas 2008
* www.lookmumimontheinternet.com
**/
fl.outputPanel.clear();
trace = fl.outputPanel.trace;
function onDocumentOpened(){
var currentDoc = fl.getDocumentDOM();
nativePath = currentDoc.path;
uriPath = nativePath.split(':').join('|');
uriPath = uriPath.split("\").join("/");
uriPath = 'file:///'+uriPath
attributes = FLfile.getAttributes(uriPath)
if(attributes.indexOf('R')!=-1){
alert('This file is read only. If it is in SVN you should request a lock before working on it.');
}
}
fl.removeEventListener("documentOpened", onDocumentOpened);
fl.addEventListener("documentOpened", onDocumentOpened);

42 comments April 17th, 2008

WebDu 2007 slides and notes

You can download the slides and notes from my talk on e-learning here

I’ll be writing a wrap up of the conference soon, but it’s amazing how much work piles up in two days away from the office. :P

2 comments March 27th, 2007

Speaking at WebDU 2007

I’ve now been officially announced on the list of speakers for this years WebDu conference. It’s totally exciting, and also my first time presenting at this type of thing, so should be a heap of fun (and fear).

I’m doing a session on E-learning from a developers perspective. Covering some things that will hopefully be new to people from a normal web dev background, and sharing a few things that i learned the hard way. You can find out more about the session here.

It’s amazing to be involved in something that attracts so many awesome people. Make sure you grab me to say hi even if you don’t see the session itself.

7 comments January 10th, 2007

Another flashden file approved - MP3 player

Just a quick one. Flashden have approved another of my items for sale, a skinnable XML driven Mp3 player. Enjoy you crazy disco kids!

2 comments November 20th, 2006

Flashden goes official

Flashden has finally removed the beta from their name. Time to load up on stock flash. You see my creations on my portfolio page.

November 1st, 2006

Design pattern wanted.

Calling all design pattern gurus. I’ve got a challenge for all you object orientated persons. I’m currently working on an actionscript component framework, that includes modal behaviour. That is if a component is modal, when it is enabled, all other components are disabled. Think of an alert box that doesn’t allow you to progress through an application until you’ve chosen an option and you’ll see what i’m trying to achieve.

I’ve actually got this all working fine. My only reservation is that the solution i’ve come up with seems a bit clunky. Anyway on with the show. I’ll detail all the steps in the creation, with pseudo-code examples.

The basis for all this is the component class, which all my other components will inherit from. It has enable, and disable public functions.

 class com.lookmum.view.Component{
//enable function
public function enable(){
//enable component code here
}

//disable function
public function disable(){
//disable component code here
}
} 

Next comes the creation of the modal manager class. This is a singleton which all components will register with when they become enabled, and unregister from when disabling. It also includes methods to enable and disable all active components. Here’s the relevent parts of the class shown with pseudo-code

class com.lookmum.util.ModalManager
{
// the list of all enabled components
private var componentList : Array
//the list of all components that this class has disabled, stored ready for re-enabling
private var disabledList : Array
public function registerComponent (com : Component) : Void
{
//add a component to the active list
}
public function unregisterComponent (com : Component) : Void
{
//remove a component from the active list
}
public function disableModal () : Void
{
//disable all active components and add them to the disabled list
this.disabledList.push ([])
var currentLayer : Number = this.disabledList.length - 1

{
if (this.componentList [i].enabled)
{
this.componentList [i].disable ()
this.disabledList [currentLayer].push (this.componentList [i])
}
}
}
public function enableModal (forceAll : Boolean) : Void
{
//enable the last disabled batch of components and put them back into the enabled list
var currentLayer : Number = this.disabledList.length - 1
var currentLayerLength : Number = this.disabledList [this.disabledList.length - 1].length

{
this.disabledList [currentLayer][i].enable ()
}
this.disabledList.pop ()
}
}

We then revise the component class to register itself with the singleton on enable, and unregister on disable.

import com.lookmum.util.ModalManager
class com.lookmum.view.Component{
private var modalManager:ModalManager
//constructor function
public function Component(){
//get a reference to the modal manager singleton
this.modalManager = ModalManager.getInstance()
}
//enable function
public function enable(){
//register the component with the modal manager
this.modalManager.registerComponent(this)
//enable component code here
}
//disable function
public function disable(){
//unregister the component from the modal manager
this.modalManager.unregisterComponent(this)
//disable component code here
}
}

Our immediate problem is that the enable functions affect registration with the singleton, so we need to test wether it is the singleton doing the enabling, and not to register/unregister if it is. The quickest thing to do is to pass an argument to the enable functions telling the component that the function is being called by the manager.

//the modified enable modal function in modal manager
public function enableModal (forceAll : Boolean) : Void
{
//enable the last disabled batch of components and put them back into the enabled list
var currentLayer : Number = this.disabledList.length - 1
var currentLayerLength : Number = this.disabledList [this.disabledList.length - 1].length

{
this.disabledList [currentLayer][i].enable (true)
}
this.disabledList.pop ()
}

and…

//the modified enable function
public function enable(modal:Boolean){
if(modal){
//register the component with the modal manager
this.modalManager.registerComponent(this)
}
//enable component code here
} 

The main problem with this approach is that we are making what should be internal behaviour public. There’s no way to enforce that the boolean value will only be passed by the manager.

Another approach would be to have a pair of enable functions, enable() and modalEnable(). One for general use which performs the registration, and one for use by the manager. However this still makes public something that should happen behind the scenes. There’s nothing to stop another developer accidentally using modalEnable() instead of enable()

The solution I came up with was to have this second enable function, but make it a private member. I then create a function delegate within the normal enable function and pass it to the modal manager with the component registration.

//the modified enable function
public function enable(){
//register the component with the modal manager and pass a function delegate as a scond parameter
this.modalManager.registerComponent(this,mx.utils.Delegate.create(this,this.modalEnable())
}
doEnable()
} 	private function doEnable(){
//enable component code here
} 

We then give the manager event dispatching behaviours and let it add and remove the listeners itself.

public function disableModal () : Void
{
this.disabledList.push ([])
var currentLayer : Number = this.disabledList.length - 1
var dispatchList:Array = new Array()
for (var i = 0; i < this.componentList.length; i ++)
{
if (this.componentList [i][0].enabled)
{
dispatchList.push(this.componentList [i][1])
this.disabledList [currentLayer].push (this.componentList [i])
}
}
for (var i:Number = 0; i
this.addEventListener(DISABLE,dispatchList[i])
}
this.dispatchEvent(new Event(DISABLE,this))
for (var i:Number = 0; i
this.removeEventListener(DISABLE,dispatchList[i])
}
}

What i really want is some way to make a method of a class A only available to instances of another class B, bearing in mind that these two classes are unrelated, and i want any errors to be compile time, which means doing fancy things with arguments.caller isn’t quite what i want.

Any ideas anyone, or am i just being a pedant?

5 comments October 18th, 2006

Particle Playground

I finally released my finished particle simulation extension for flash7+. You can purchase it from flashden here for a mere 10 bones.

October 17th, 2006

Featured item on flashden (with thoughts on wallop)

A simple little extension I created for flashden is currently a featured item. This site rocks. It allows me to package up little utilities i created for other jobs and sell them for a few bucks without the hassle of setting up my own on-line store.

This got me thinking about microsofts new myspace competitor wallop. A few people have pointed out that you can make quick cash from creating little widgets for the site. But i wonder if this is really such a great idea. The fact that you need to invest the development time for such items, coupled with the rather large API you need to learn in order to implement widgets for the site, seems to suggest that you need to ship a lot of units before you see any return on the time you’ve invested. And i’m not event sure how many people are actually using wallop.
Compare this to flashden where all i have to do is package things i’ve already developed, and i think it’s easy to see that there’s better ways to spend your time.

2 comments October 10th, 2006

Holiday snaps

People and police on the beach

I finally got round to uploading some of my holiday pictures to flickr. You can see them as a slide show here.

When I get some free time, I’ll hopfully be integrating my flickr account into this site, so you can view the pictures here.

1 comment August 24th, 2006

Actionscript: The rules #2 - Observer pattern for all events

All classes that generate events should do so via the observer pattern.

This one might prove a little more contravertial than the last, but i’m going to stick my neck out and say that all classes should use the observer pattern for events, rather than myEvent=function() callbacks, or object listeners.

For those who don’t want to read up about the observer pattern check out the EventDispatcher class which is basically an implementation of this. or better still grant skinners GDispatcher which has a few extra tricks up its sleeve. The first benefit of this method is that you can have multiple objects listening to the same event. This is all covered in the chapter on the observer pattern in Colin Moocks Essential ActionScript 2. If you want to start using these classes i suggest you read the tutorials on EventDispatcher and Delegate over at actionscript.org.

I also tend to use Dynamic flash’s Delegate class rather than macromedias own for scoping the listener object, as this also has a few added extras, such as passing the delegate itself to a listening function, as well as the event object, which makes removal of anonymous delegates an easy task.

This may sound like overkill for a lot of simple class structures, and you will have to remember to remove your event listeners, but it does mean consistency. If you’re using EventDispatcher in one class, and myEvent=function() style callbacks in another, then it’s easier to make mistakes. And harder to pick up code that you havent looked at in a while, because you have to figure out which method you used.

When using EventDispatcher it’s always useful to include static constant variable strings (try saying that 10 times quickly) for all the events a class will dispatch. This not only lets you keep track of which events a class broadcasts easily, but also provides compile time checking to make sure you are subscribing to events that actually exist. For example:

import com.gskinner.event.GDispatcher
class com.lookmum.Broadcaster{
public static var MYEVENT:String = ‘myEvent’
public var addEventListener:Function
public var removeEventListener:Function
public var dispatchEvent:Function
public function Broadcaster(){
GDispatcher.initialize(this)
}
public function myFunction(){
this.dispatchEvent({type:MYEVENT,target:this})
}
}

and…

import com.lookmum.Broadcaster
import com.dynamicflash.utils.Delegate
class com.lookmum.Observer{
private var broadcaster:Broadcaster
public function Observer(){
this.broadcaster = new Broadcaster
this.broadcaster.addEventListener(Broadcaster.MYEVENT, Delegate.create(this, this.eventHandler))
}
public function myFunction(){
this.broadcaster.myFunction()
}
private function eventHandler(){
trace(’event handled’)
}
}

Two added benefits are that this makes it easy to document events because you can attach javadoc comments to the string constants and they stand out from other class members so events are easy to find rather than function callbacks which apart from their names look just like empty functions.

This is all very similar to the way events are used in AS3 and so if you can get used to using this methodology now, then the transition should be that much easier. In fact another useful methodology that AS3 uses is the use of a proper Event class, as the event object rather than using a standard object, which makes it easier to keep track of what properties your event object will hold.

1 comment June 9th, 2006

Previous Posts



Categories

Links

Feeds









The-Brights.net

flashden

Check Page Ranking