PageRenderTime 79ms CodeModel.GetById 71ms app.highlight 3ms RepoModel.GetById 1ms app.codeStats 0ms

/src/org/ishafoundation/archives/transcript/components/studio/MainPanel.mxml

http://transcriptstudio4isha.googlecode.com/
Macromedia eXtensible Markup Language | 637 lines | 592 code | 45 blank | 0 comment | 0 complexity | b697faa74052a155cbd595e77409da78 MD5 | raw file
  1<!--
  2   Transcript Studio for Isha Foundation: An XML based application that allows users to define 
  3   and store contextual metadata for contiguous sections within a text document. 
  4
  5   Copyright 2008 Mark Carter, Swami Kevala
  6
  7   This file is part of Transcript Studio for Isha Foundation.
  8
  9   Transcript Studio for Isha Foundation is free software: you can redistribute it and/or modify it 
 10   under the terms of the GNU General Public License as  published by the Free Software 
 11   Foundation, either version 3 of the License, or (at your option) any later version.
 12
 13   Transcript Studio for Isha Foundation is distributed in the hope that it will be useful, but 
 14   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 15   FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 16
 17   You should have received a copy of the GNU General Public License along with 
 18   Transcript Studio for Isha Foundation. If not, see http://www.gnu.org/licenses/.
 19-->
 20
 21<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:studioNS="org.ishafoundation.archives.transcript.components.studio.*" width="100%" height="100%" verticalGap="0" keyDown="keyDownHandler(event)">
 22	<mx:Script>
 23		<![CDATA[
 24			import mx.events.FlexEvent;
 25			import org.ishafoundation.archives.transcript.model.Transcript;
 26			import org.ishafoundation.archives.transcript.model.TranscriptTextSelection;
 27			import com.ericfeminella.collections.HashMap;
 28			import com.ericfeminella.collections.IMap;
 29			import mx.events.PropertyChangeEvent;
 30			import org.ishafoundation.archives.transcript.components.studio.importer.TranscriptsToImportSelectorDialog;
 31			import org.ishafoundation.archives.transcript.components.studio.importer.ImportDialog;
 32			import mx.utils.StringUtil;
 33			import mx.managers.CursorManager;
 34			import org.ishafoundation.archives.transcript.components.studio.session.SessionSelectorDialog;
 35			import org.ishafoundation.archives.transcript.components.studio.OpenDialog;
 36			import org.ishafoundation.archives.transcript.components.studio.OpenByIdDialog;
 37			import org.ishafoundation.archives.transcript.util.ApplicationUtils;
 38			import org.ishafoundation.archives.transcript.db.DatabaseConstants;
 39			import org.ishafoundation.archives.transcript.importer.MSWordImporter;
 40			import name.carter.mark.flex.util.XMLUtils;
 41			import name.carter.mark.flex.util.Utils;
 42			import name.carter.mark.flex.util.icon.IconUtils;
 43			import org.ishafoundation.archives.transcript.components.generic.UnhandledChangesPopUpManager;
 44			import org.ishafoundation.archives.transcript.db.DatabaseManagerUtils;
 45			import mx.controls.Alert;
 46			import org.ishafoundation.archives.transcript.components.generic.AboutBox;
 47			import org.ishafoundation.archives.transcript.components.studio.session.SessionMetadataEditorDialog;
 48			import org.ishafoundation.archives.transcript.model.SessionMetadata;
 49			import org.ishafoundation.archives.transcript.model.SessionManager;
 50			import org.ishafoundation.archives.transcript.model.ReferenceManager;
 51			import mx.managers.PopUpManager;
 52			import name.carter.mark.flex.project.mdoc.*;
 53			import org.ishafoundation.archives.transcript.components.studio.media.MediaPlayerDialog;
 54			import org.ishafoundation.archives.transcript.components.studio.event.EventMetadataEditorDialog;
 55			import org.ishafoundation.archives.transcript.model.EventMetadata;
 56			import org.ishafoundation.archives.transcript.components.generic.DebugPopUp;
 57			import org.ishafoundation.archives.transcript.components.studio.concept.ConceptManagerDialog;
 58			import org.ishafoundation.archives.transcript.components.studio.category.CategoryManagerDialog;
 59			import org.ishafoundation.archives.transcript.model.Session;
 60			import mx.events.MenuEvent;
 61			import mx.events.CloseEvent;
 62			import org.ishafoundation.archives.transcript.db.DatabaseManager;
 63
 64			[Bindable]
 65			public var databaseMgr:DatabaseManager;
 66
 67			[Bindable]			
 68			private var referenceMgr:ReferenceManager;
 69
 70			[Bindable]
 71			private var sessionMgr:SessionManager;
 72			
 73			[Bindable]
 74			private var session:Session;
 75			
 76			private static const DEFAULT_TITLE:String = ApplicationUtils.getApplicationName();
 77			
 78			[Bindable]
 79			public var title:String = DEFAULT_TITLE;
 80			
 81			[Bindable]
 82			public var status:String;
 83			
 84			public function init(username:String, databaseMgr:DatabaseManager):void {
 85				IconUtils.overrideIcon(Utils.DEFAULT_ICON_PATH, Utils.DEFAULT_ICON_CLASS);
 86				this.databaseMgr = databaseMgr;
 87				this.referenceMgr = new ReferenceManager(databaseMgr);
 88				this.sessionMgr = new SessionManager(username, referenceMgr, databaseMgr);
 89				this.referenceMgr.loadReferences(referenceXMLRetrieveSuccess, referenceXMLRetrieveFailure);
 90			}
 91			
 92			private static const KEYBOARD_SHORTCUT_MODIFIER:String = "ctrlKey";
 93			/** key is charCode, value is actionName */
 94			private static const KEYBOARD_SHORTCUT_MAP:IMap = createKeyboardShortcutMap();		
 95			private static function createKeyboardShortcutMap():IMap {
 96				var result:IMap = new HashMap();
 97				result.put("m", "markupText")
 98				return result;
 99			}
100		
101			protected override function keyDownHandler(evt:KeyboardEvent):void {
102				if (evt[KEYBOARD_SHORTCUT_MODIFIER]) {
103					var keyStr:String = String.fromCharCode(evt.charCode);
104					var actionName:String = KEYBOARD_SHORTCUT_MAP.getValue(keyStr);
105					if (actionName != null) {
106						var menuItemElement:XML = menuData..*.(hasOwnProperty("@id") && @id == actionName)[0]
107						if (menuItemElement.@enabled == "true") {
108							trace("Keyboard shortcut: " + KEYBOARD_SHORTCUT_MODIFIER + "-" + keyStr);
109							onMenuClick(menuItemElement);
110							evt.preventDefault();
111							return;
112						}
113					}
114				}
115				super.keyDownHandler(evt);				
116			}
117			
118			private function referenceXMLRetrieveSuccess():void {
119				this.status = "References loaded";
120			}
121			
122			private static function referenceXMLRetrieveFailure(msg:String):void {
123				throw new Error(msg);
124			}
125			
126			public function openClicked():void {
127				showUnsavedChangesPopupIfNecessary(showOpenDialog);
128			}
129			
130			public function openByIdClicked():void {
131				showUnsavedChangesPopupIfNecessary(showOpenByIdDialog);
132			}
133			
134			private function managerClicked(openManagerFunc:Function):void {
135				if (this.session != null && this.session.unsavedChanges) {
136					// confirm this operation with the user
137					Alert.show("Save session?", "Unsaved changes...", Alert.YES | Alert.NO | Alert.CANCEL, null, function(evt:CloseEvent):void {
138						if (evt.detail == Alert.YES) {
139							storeSession(openManagerFunc);
140						}
141						else if (evt.detail == Alert.NO) {
142							// dont save (but dont have to really lose the changes just yet
143							openManagerFunc();
144						}
145					});
146				}
147				else {
148					openManagerFunc();
149				}
150			}
151			
152			private function openCategoryManager():void {				
153				var thisRef:DisplayObject = this;
154				reloadReferencesBeforeContinuing(function():void {
155					var categoryManagerDialog:CategoryManagerDialog = new CategoryManagerDialog();
156					categoryManagerDialog.referenceMgr = referenceMgr;
157					PopUpManager.addPopUp(categoryManagerDialog, thisRef, true);
158					categoryManagerDialog.doneButton.addEventListener(MouseEvent.CLICK, function(evt:MouseEvent):void {
159						// finished with the dialog box so reload transcript (because changes may have been made during the dialog
160						reloadSession();
161					});
162					var selectedMarkupProps:MSuperNodeProperties = transcriptPane.markupsPane.selectedMarkupProps;
163					if (selectedMarkupProps != null) {
164						categoryManagerDialog.categorySearchPane.initialCategoryId = selectedMarkupProps.markupCategoryId;
165					}
166				});
167			}
168			
169			private function openConceptManager():void {
170				var thisRef:DisplayObject = this;
171				reloadReferencesBeforeContinuing(function():void {
172					var conceptManagerDialog:ConceptManagerDialog = ConceptManagerDialog.createInstance(referenceMgr);
173					PopUpManager.addPopUp(conceptManagerDialog, thisRef, true);
174					conceptManagerDialog.okButton.addEventListener(MouseEvent.CLICK, function(evt:MouseEvent):void {
175						// finished with the dialog box so reload transcript (because changes may have been made during the dialog
176						reloadSession();
177					});
178				});
179			}
180			
181			private function queryClicked():void {
182				var queryExecutorDialog:XQueryExecutorDialog = new XQueryExecutorDialog();
183				queryExecutorDialog.xQueryExecutor = databaseMgr;
184				PopUpManager.addPopUp(queryExecutorDialog, this, true);
185			}
186			
187			private function showUnsavedChangesPopupIfNecessary(successFunction:Function):void {
188				UnhandledChangesPopUpManager.displayIfNecessaryUsingAsyncFunc(this.session != null && this.session.unsavedChanges, storeSession, storeSessionFailure, successFunction); 
189			}
190			
191			private function showOpenDialog():void {
192				var popup:OpenDialog = OpenDialog.display(this, databaseMgr, referenceMgr);
193				popup.addEventListener(OpenDialog.OPEN_SESSION_REQUEST, function(evt:Event):void {
194					var sessionId:String = popup.selectedSessionId;
195					CursorManager.setBusyCursor();
196					// first update the reference file - continue even if it fails
197					reloadReferencesBeforeContinuing(function():void {
198						sessionMgr.retrieveSession(sessionId, popup.eventSelectorPane.selectedEventMetadata, openSessionSuccess, openSessionFailure);
199					});					
200				});
201			}
202			
203			private function showOpenByIdDialog():void {
204				var popup:OpenByIdDialog = new OpenByIdDialog();
205				PopUpManager.addPopUp(popup, this, true);
206				popup.okButton.addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void {
207					trace("Retrieving event/session using id: " + popup.enteredId);
208					// id is of the form: <event/session id>[#<markup/paragraph id>] (i.e. the last part is optional)
209					// examples: 20090329-n1-1-1800, 20090329-n1-1-1800#p12
210					var hashIndex:int = popup.enteredId.indexOf('#');
211					var docId:String = hashIndex < 0 ? popup.enteredId : popup.enteredId.substring(0, hashIndex);
212					var nodeId:String = hashIndex < 0 ? null : popup.enteredId.substring(hashIndex + 1);
213					reloadReferencesBeforeContinuing(function():void {
214						databaseMgr.retrieveXML(function(docXML:XML):void {
215							if (docXML == null) {
216								Alert.show("No document exists with id: " + docId);
217							}
218							else if (docXML.localName() == "event") {
219								var eventMetadata:EventMetadata = EventMetadata.createInstance(docXML);
220								SessionSelectorDialog.displayIfNecessary(eventMetadata, popup, databaseMgr, function(sessionMetadata:SessionMetadata):void {
221									sessionMgr.retrieveSession(sessionMetadata.sessionId, eventMetadata, openSessionSuccess, openSessionFailure);
222									popup.closeMe();
223								});
224							}
225							else if (docXML.localName() == "session") {
226								// first we need to get the event props
227								var sessionMetadata:SessionMetadata = SessionMetadata.createInstanceFromSessionXML(docXML);
228								trace("Opening session based on session XML already in memory");
229								DatabaseManagerUtils.retrieveEventXML(sessionMetadata.eventId, databaseMgr, function(eventXML:XML):void {
230									var eventMetadata:EventMetadata = EventMetadata.createInstance(eventXML);
231									var session:Session = new Session(docXML, eventMetadata, referenceMgr);
232									openSessionSuccess(session);
233									popup.closeMe();
234									// the nodeId might refer to a markup or something
235									if (nodeId != null && nodeId.length > 0) {
236										callLater(function():void {
237											var node:MNode = session.transcript.mdoc.resolveId(nodeId);
238											if (node == null) {
239												Alert.show("Could not find document internal id: " + nodeId);
240												return;
241											}
242											if (node is MSuperNode) {
243												transcriptPane.markupsPane.selectedMarkup = node as MSuperNode;
244												transcriptPane.textPane.selectMarkup(node as MSuperNode);
245											}
246											else {
247												var newSelection:TranscriptTextSelection = new TranscriptTextSelection(node);
248												transcriptPane.textPane.select(newSelection);
249											}
250										});
251									}								
252								}, function(msg:String):void {
253									Alert.show(msg, "Could not open session");
254								});
255							}
256							else {
257								Alert.show("Unknown xml doc type: " + docXML.localName());
258							}
259						}, function(msg:String):void {
260							Alert.show(msg, "Could not retrieve document using id: " + docId);						
261						}, null, docId, "/db/ts4isha/data");
262					});
263				});
264			}
265			
266			private function reloadReferencesBeforeContinuing(nextFunc:Function):void {
267				this.referenceMgr.loadReferences(nextFunc, function(msg:String):void {
268					Alert.show("Could not reload reference file: " + msg);
269				});				
270			}
271
272			private function openSessionSuccess(session:Session):void {
273				this.session = session;
274				this.transcriptPane.transcript = session.transcript;
275				this.status = "Successfully loaded transcript";
276				updateTitle();
277				CursorManager.removeBusyCursor();
278			}
279			
280			private function openSessionFailure(msg:String):void {
281				try {
282					if (msg.indexOf("document not found") >= 0) {
283						// exist message includes this phrase
284						Alert.show("Transcript not found", "Error loading transcript");
285					}
286					else {
287						var index:int = msg.indexOf("PermissionDeniedException:");
288						if (index >= 0) {
289							Alert.show(msg.substr(index + 26), "Error loading transcript");
290						}
291						else {
292							throw new Error(msg);
293						}				
294					}
295				}
296				finally {
297					CursorManager.removeBusyCursor();					
298				}
299			}
300			
301			private function storeSession(successFunc:Function = null, failureFunc:Function = null):void {
302				this.sessionMgr.updateSessionInDatabase(session, function():void {
303					storeSessionSuccess();
304					if (successFunc != null) {
305						successFunc();
306					}
307				}, function(msg:String):void {
308					storeSessionFailure(msg);
309					if (failureFunc != null) {
310						failureFunc(msg);
311					}
312				});
313			}
314			
315			private function storeSessionSuccess():void
316			{
317				this.status = "Successfully saved transcript";
318				this.session.saveChangesHandler();
319				var selectedMarkup:MSuperNode = this.transcriptPane.markupsPane.selectedMarkup;
320				// this is primarily to refresh the "committedMarkup" in the propertiesPane
321				if (selectedMarkup != null) {
322					this.transcriptPane.markupsPane.selectedMarkup = null;
323					this.transcriptPane.markupsPane.selectedMarkup = selectedMarkup;
324				}
325				Alert.show("Successfully saved transcript changes");
326			}
327			 
328			private function storeSessionFailure(msg:String):void
329			{
330				var index:int = msg.indexOf("PermissionDeniedException:");
331				if (index >= 0) {
332					Alert.show(msg.substr(index + 26), "Error saving transcript");
333				}
334				else if (StringUtil.trim(msg).length == 0) {
335					// nothing in the message
336					databaseMgr.testConnection(function():void {
337						Alert.show("Unknown reason", "Error saving transcript");
338					}, function(msg2:String):void {
339						Alert.show("Could not connect to database", "Error saving transcript");						
340					});
341				}
342				else {
343					Alert.show(msg, "Error saving transcript");
344				}				
345			}
346			
347			private function reloadClicked():void {
348				if (session.unsavedChanges) {
349					// confirm this operation with the user
350					Alert.show("Are you sure?", "Discarding changes...", Alert.OK | Alert.CANCEL, null, function(evt:CloseEvent):void {
351						if (evt.detail==Alert.OK) {
352							reloadSession();
353						}
354					});
355				}
356				else {
357					reloadSession();
358				} 
359			}
360			
361			private function reloadSession():void {
362				if (session == null) {
363					return;
364				}
365				var reloadSessionFunction:Function = function():void {
366					sessionMgr.retrieveSession(session.id, session.eventMetadata, openSessionSuccess, openSessionFailure);
367				}
368				// first update the reference file - continue even if it fails
369				referenceMgr.loadReferences(reloadSessionFunction, function(msg:String):void {
370					trace("Couldnt retrieve reference.xml (continuing anyway): " + msg);
371					reloadSessionFunction();
372				});
373			}
374			
375			private function editEventMetadata():void {
376				var thisPanel:MainPanel = this;
377				DatabaseManagerUtils.retrieveEventXML(session.eventMetadata.id, databaseMgr, function(eventXML:XML):void {
378					session.eventMetadata = EventMetadata.createInstance(eventXML);
379					var popup:EventMetadataEditorDialog = EventMetadataEditorDialog.display(thisPanel, databaseMgr, referenceMgr, session.eventMetadata);
380					popup.addEventListener(EventMetadataEditorDialog.EVENT_EDITED, function(event:Event):void {
381						status = "Successfully edited event";
382						Alert.show("Successfully edited event"); 
383						updateTitle();
384					});
385				}, function(msg:String):void {;				
386					Alert.show(msg, "Could not retrieve event XML");
387				});
388			}
389			
390			private function editSessionMetadata():void {
391				var sessionXMLCopy:XML = session.sessionXML.copy();
392				var sessionMetadataCopy:SessionMetadata = SessionMetadata.createInstanceFromSessionXML(sessionXMLCopy);
393				var popup:SessionMetadataEditorDialog = SessionMetadataEditorDialog.display(this, databaseMgr, referenceMgr, sessionMetadataCopy); 
394				popup.addEventListener(FlexEvent.CREATION_COMPLETE, function(evt:FlexEvent):void {
395					popup.sessionMetadataPane.selectableStartAtRange = session.eventMetadata.dateRange;
396				});
397				popup.addEventListener(SessionMetadataEditorDialog.SESSION_PROPS_EDITED, function():void {
398					// copy the session props over the existing ones
399					// first delete the old ones
400					session.metadata.metadataElement = sessionMetadataCopy.metadataElement;
401					session.unsavedChanges = true;
402					Alert.show("Session properties edited but not yet saved");				
403					updateTitle();
404				});
405			}
406			
407			private function eventSessionBuilderClicked():void {
408				if (session != null && session.unsavedChanges) {
409					// confirm this operation with the user
410					Alert.show("Are you sure?", "Discarding changes...", Alert.OK | Alert.CANCEL, null, function(evt:CloseEvent):void {
411						if (evt.detail==Alert.OK) {
412							importTranscript();
413						}
414					});
415				}
416				else {
417					importTranscript();
418				} 
419			}
420			
421			private function importTranscript():void {
422				// always bring up the full import dialog if there is no session loaded or the session already has a transcript
423				if (session == null || session.transcript != null) {
424					importTranscriptComplex();
425				}
426				else {
427					var popup:Alert = Alert.show("Import into current session?", null, Alert.YES + Alert.NO + Alert.CANCEL, this, function(evt:CloseEvent):void {
428						if (evt.detail == Alert.YES) {
429							importTranscriptSimple();
430						}
431						else if (evt.detail == Alert.NO) {
432							importTranscriptComplex();
433						}
434						else {
435							// do nothing
436						}
437					});
438				}
439			}
440			
441			private function importTranscriptComplex():void {
442				var popup:ImportDialog = ImportDialog.display(this, databaseMgr, referenceMgr);
443				popup.addEventListener(ImportDialog.IMPORT_CLICKED, function(event:Event):void {
444					var newSession:Session = sessionMgr.openSessionForEvent(popup.sessionXML, popup.eventMetadata);
445					openSessionSuccess(newSession);
446					storeSession();
447				});
448			}
449			
450			/** imports the selected transcript files into the current session */
451			private function importTranscriptSimple():void {
452				if (session == null) {
453					throw new Error("Cannot do a simple import when no session is open");
454				}
455				var popup:TranscriptsToImportSelectorDialog = TranscriptsToImportSelectorDialog.display(this, databaseMgr, referenceMgr);
456				popup.addEventListener(TranscriptsToImportSelectorDialog.FILES_IMPORTED, function(evt:Event):void {
457					var importedSessionXML:XML = MSWordImporter.createSessionElement(popup.selectedAudioTranscripts);
458					var importedDeviceElements:XMLList = importedSessionXML..device;
459					var importedTranscriptElement:XML = importedSessionXML.transcript[0];
460					session.appendTranscript(importedTranscriptElement, importedDeviceElements);
461					storeSession();
462					session.unsavedChanges = true;
463					openSessionSuccess(session);
464				});
465				
466			}
467			
468			private function showAboutBox():void {
469				var popup:AboutBox = PopUpManager.createPopUp(this, AboutBox, true) as AboutBox;
470				popup.user = databaseMgr.user;
471			}
472			
473			private function updateTitle():void {
474				var title:String = "";
475				if (session == null) {
476					title += "No session open";
477				}
478				else {
479					if (session.eventMetadata != null) {
480						title += session.eventMetadata.generateFullName(referenceMgr) + "; ";
481					}
482					title += session.metadata.getFullName(session.eventMetadata) + " ";
483					if (session.transcript == null) {
484						title += "- NO TRANSCRIPT";
485					}
486				}
487				transcriptPane.label = title;
488			}
489			
490			private function onMenuClick(menuItemElement:XML):void {
491				var actionName:String = menuItemElement.@id;
492				if ( actionName == "open" ) {
493					openClicked();
494				}
495				else if ( actionName == "openById" ) {
496					openByIdClicked();
497				}
498				else if ( actionName == "store" ) {
499					storeSession();
500				}
501				else if ( actionName == "reloadTranscript" ) {
502					reloadClicked();
503				}
504				else if ( actionName == "eventMetadata" ) {
505					editEventMetadata();
506				}
507				else if ( actionName == "sessionMetadata" ) {
508					editSessionMetadata();
509				}
510				else if ( actionName == "markupText" ) {
511					this.transcriptPane.markupText();
512				}
513				else if ( actionName == "removeMarkup" ) {
514					this.transcriptPane.removeMarkup();
515				}
516				else if ( actionName == "mergeSegmentRange" ) {
517					this.transcriptPane.mergeSegmentRange();
518				}
519				else if ( actionName == "deleteText" ) {
520					this.transcriptPane.deleteText();
521				}
522				else if ( actionName == "nudgeUp" ) {
523					this.transcriptPane.nudgeUp();
524				}
525				else if ( actionName == "nudgeDown" ) {
526					this.transcriptPane.nudgeDown();
527				}
528				else if ( actionName == "showMediaPlayer" ) {					
529					var mediaPlayerDialog:MediaPlayerDialog = MediaPlayerDialog.display(this);
530					mediaPlayerDialog.mediaMetadataElement = session.sessionXML.mediaMetadata[0];
531				}
532				else if ( actionName == "showMarkupPropertiesPane" ) {
533					var showMarkupProps:Boolean = menuItemElement.@toggled.toString() == "true";
534					this.transcriptPane.markupsPane.setNodePropertiesPaneVisibility(showMarkupProps);
535				}
536				else if ( actionName == "showTextPropertiesPane" ) {
537					var showTextProps:Boolean = menuItemElement.@toggled.toString() == "true";
538					this.transcriptPane.textPane.setPropertiesPaneVisibility(showTextProps);
539				}
540				else if ( actionName == "eventSessionBuilder" ) {
541					eventSessionBuilderClicked();
542				}
543				else if ( actionName == "categoryManager" ) {
544					managerClicked(openCategoryManager);
545				}
546				else if ( actionName == "conceptManager" ) {
547					managerClicked(openConceptManager);
548				}
549				else if ( actionName == "query" ) {
550					queryClicked();
551				}
552				else if ( actionName == "showHTMLSearchInterface" ) {					
553					navigateToURL(new URLRequest(DatabaseConstants.EXIST_URL + "/rest/db/ts4isha/xquery/main.xql"), "_blank");
554				}
555				else if ( actionName.indexOf("debug") == 0) {
556					var popup:DebugPopUp = new DebugPopUp();
557					PopUpManager.addPopUp(popup, this, true);
558					if ( actionName == "debugSession") {
559						popup.textArea.text = this.session.sessionXML.toXMLString();
560					}
561					else if ( actionName == "debugReference") {
562						popup.textArea.text = referenceMgr.referenceXML.toXMLString();
563					}
564					else if ( actionName == "debugTranscriptHTML") {
565						popup.textArea.text = transcriptPane.textPane.transcriptTextArea.wrappedTextArea.htmlText;
566					}
567				}
568				else if ( actionName == "highlightHTMLElements") {
569					transcriptPane.textPane.transcriptTextArea.highlightHTMLElements();
570				}
571				else if ( actionName == "about") {
572					showAboutBox();
573				}
574			}			
575		]]>
576	</mx:Script>
577	<mx:MenuBar id="myMenuBar" width="100%" labelField="@label" itemClick="onMenuClick(event.item as XML)">
578		<mx:XMLList id="menuData">
579			<menuitem label="File" enabled="{referenceMgr != null}">
580				<menuitem id="open" label="Open..."/>
581				<menuitem id="openById" label="Open by ID..."/>
582				<!-- the enabled attribute value is a workaround because the following do not work:
583					{session != null &amp;&amp; session.unsavedChanges}
584					{session != null}
585					{session != null ? true : false}
586					{true &amp;&amp; session != null}
587					{this &amp;&amp; session != null}
588				-->
589				<menuitem id="store" label="Save" enabled="true"/>
590				<menuitem id="reloadTranscript" label="Reload from database" enabled="{myMenuBar != null &amp;&amp; session != null}"/>
591				<menuitem type="separator"/>
592				<menuitem id="eventMetadata" label="Event properties..." enabled="{myMenuBar != null &amp;&amp; session != null}"/>
593				<menuitem id="sessionMetadata" label="Session properties..." enabled="{myMenuBar != null &amp;&amp; session != null}"/>
594				<!--menuitem id="mediaProps" label="Media properties..." enabled="{myMenuBar != null &amp;&amp; session != null}"/-->
595			</menuitem>
596			<menuitem label="Selection" enabled="{transcriptPane.textPane.ttSelection != null}">
597				<menuitem id="markupText" label="Markup text" enabled="{databaseMgr.user.isMarkupUser() &amp;&amp; transcriptPane.textPane.ttSelection.allowMarkup()}"/>
598				<menuitem id="removeMarkup" label="Remove markup" enabled="{databaseMgr.user.isMarkupUser() &amp;&amp; transcriptPane.textPane.ttSelection.allowRemoveMarkup()}"/>
599				<menuitem type="separator"/>
600				<menuitem id="mergeSegmentRange" label="Merge paragraphs" enabled="{databaseMgr.user.isTextUser() &amp;&amp; transcriptPane.textPane.ttSelection.allowMerge()}"/>
601				<menuitem id="deleteText" label="Delete text" enabled="{databaseMgr.user.isTextUser() &amp;&amp; transcriptPane.textPane.ttSelection.allowDeleteText()}"/>
602				<menuitem type="separator"/>
603				<menuitem id="nudgeUp" label="Nudge up" enabled="{databaseMgr.user.isMarkupUser() &amp;&amp; transcriptPane.textPane.ttSelection.allowNudgeUp()}"/>
604				<menuitem id="nudgeDown" label="Nudge down" enabled="{databaseMgr.user.isMarkupUser() &amp;&amp; transcriptPane.textPane.ttSelection.allowNudgeDown()}"/>
605			</menuitem>				
606			<menuitem label="Window" enabled="{myMenuBar != null &amp;&amp; session != null}">
607				<menuitem id="showMediaPlayer" label="Media player"/>
608				<menuitem type="separator"/>
609				<menuitem id="showMarkupPropertiesPane" label="Markup properties" type="check" toggled="true"/>
610				<menuitem id="showTextPropertiesPane" label="Text properties" type="check" toggled="false"/>
611			</menuitem>
612			<menuitem label="Admin" enabled="{databaseMgr != null &amp;&amp; databaseMgr.user.isDbaUser()}">
613				<menuitem id="eventSessionBuilder" label="Event/Session Builder..."/>
614				<menuitem type="separator"/>
615				<menuitem id="categoryManager" label="Categories..."/>
616				<menuitem id="conceptManager" label="Concepts..."/>
617				<menuitem type="separator"/>
618				<menuitem id="query" label="Execute XQuery..."/>				
619			</menuitem>
620			<menuitem label="Tools">
621				<menuitem id="showHTMLSearchInterface" label="HTML Search Interface"/>
622			</menuitem>
623			<menuitem label="Help">
624				<menuitem label="Debug">
625					<menuitem id="debugSession" label="Session XML"/>
626					<menuitem id="debugReference" label="Reference XML"/>
627					<menuitem id="debugTranscriptHTML" label="Transcript HTML"/>
628					<!--menuitem id="highlightHTMLElements" label="Highlight HTML Elements"/-->
629				</menuitem>					
630				<menuitem id="about" label="About {ApplicationUtils.getApplicationName()}"/>
631			</menuitem>
632		</mx:XMLList>
633	</mx:MenuBar>
634	<mx:TabNavigator borderStyle="none" tabWidth="{transcriptPane.width}" horizontalAlign="center" width="100%" height="100%" paddingTop="0" visible="{this.session != null}">
635		<studioNS:TranscriptPane id="transcriptPane" width="100%" height="100%" backgroundColor="0x869CA7" referenceMgr="{this.referenceMgr}" visible="{this.session != null}" enabled="{this.transcriptPane.transcript != null}" user="{databaseMgr.user}"/>
636	</mx:TabNavigator>
637</mx:VBox>