Merge branch 'fix-context-menu' into mconf-live0.6.2

Conflicts:
	bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatView.mxml
	bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/view/components/DesktopPublishWindow.mxml
	bigbluebutton-client/src/org/bigbluebutton/modules/deskshare/view/components/DesktopViewWindow.mxml
	bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/SharedNotesWindow.mxml
	bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/business/VideoWindowItf.as
	bigbluebutton-client/src/org/bigbluebutton/modules/videodock/views/VideoDock.mxml
	bigbluebutton-client/src/org/bigbluebutton/modules/whiteboard/views/WhiteboardToolbar.mxml
This commit is contained in:
Felipe Cecagno 2015-04-09 18:08:33 -03:00
commit 1f0ecdfa0e
25 changed files with 985 additions and 923 deletions

View File

@ -30,8 +30,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<![CDATA[
import com.asfusion.mate.events.Dispatcher;
import flexlib.mdi.containers.MDIWindow;
import org.bigbluebutton.common.IBbbModuleWindow;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.common.events.CloseWindowEvent;

View File

@ -0,0 +1,91 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation; either version 3.0 of the License, or (at your option) any later
* version.
*
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
*
*/
package org.bigbluebutton.common
{
import flash.ui.ContextMenu;
import flexlib.mdi.containers.MDIWindow;
import flexlib.mdi.managers.MDIManager;
import mx.utils.ObjectUtil;
/**
* This class exists so we can properly handle context menus on MDIWindow
* instances. Also, we'll be able in the future to properly handle shortcuts
* such as SHIFT + LEFT/RIGHT ARROW while in a text area (today, besides
* selecting the text, it will move the window).
*/
public class CustomMdiWindow extends MDIWindow {
private static const IGNORED_MENU_ITEMS:Array = new Array(
MDIWindow.CONTEXT_MENU_LABEL_CLOSE,
MDIManager.CONTEXT_MENU_LABEL_TILE,
MDIManager.CONTEXT_MENU_LABEL_TILE_FILL,
MDIManager.CONTEXT_MENU_LABEL_CASCADE,
MDIManager.CONTEXT_MENU_LABEL_SHOW_ALL );
private var _customContextMenuItems:Array = null;
private function filterContextMenu(item:*, index:int, array:Array):Boolean {
return IGNORED_MENU_ITEMS.indexOf(item.caption) < 0;
}
override public function updateContextMenu():void {
super.updateContextMenu();
var modifiedContextMenuItems:Array = new Array();
if (customContextMenuItems != null) {
if (modifiedContextMenuItems.length > 0 && customContextMenuItems.length > 0) {
modifiedContextMenuItems[0].separatorBefore = true;
}
modifiedContextMenuItems = customContextMenuItems.concat(modifiedContextMenuItems);
}
if (this.contextMenu != null) {
var filteredMenu:Array = this.contextMenu.customItems.filter(filterContextMenu);
if (modifiedContextMenuItems.length > 0 && filteredMenu.length > 0) {
filteredMenu[0].separatorBefore = true;
}
modifiedContextMenuItems = modifiedContextMenuItems.concat(filteredMenu);
}
var modifiedContextMenu:ContextMenu = new ContextMenu();
modifiedContextMenu.hideBuiltInItems();
modifiedContextMenu.customItems = modifiedContextMenuItems;
this.contextMenu = modifiedContextMenu;
}
override public function set showCloseButton(value:Boolean):void {
super.showCloseButton = value;
updateContextMenu();
}
public function get customContextMenuItems():Array {
return _customContextMenuItems;
}
public function set customContextMenuItems(value:Array):void {
_customContextMenuItems = value;
updateContextMenu();
}
}
}

View File

@ -20,7 +20,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<MDIWindow xmlns="flexlib.mdi.containers.*"
<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
title="Log Window" creationComplete="displayLogMessages();"
showCloseButton="true" xmlns:text="flash.text.*">
@ -88,4 +88,4 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<mx:Button label="Refresh" click="displayLogMessages()"/>
</mx:HBox>
</mx:ApplicationControlBar>
</MDIWindow>
</CustomMdiWindow>

View File

@ -76,7 +76,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import flash.events.MouseEvent;
import flash.geom.Point;
import flexlib.mdi.containers.MDIWindow;
import flexlib.mdi.effects.effectsLib.MDIVistaEffects;
import mx.collections.ArrayCollection;

View File

@ -20,7 +20,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<MDIWindow xmlns="flexlib.mdi.containers.*"
<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:mate="http://mate.asfusion.com/"
title="{ResourceUtil.getInstance().getString('bbb.bwmonitor.title')}"
@ -113,4 +113,4 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
</mx:VBox>
</mx:Panel>
</MDIWindow>
</CustomMdiWindow>

View File

@ -20,7 +20,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<MDIWindow xmlns="flexlib.mdi.containers.*"
<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
showCloseButton="true"
initialize="init()"
@ -289,4 +289,4 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<mx:DataGridColumn dataField="func" headerText="{ResourceUtil.getInstance().getString('bbb.shortcuthelp.headers.function')}"/>
</mx:columns>
</mx:DataGrid>
</MDIWindow>
</CustomMdiWindow>

View File

@ -18,8 +18,8 @@ You should have received a copy of the GNU Lesser General Public License along
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<bcast:MDIWindow xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:bcast="flexlib.mdi.containers.*"
<bcast:CustomMdiWindow xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:bcast="org.bigbluebutton.common.*"
implements="org.bigbluebutton.common.IBbbModuleWindow"
styleNameFocus="broadcastStyleFocus"
styleNameNoFocus="broadcastStyleNoFocus"
@ -30,7 +30,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<mx:Script>
<![CDATA[
import flexlib.mdi.events.MDIWindowEvent;
import mx.core.UIComponent;
import mx.events.ResizeEvent;
import mx.skins.Border;
@ -146,4 +145,4 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<mx:Button id="playBtn" label="Play" width="15% " click="playStopVideo()" toggle="true"/>
</mx:HBox>
</mx:ControlBar>
</bcast:MDIWindow>
</bcast:CustomMdiWindow>

View File

@ -1,405 +1,404 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
This program is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 3.0 of the License, or (at your option) any later
version.
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:mate="http://mate.asfusion.com/"
creationComplete="onCreationComplete()"
initialize="init()"
xmlns:flexlib="http://code.google.com/p/flexlib/"
width="100%" height="100%" xmlns:containers="flexlib.containers.*"
verticalScrollPolicy="off">
<mate:Listener type="{PrivateChatMessageEvent.PRIVATE_CHAT_MESSAGE_EVENT}" method="handlePrivateChatMessageEvent"/>
<mate:Listener type="{PublicChatMessageEvent.PUBLIC_CHAT_MESSAGE_EVENT}" method="handlePublicChatMessageEvent"/>
<mate:Listener type="{EventConstants.START_PRIVATE_CHAT}" method="handleStartPrivateChatMessageEvent"/>
<mate:Listener type="{ShortcutEvent.FOCUS_CHAT_TABS}" method="focusChatTabs" />
<mate:Listener type="{ChatToolbarButtonEvent.SAVE_CHAT_TOOLBAR_EVENT}" method="dispatchSaveChatEvent" />
<mate:Listener type="{ChatToolbarButtonEvent.COPY_CHAT_TOOLBAR_EVENT}" method="dispatchCopyChatEvent" />
<mx:Script>
<![CDATA[
import com.asfusion.mate.events.Dispatcher;
import flash.accessibility.Accessibility;
import flash.events.Event;
import flash.events.FocusEvent;
import flash.external.ExternalInterface;
import flash.media.Sound;
import flash.media.SoundChannel;
import flexlib.controls.tabBarClasses.SuperTab;
import flexlib.controls.textClasses.StringBoundaries;
import flexlib.events.SuperTabEvent;
import flexlib.mdi.containers.MDIWindow;
import mx.collections.ArrayCollection;
import mx.containers.ControlBar;
import mx.controls.Button;
import mx.core.Container;
import mx.core.UIComponent;
import mx.events.IndexChangedEvent;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.core.BBB;
import org.bigbluebutton.core.EventConstants;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.core.events.CoreEvent;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.main.events.BBBEvent;
import org.bigbluebutton.main.events.ShortcutEvent;
import org.bigbluebutton.main.model.users.BBBUser;
import org.bigbluebutton.modules.chat.ChatUtil;
import org.bigbluebutton.modules.chat.events.ChatCopyEvent;
import org.bigbluebutton.modules.chat.events.ChatOptionsEvent;
import org.bigbluebutton.modules.chat.events.ChatSaveEvent;
import org.bigbluebutton.modules.chat.events.PrivateChatMessageEvent;
import org.bigbluebutton.modules.chat.events.PublicChatMessageEvent;
import org.bigbluebutton.modules.chat.events.SendPrivateChatMessageEvent;
import org.bigbluebutton.modules.chat.events.SendPublicChatMessageEvent;
import org.bigbluebutton.modules.chat.model.ChatOptions;
import org.bigbluebutton.modules.chat.model.business.UserVO;
import org.bigbluebutton.modules.chat.vo.ChatMessageVO;
import org.bigbluebutton.util.i18n.ResourceUtil;
import org.bigbluebutton.modules.chat.events.ChatToolbarButtonEvent;
private static const PUBLIC_CHAT_USERID:String = 'public_chat_userid';
private var PUBLIC_CHAT_USERNAME:String = ResourceUtil.getInstance().getString("bbb.chat.publicChatUsername");
private var OPTION_TAB_ID:String = ResourceUtil.getInstance().getString("bbb.chat.optionsTabName");
private var tabBox:AddChatTabBox;
private var publicBox:ChatBox;
private var focus:Boolean = true;
private var globalDispatcher:Dispatcher = new Dispatcher();
[Bindable] public var chatOptions:ChatOptions;
[Bindable] private var baseIndex:int;
private static const PUBLIC_TAB_NEW:String = ResourceUtil.getInstance().getString("bbb.accessibility.chat.chatView.publicTabNew");
private var publicWaiting:Boolean = false;
private var publicFocus:Boolean = false;
private var noticeLabel:String;
[Embed(source="../sounds/notice.mp3")]
private var noticeSoundClass:Class;
private var noticeSound:Sound = new noticeSoundClass() as Sound;
// All author and license information for the use of this sound can be found in:
// src/org/bigbluebutton/modules/chat/sounds/license.txt
// Initialization
private function init():void {
chatOptions = new ChatOptions();
noticeLabel = ResourceUtil.getInstance().getString('bbb.chat.chatTabs.accessibleNotice');
// Get the base tab index from config, and add four to make up for the min/max/close buttons and title overlay
baseIndex = chatOptions.getBaseIndex() + 4;
}
private function onCreationComplete():void{
openChatBoxFor(PUBLIC_CHAT_USERID, true);
makePublicChatUncloseable();
if (chatOptions.privateEnabled) {
createAddTabBox();
makeAddPrivateChatUncloseable();
}
ResourceUtil.getInstance().addEventListener(Event.CHANGE, localeChanged); // Listen for locale changing
addEventListener(SuperTabEvent.TAB_CLOSE, onUserClosedTab);
systemManager.stage.addEventListener(Event.MOUSE_LEAVE, mouseLeave);
systemManager.stage.addEventListener(Event.ACTIVATE, activate);
systemManager.stage.addEventListener(Event.DEACTIVATE, deactivate);
}
private function getVisibleChatBox():ChatBox {
var chatBox:ChatBox = chatTabs.getChildAt(chatTabs.selectedIndex) as ChatBox;
return chatBox;
}
private function dispatchSaveChatEvent(e:Event):void {
var chatBox:ChatBox = getVisibleChatBox();
var saveEvent:ChatSaveEvent = new ChatSaveEvent(ChatSaveEvent.SAVE_CHAT_EVENT);
if (chatBox.chatWithUsername == null || chatBox.chatWithUsername == "") {
saveEvent.filename = ResourceUtil.getInstance().getString('bbb.chat.save.filename');
} else {
saveEvent.filename = chatBox.chatWithUsername;
}
saveEvent.chatMessages = chatBox.getChatMessages();
globalDispatcher.dispatchEvent(saveEvent);
}
private function dispatchCopyChatEvent(e:Event):void {
var chatBox:ChatBox = getVisibleChatBox();
var copyEvent:ChatCopyEvent = new ChatCopyEvent(ChatCopyEvent.COPY_CHAT_EVENT);
copyEvent.chatMessages = chatBox.getChatMessages();
globalDispatcher.dispatchEvent(copyEvent);
}
private function focusChatTabs(e:ShortcutEvent):void{
focusManager.setFocus(chatTabs);
}
private function localeChanged(e:Event):void{
setTabTitles();
}
private function setTabTitles():void {
PUBLIC_CHAT_USERNAME = ResourceUtil.getInstance().getString("bbb.chat.publicChatUsername");
OPTION_TAB_ID = ResourceUtil.getInstance().getString("bbb.chat.optionsTabName");
if (tabBox != null) {
tabBox.id = OPTION_TAB_ID;
tabBox.label = OPTION_TAB_ID;
tabBox.name = OPTION_TAB_ID;
}
if (publicBox != null) {
publicBox.label = PUBLIC_CHAT_USERNAME;
}
}
private function handlePublicChatMessageEvent(event:PublicChatMessageEvent):void {
notifyUserOfNewMessage(PUBLIC_CHAT_USERID);
if (!UsersUtil.isMe(event.message.fromUserID)) {
publicNotification();
}
}
private function handlePrivateChatMessageEvent(event:PrivateChatMessageEvent):void {
// This message is from me. Ignore as a chatbox has already been created for this
// private chat and that chatbox will handle this message.
if (UsersUtil.isMe(event.message.fromUserID)) return;
// I received a new private chat. Open up a new chatbox and forward the message
// to the chatbox. Succeeding messages will be handled by that chatbox.
if (! userHasChatBox(event.message.fromUserID)) {
// Open a private chat tab.
openChatBoxFor(event.message.fromUserID, false).handleFirstPrivateMessage(event);
}
// See if the chatbox is not in focus and notify user about the message.
notifyUserOfNewMessage(event.message.fromUserID);
privateNotification(event);
}
private function notifyUserOfNewMessage(userID:String):void {
if (! isChatBoxCurrentlySelected(userID)) {
notifyParticipantOfUnreadMessageFrom(userID);
}
}
private function mouseLeave(event:Event):void{
this.focus = false;
}
private function activate(event:Event):void{
this.focus = true;
}
private function deactivate(event:Event):void{
this.focus = false;
}
private function makePublicChatUncloseable():void {
// See definition of callLater on Adobe Flash doc.
callLater(calledOnTheNextScreenRefreshToMakePublicChatUncloseable);
}
private function makeAddPrivateChatUncloseable():void {
// See definition of callLater on Adobe Flash doc.
callLater(calledOnTheNextScreenRefreshToMakeTabUncloseable);
}
private function calledOnTheNextScreenRefreshToMakeTabUncloseable():void {
chatTabs.setClosePolicyForTab(chatTabs.getChildIndex(tabBox), SuperTab.CLOSE_NEVER);
}
private function calledOnTheNextScreenRefreshToMakePublicChatUncloseable():void {
var chatBox:ChatBox = getChatBoxForUser(PUBLIC_CHAT_USERID);
var chatIndex:int = getTabIndexFor(chatBox);
chatTabs.setClosePolicyForTab(chatIndex, SuperTab.CLOSE_NEVER);
}
private function isChatBoxCurrentlySelected(id:String):Boolean {
if (chatTabs.getChildByName(id) == chatTabs.selectedChild){
return true;
}
return false;
}
private function notifyParticipantOfUnreadMessageFrom(userid:String):void {
var chatBox:ChatBox = getChatBoxForUser(userid);
var tabIndex:int = getTabIndexFor(chatBox);
var tab:Button = chatTabs.getTabAt(tabIndex);
tab.setStyle("fillColors", new Array(0xFFAE00, 0xD3800A));
tab.setStyle("fillAlphas", new Array(1.0, 0.8));
// An event to change the accessibilityDescription of the given chat tab to <existing label> + "NEW MESSAGE" should go here.
// However, the SuperTabNavigator does not cooperate with changes to it's accessibility properties.
}
private function getTabIndexFor(chatBox:ChatBox):int {
return chatTabs.getChildIndex(chatBox);
}
private function onTabNavChange():void{
var tab:Button = chatTabs.getTabAt(chatTabs.selectedIndex);
tab.setStyle("fillColors", new Array(0xFFFFFF, 0xCCCCCC));
// An event to remove the "NEW MESSAGE" notification from the accessibilityDescription of the given chat tab (if it exists) should go here.
// However, the SuperTabNavigator does not cooperate with changes to it's accessibility properties.
var chatBox:IChatTab = chatTabs.getChildAt(chatTabs.selectedIndex) as IChatTab;
chatBox.focusToTextMessageArea();
}
private function userHasChatBox(userID:String):Boolean {
var chatBox:ChatBox = chatTabs.getChildByName(userID) as ChatBox;
if (chatBox != null) return true;
return false;
}
private function getChatBoxForUser(userID:String):ChatBox {
return chatTabs.getChildByName(userID) as ChatBox;
}
private function handleStartPrivateChatMessageEvent(event:CoreEvent):void {
var userID:String = event.message.chatWith;
var tabIndex:int = getTabIndexFor(openChatBoxFor(userID));
chatTabs.selectedIndex = tabIndex;
}
public function openChatBoxFor(chatWithUserID:String, publicChat:Boolean=false):ChatBox {
if (userHasChatBox(chatWithUserID)) {
return getChatBoxForUser(chatWithUserID);
} else {
return createChatBoxFor(chatWithUserID, publicChat);
}
}
private function createChatBoxFor(chatWithUserID:String, publicChat:Boolean=false):ChatBox {
var chatBox:ChatBox = new ChatBox();
chatBox.id = chatWithUserID;
chatBox.name = chatWithUserID;
chatBox.chatWithUserID = chatWithUserID;
chatBox.baseIndex = baseIndex;
if (publicChat) {
chatBox.label = PUBLIC_CHAT_USERNAME
chatBox.publicChat = true;
publicBox = chatBox; // keep a reference to the public chat box
} else {
chatBox.publicChat = false;
chatBox.label = UsersUtil.getUserName(chatWithUserID);
}
chatBox.chatWithUsername = UsersUtil.getUserName(chatWithUserID);
if (chatTabs.numChildren >= 2) {
chatTabs.addChildAt(chatBox, chatTabs.numChildren - 1);
} else {
chatTabs.addChild(chatBox);
}
// set the font size on tab opening
if (tabBox) chatBox.setStyle("fontSize", int(tabBox.cmbFontSize.selectedItem));
return chatBox;
}
private function createAddTabBox():AddChatTabBox {
tabBox = new AddChatTabBox();
tabBox.chatView = this;
tabBox.id = OPTION_TAB_ID;
tabBox.label = OPTION_TAB_ID;
tabBox.name = OPTION_TAB_ID;
tabBox.chatOptions = chatOptions;
tabBox.addEventListener(KeyboardEvent.KEY_DOWN, tabBox.accessibleClick);
chatTabs.addChild(tabBox);
return tabBox;
}
// Activates an audio alert for screen-reader users on public message reception
private function publicNotification():void {
publicWaiting = true;
if (Accessibility.active){
noticeSound.play();
}
chatTabs.getChildByName(PUBLIC_CHAT_USERID).addEventListener(FocusEvent.FOCUS_IN, publicChatFocus);
chatTabs.getChildByName(PUBLIC_CHAT_USERID).addEventListener(FocusEvent.FOCUS_OUT, publicChatUnfocus);
}
// Activates an audio alert for screen-reader users on private message reception
private function privateNotification(event:PrivateChatMessageEvent):void{
if (! UsersUtil.isMe(event.message.fromUserID)) {
if (Accessibility.active){
noticeSound.play();
}
}
}
public function publicChatFocus(event:FocusEvent):void{
publicFocus = true;
publicWaiting = false;
}
public function publicChatUnfocus(event:FocusEvent):void {
publicFocus = false;
}
private function focusPreviousChatTab(e:ShortcutEvent):void{
if (chatTabs.selectedIndex > 0){
chatTabs.selectedIndex--;
}
else{
chatTabs.selectedIndex = chatTabs.numChildren - 1;
}
}
private function focusNextChatTab(e:ShortcutEvent):void{
if (chatTabs.selectedIndex < chatTabs.numChildren - 1){
chatTabs.selectedIndex++;
}
else{
chatTabs.selectedIndex = 0;
}
}
private function onTabClose(e:SuperTabEvent):void{
dispatchEvent(e);
}
private function onUserClosedTab(e:SuperTabEvent):void{
var name:String = chatTabs.getChildAt(e.tabIndex).name;
}
]]>
</mx:Script>
<containers:SuperTabNavigator includeInLayout="false" id="chatTabs"
width="100%" height="100%" change="onTabNavChange()"
tabClose="onTabClose(event)" minTabWidth="20"
dragEnabled="false" popUpButtonPolicy="off" tabIndex="{baseIndex}"
/>
</mx:VBox>
<?xml version="1.0" encoding="utf-8"?>
<!--
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
This program is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 3.0 of the License, or (at your option) any later
version.
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:mate="http://mate.asfusion.com/"
creationComplete="onCreationComplete()"
initialize="init()"
xmlns:flexlib="http://code.google.com/p/flexlib/"
width="100%" height="100%" xmlns:containers="flexlib.containers.*"
verticalScrollPolicy="off">
<mate:Listener type="{PrivateChatMessageEvent.PRIVATE_CHAT_MESSAGE_EVENT}" method="handlePrivateChatMessageEvent"/>
<mate:Listener type="{PublicChatMessageEvent.PUBLIC_CHAT_MESSAGE_EVENT}" method="handlePublicChatMessageEvent"/>
<mate:Listener type="{EventConstants.START_PRIVATE_CHAT}" method="handleStartPrivateChatMessageEvent"/>
<mate:Listener type="{ShortcutEvent.FOCUS_CHAT_TABS}" method="focusChatTabs" />
<mate:Listener type="{ChatToolbarButtonEvent.SAVE_CHAT_TOOLBAR_EVENT}" method="dispatchSaveChatEvent" />
<mate:Listener type="{ChatToolbarButtonEvent.COPY_CHAT_TOOLBAR_EVENT}" method="dispatchCopyChatEvent" />
<mx:Script>
<![CDATA[
import com.asfusion.mate.events.Dispatcher;
import flash.accessibility.Accessibility;
import flash.events.Event;
import flash.events.FocusEvent;
import flash.external.ExternalInterface;
import flash.media.Sound;
import flash.media.SoundChannel;
import flexlib.controls.tabBarClasses.SuperTab;
import flexlib.controls.textClasses.StringBoundaries;
import flexlib.events.SuperTabEvent;
import mx.collections.ArrayCollection;
import mx.containers.ControlBar;
import mx.controls.Button;
import mx.core.Container;
import mx.core.UIComponent;
import mx.events.IndexChangedEvent;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.core.BBB;
import org.bigbluebutton.core.EventConstants;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.core.events.CoreEvent;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.main.events.BBBEvent;
import org.bigbluebutton.main.events.ShortcutEvent;
import org.bigbluebutton.main.model.users.BBBUser;
import org.bigbluebutton.modules.chat.ChatUtil;
import org.bigbluebutton.modules.chat.events.ChatCopyEvent;
import org.bigbluebutton.modules.chat.events.ChatOptionsEvent;
import org.bigbluebutton.modules.chat.events.ChatSaveEvent;
import org.bigbluebutton.modules.chat.events.PrivateChatMessageEvent;
import org.bigbluebutton.modules.chat.events.PublicChatMessageEvent;
import org.bigbluebutton.modules.chat.events.SendPrivateChatMessageEvent;
import org.bigbluebutton.modules.chat.events.SendPublicChatMessageEvent;
import org.bigbluebutton.modules.chat.model.ChatOptions;
import org.bigbluebutton.modules.chat.model.business.UserVO;
import org.bigbluebutton.modules.chat.vo.ChatMessageVO;
import org.bigbluebutton.util.i18n.ResourceUtil;
import org.bigbluebutton.modules.chat.events.ChatToolbarButtonEvent;
private static const PUBLIC_CHAT_USERID:String = 'public_chat_userid';
private var PUBLIC_CHAT_USERNAME:String = ResourceUtil.getInstance().getString("bbb.chat.publicChatUsername");
private var OPTION_TAB_ID:String = ResourceUtil.getInstance().getString("bbb.chat.optionsTabName");
private var tabBox:AddChatTabBox;
private var publicBox:ChatBox;
private var focus:Boolean = true;
private var globalDispatcher:Dispatcher = new Dispatcher();
[Bindable] public var chatOptions:ChatOptions;
[Bindable] private var baseIndex:int;
private static const PUBLIC_TAB_NEW:String = ResourceUtil.getInstance().getString("bbb.accessibility.chat.chatView.publicTabNew");
private var publicWaiting:Boolean = false;
private var publicFocus:Boolean = false;
private var noticeLabel:String;
[Embed(source="../sounds/notice.mp3")]
private var noticeSoundClass:Class;
private var noticeSound:Sound = new noticeSoundClass() as Sound;
// All author and license information for the use of this sound can be found in:
// src/org/bigbluebutton/modules/chat/sounds/license.txt
// Initialization
private function init():void {
chatOptions = new ChatOptions();
noticeLabel = ResourceUtil.getInstance().getString('bbb.chat.chatTabs.accessibleNotice');
// Get the base tab index from config, and add four to make up for the min/max/close buttons and title overlay
baseIndex = chatOptions.getBaseIndex() + 4;
}
private function onCreationComplete():void{
openChatBoxFor(PUBLIC_CHAT_USERID, true);
makePublicChatUncloseable();
if (chatOptions.privateEnabled) {
createAddTabBox();
makeAddPrivateChatUncloseable();
}
ResourceUtil.getInstance().addEventListener(Event.CHANGE, localeChanged); // Listen for locale changing
addEventListener(SuperTabEvent.TAB_CLOSE, onUserClosedTab);
systemManager.stage.addEventListener(Event.MOUSE_LEAVE, mouseLeave);
systemManager.stage.addEventListener(Event.ACTIVATE, activate);
systemManager.stage.addEventListener(Event.DEACTIVATE, deactivate);
}
private function getVisibleChatBox():ChatBox {
var chatBox:ChatBox = chatTabs.getChildAt(chatTabs.selectedIndex) as ChatBox;
return chatBox;
}
private function dispatchSaveChatEvent(e:Event):void {
var chatBox:ChatBox = getVisibleChatBox();
var saveEvent:ChatSaveEvent = new ChatSaveEvent(ChatSaveEvent.SAVE_CHAT_EVENT);
if (chatBox.chatWithUsername == null || chatBox.chatWithUsername == "") {
saveEvent.filename = ResourceUtil.getInstance().getString('bbb.chat.save.filename');
} else {
saveEvent.filename = chatBox.chatWithUsername;
}
saveEvent.chatMessages = chatBox.getChatMessages();
globalDispatcher.dispatchEvent(saveEvent);
}
private function dispatchCopyChatEvent(e:Event):void {
var chatBox:ChatBox = getVisibleChatBox();
var copyEvent:ChatCopyEvent = new ChatCopyEvent(ChatCopyEvent.COPY_CHAT_EVENT);
copyEvent.chatMessages = chatBox.getChatMessages();
globalDispatcher.dispatchEvent(copyEvent);
}
private function focusChatTabs(e:ShortcutEvent):void{
focusManager.setFocus(chatTabs);
}
private function localeChanged(e:Event):void{
setTabTitles();
}
private function setTabTitles():void {
PUBLIC_CHAT_USERNAME = ResourceUtil.getInstance().getString("bbb.chat.publicChatUsername");
OPTION_TAB_ID = ResourceUtil.getInstance().getString("bbb.chat.optionsTabName");
if (tabBox != null) {
tabBox.id = OPTION_TAB_ID;
tabBox.label = OPTION_TAB_ID;
tabBox.name = OPTION_TAB_ID;
}
if (publicBox != null) {
publicBox.label = PUBLIC_CHAT_USERNAME;
}
}
private function handlePublicChatMessageEvent(event:PublicChatMessageEvent):void {
notifyUserOfNewMessage(PUBLIC_CHAT_USERID);
if (!UsersUtil.isMe(event.message.fromUserID)) {
publicNotification();
}
}
private function handlePrivateChatMessageEvent(event:PrivateChatMessageEvent):void {
// This message is from me. Ignore as a chatbox has already been created for this
// private chat and that chatbox will handle this message.
if (UsersUtil.isMe(event.message.fromUserID)) return;
// I received a new private chat. Open up a new chatbox and forward the message
// to the chatbox. Succeeding messages will be handled by that chatbox.
if (! userHasChatBox(event.message.fromUserID)) {
// Open a private chat tab.
openChatBoxFor(event.message.fromUserID, false).handleFirstPrivateMessage(event);
}
// See if the chatbox is not in focus and notify user about the message.
notifyUserOfNewMessage(event.message.fromUserID);
privateNotification(event);
}
private function notifyUserOfNewMessage(userID:String):void {
if (! isChatBoxCurrentlySelected(userID)) {
notifyParticipantOfUnreadMessageFrom(userID);
}
}
private function mouseLeave(event:Event):void{
this.focus = false;
}
private function activate(event:Event):void{
this.focus = true;
}
private function deactivate(event:Event):void{
this.focus = false;
}
private function makePublicChatUncloseable():void {
// See definition of callLater on Adobe Flash doc.
callLater(calledOnTheNextScreenRefreshToMakePublicChatUncloseable);
}
private function makeAddPrivateChatUncloseable():void {
// See definition of callLater on Adobe Flash doc.
callLater(calledOnTheNextScreenRefreshToMakeTabUncloseable);
}
private function calledOnTheNextScreenRefreshToMakeTabUncloseable():void {
chatTabs.setClosePolicyForTab(chatTabs.getChildIndex(tabBox), SuperTab.CLOSE_NEVER);
}
private function calledOnTheNextScreenRefreshToMakePublicChatUncloseable():void {
var chatBox:ChatBox = getChatBoxForUser(PUBLIC_CHAT_USERID);
var chatIndex:int = getTabIndexFor(chatBox);
chatTabs.setClosePolicyForTab(chatIndex, SuperTab.CLOSE_NEVER);
}
private function isChatBoxCurrentlySelected(id:String):Boolean {
if (chatTabs.getChildByName(id) == chatTabs.selectedChild){
return true;
}
return false;
}
private function notifyParticipantOfUnreadMessageFrom(userid:String):void {
var chatBox:ChatBox = getChatBoxForUser(userid);
var tabIndex:int = getTabIndexFor(chatBox);
var tab:Button = chatTabs.getTabAt(tabIndex);
tab.setStyle("fillColors", new Array(0xFFAE00, 0xD3800A));
tab.setStyle("fillAlphas", new Array(1.0, 0.8));
// An event to change the accessibilityDescription of the given chat tab to <existing label> + "NEW MESSAGE" should go here.
// However, the SuperTabNavigator does not cooperate with changes to it's accessibility properties.
}
private function getTabIndexFor(chatBox:ChatBox):int {
return chatTabs.getChildIndex(chatBox);
}
private function onTabNavChange():void{
var tab:Button = chatTabs.getTabAt(chatTabs.selectedIndex);
tab.setStyle("fillColors", new Array(0xFFFFFF, 0xCCCCCC));
// An event to remove the "NEW MESSAGE" notification from the accessibilityDescription of the given chat tab (if it exists) should go here.
// However, the SuperTabNavigator does not cooperate with changes to it's accessibility properties.
var chatBox:IChatTab = chatTabs.getChildAt(chatTabs.selectedIndex) as IChatTab;
chatBox.focusToTextMessageArea();
}
private function userHasChatBox(userID:String):Boolean {
var chatBox:ChatBox = chatTabs.getChildByName(userID) as ChatBox;
if (chatBox != null) return true;
return false;
}
private function getChatBoxForUser(userID:String):ChatBox {
return chatTabs.getChildByName(userID) as ChatBox;
}
private function handleStartPrivateChatMessageEvent(event:CoreEvent):void {
var userID:String = event.message.chatWith;
var tabIndex:int = getTabIndexFor(openChatBoxFor(userID));
chatTabs.selectedIndex = tabIndex;
}
public function openChatBoxFor(chatWithUserID:String, publicChat:Boolean=false):ChatBox {
if (userHasChatBox(chatWithUserID)) {
return getChatBoxForUser(chatWithUserID);
} else {
return createChatBoxFor(chatWithUserID, publicChat);
}
}
private function createChatBoxFor(chatWithUserID:String, publicChat:Boolean=false):ChatBox {
var chatBox:ChatBox = new ChatBox();
chatBox.id = chatWithUserID;
chatBox.name = chatWithUserID;
chatBox.chatWithUserID = chatWithUserID;
chatBox.baseIndex = baseIndex;
if (publicChat) {
chatBox.label = PUBLIC_CHAT_USERNAME
chatBox.publicChat = true;
publicBox = chatBox; // keep a reference to the public chat box
} else {
chatBox.publicChat = false;
chatBox.label = UsersUtil.getUserName(chatWithUserID);
}
chatBox.chatWithUsername = UsersUtil.getUserName(chatWithUserID);
if (chatTabs.numChildren >= 2) {
chatTabs.addChildAt(chatBox, chatTabs.numChildren - 1);
} else {
chatTabs.addChild(chatBox);
}
// set the font size on tab opening
if (tabBox) chatBox.setStyle("fontSize", int(tabBox.cmbFontSize.selectedItem));
return chatBox;
}
private function createAddTabBox():AddChatTabBox {
tabBox = new AddChatTabBox();
tabBox.chatView = this;
tabBox.id = OPTION_TAB_ID;
tabBox.label = OPTION_TAB_ID;
tabBox.name = OPTION_TAB_ID;
tabBox.chatOptions = chatOptions;
tabBox.addEventListener(KeyboardEvent.KEY_DOWN, tabBox.accessibleClick);
chatTabs.addChild(tabBox);
return tabBox;
}
// Activates an audio alert for screen-reader users on public message reception
private function publicNotification():void {
publicWaiting = true;
if (Accessibility.active){
noticeSound.play();
}
chatTabs.getChildByName(PUBLIC_CHAT_USERID).addEventListener(FocusEvent.FOCUS_IN, publicChatFocus);
chatTabs.getChildByName(PUBLIC_CHAT_USERID).addEventListener(FocusEvent.FOCUS_OUT, publicChatUnfocus);
}
// Activates an audio alert for screen-reader users on private message reception
private function privateNotification(event:PrivateChatMessageEvent):void{
if (! UsersUtil.isMe(event.message.fromUserID)) {
if (Accessibility.active){
noticeSound.play();
}
}
}
public function publicChatFocus(event:FocusEvent):void{
publicFocus = true;
publicWaiting = false;
}
public function publicChatUnfocus(event:FocusEvent):void {
publicFocus = false;
}
private function focusPreviousChatTab(e:ShortcutEvent):void{
if (chatTabs.selectedIndex > 0){
chatTabs.selectedIndex--;
}
else{
chatTabs.selectedIndex = chatTabs.numChildren - 1;
}
}
private function focusNextChatTab(e:ShortcutEvent):void{
if (chatTabs.selectedIndex < chatTabs.numChildren - 1){
chatTabs.selectedIndex++;
}
else{
chatTabs.selectedIndex = 0;
}
}
private function onTabClose(e:SuperTabEvent):void{
dispatchEvent(e);
}
private function onUserClosedTab(e:SuperTabEvent):void{
var name:String = chatTabs.getChildAt(e.tabIndex).name;
}
]]>
</mx:Script>
<containers:SuperTabNavigator includeInLayout="false" id="chatTabs"
width="100%" height="100%" change="onTabNavChange()"
tabClose="onTabClose(event)" minTabWidth="20"
dragEnabled="false" popUpButtonPolicy="off" tabIndex="{baseIndex}"
/>
</mx:VBox>

View File

@ -20,7 +20,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<MDIWindow xmlns="flexlib.mdi.containers.*"
<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:chat="org.bigbluebutton.modules.chat.views.components.*"
showCloseButton="false"
@ -40,7 +40,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<![CDATA[
import org.bigbluebutton.modules.chat.model.ChatOptions;
import com.asfusion.mate.events.Dispatcher;
import flexlib.mdi.events.MDIWindowEvent;
import mx.controls.Alert;
import mx.core.Application;
import mx.core.FlexGlobals;
@ -192,4 +191,4 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
</mx:Script>
<views:ChatView id="chatView" chatOptions="{chatOptions}" includeInLayout="false"/>
</MDIWindow>
</CustomMdiWindow>

View File

@ -20,11 +20,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<dspub:MDIWindow
<dspub:CustomMdiWindow
xmlns:mx="http://www.adobe.com/2006/mxml"
implements="org.bigbluebutton.common.IBbbModuleWindow"
xmlns:mate="http://mate.asfusion.com/"
xmlns:dspub="flexlib.mdi.containers.*"
xmlns:dspub="org.bigbluebutton.common.*"
backgroundColor="#C0C0C0"
initialize="init()"
creationComplete="onCreationComplete()"
@ -48,7 +48,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<![CDATA[
import com.asfusion.mate.events.Dispatcher;
import flexlib.mdi.events.MDIWindowEvent;
import flexlib.scheduling.scheduleClasses.BackgroundItem;
import mx.core.UIComponent;
@ -455,4 +454,4 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
</dspub:states>
<mx:Image id="cursorImg" visible="false" source="@Embed('../../assets/images/cursor4.png')"/>
</dspub:MDIWindow>
</dspub:CustomMdiWindow>

View File

@ -20,7 +20,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<MDIWindow xmlns="flexlib.mdi.containers.*"
<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:views="org.bigbluebutton.modules.deskshare.view.components.*"
width="600" height="400"
@ -270,4 +270,4 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
toolTip="{actualSize ? ResourceUtil.getInstance().getString('bbb.desktopView.fitToWindow') : ResourceUtil.getInstance().getString('bbb.desktopView.actualSize')}"
tabIndex="{baseIndex+4}"/>
</views:DesktopViewToolbar>
</MDIWindow>
</CustomMdiWindow>

View File

@ -23,15 +23,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<!--
Notes.mxml is the main view of the SharedNotes application
-->
<MDIWindow xmlns="flexlib.mdi.containers.*" xmlns:mx="http://www.adobe.com/2006/mxml"
<CustomMdiWindow xmlns="org.bigbluebutton.common.*" xmlns:mx="http://www.adobe.com/2006/mxml"
width="400" height="300" xmlns:mate="http://mate.asfusion.com/"
implements="org.bigbluebutton.common.IBbbModuleWindow" creationComplete="onCreationComplete()"
label="Example Chat Window" layout="vertical">
<mx:Script>
<![CDATA[
import flexlib.mdi.events.MDIWindowEvent;
import org.bigbluebutton.main.views.MainCanvas;
private var proxy:ExampleChatProxy;
@ -65,4 +63,4 @@ Notes.mxml is the main view of the SharedNotes application
<mx:TextInput id="txtInput" width="90%" />
<mx:Button id="btnSendMessage" label="Send Message" click="sendNewMessage()" />
</mx:HBox>
</MDIWindow>
</CustomMdiWindow>

View File

@ -43,9 +43,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import flash.net.FileReference;
import flexlib.mdi.containers.MDICanvas;
import flexlib.mdi.containers.MDIWindow;
import flexlib.mdi.events.MDIManagerEvent;
import flexlib.mdi.events.MDIWindowEvent;
import flexlib.mdi.managers.MDIManager;
import mx.collections.ArrayCollection;

View File

@ -18,8 +18,8 @@ You should have received a copy of the GNU Lesser General Public License along
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<ns:MDIWindow xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:ns="http://code.google.com/p/flexlib/"
<ns:CustomMdiWindow xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:ns="org.bigbluebutton.common.*"
xmlns:views="org.bigbluebutton.modules.notes.views.*"
implements="org.bigbluebutton.common.IBbbModuleWindow"
title="Notes"
@ -46,4 +46,4 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
</mx:Script>
<views:NotesView id="notesView" notesArray="{notesModel}"/>
</ns:MDIWindow>
</ns:CustomMdiWindow>

View File

@ -18,7 +18,7 @@ $Id: $
<!--
Notes.mxml is the main view of the SharedNotes application
-->
<MDIWindow xmlns="flexlib.mdi.containers.*"
<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
width="510" height="600"
xmlns:mate="http://mate.asfusion.com/"
@ -46,4 +46,4 @@ Notes.mxml is the main view of the SharedNotes application
<poll:PollCreatePanel width="100%" height="100%"/>
</MDIWindow>
</CustomMdiWindow>

View File

@ -20,7 +20,7 @@
$Id: $
-->
<MDIWindow xmlns="flexlib.mdi.containers.*"
<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:poll="org.bigbluebutton.modules.polling.views.*"
height="510"
@ -54,4 +54,4 @@
</mx:Script>
<poll:PollResultPanel width="100%" height="100%" viewModel="{viewModel}" pollID="{pollID}"/>
</MDIWindow>
</CustomMdiWindow>

View File

@ -18,7 +18,7 @@ $Id: $
<!--
Notes.mxml is the main view of the SharedNotes application
-->
<MDIWindow xmlns="flexlib.mdi.containers.*"
<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
width="510" height="600"
xmlns:mate="http://mate.asfusion.com/"
@ -32,8 +32,6 @@ Notes.mxml is the main view of the SharedNotes application
<![CDATA[
import com.asfusion.mate.events.Dispatcher;
import flexlib.mdi.events.MDIWindowEvent;
import mx.collections.ArrayCollection;
import mx.containers.HBox;
import mx.controls.Alert;
@ -179,4 +177,4 @@ Notes.mxml is the main view of the SharedNotes application
label="{ResourceUtil.getInstance().getString('bbb.polling.pollPreview.cancel')}" />
</mx:ControlBar>
</MDIWindow>
</CustomMdiWindow>

View File

@ -18,7 +18,7 @@ $Id: $
<!--
Notes.mxml is the main view of the SharedNotes application
-->
<MDIWindow xmlns="flexlib.mdi.containers.*"
<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
width="700" height="450"
xmlns:mate="http://mate.asfusion.com/"
@ -49,4 +49,4 @@ Notes.mxml is the main view of the SharedNotes application
<poll:PollMainPanel width="100%" height="100%" viewModel="{viewModel}"/>
</MDIWindow>
</CustomMdiWindow>

View File

@ -18,7 +18,7 @@ $Id: $
<!--
Notes.mxml is the main view of the SharedNotes application
-->
<MDIWindow xmlns="flexlib.mdi.containers.*"
<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
width="510" height="450"
xmlns:mate="http://mate.asfusion.com/"
@ -49,4 +49,4 @@ Notes.mxml is the main view of the SharedNotes application
<poll:TakePollPanel id="takePollPanel" width="100%" height="100%" viewModel="{viewModel}" pollID="{pollID}"/>
</MDIWindow>
</CustomMdiWindow>

View File

@ -18,7 +18,7 @@ $Id: $
<!--
Notes.mxml is the main view of the SharedNotes application
-->
<MDIWindow xmlns="flexlib.mdi.containers.*"
<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
width="510" height="450"
xmlns:mate="http://mate.asfusion.com/"
@ -49,4 +49,4 @@ Notes.mxml is the main view of the SharedNotes application
<poll:UpdatePollPanel width="100%" height="100%" viewModel="{viewModel}" pollID="{pollID}"/>
</MDIWindow>
</CustomMdiWindow>

View File

@ -21,9 +21,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<pres:MDIWindow xmlns:mx="http://www.adobe.com/2006/mxml"
<pres:CustomMdiWindow xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:thumb="org.bigbluebutton.modules.present.views.*"
xmlns:pres="flexlib.mdi.containers.*"
xmlns:pres="org.bigbluebutton.common.*"
xmlns:code="http://code.google.com/p/flexlib/"
xmlns:containers="flexlib.containers.*"
xmlns:mate="http://mate.asfusion.com/"
@ -104,8 +104,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private static const LOG:String = "Present::PresentationWindow - ";
public static const TITLE:String = "Presentation";
private static const NEXT_BUTTON:String = "Next";
private static const PREVIOUS_BUTTON:String = "Previous";
private static const GOTO_PAGE_BUTTON:String = "Go to Page...";
[Bindable]
@ -350,8 +348,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private function becomeViewer():void{
setupPresenter(false);
dispatchEvent(new UploadEvent(UploadEvent.CLOSE_UPLOAD_WINDOW));
this.contextMenu = new ContextMenu();
this.contextMenu.hideBuiltInItems();
this.customContextMenuItems = new Array();
if (slideView.thumbnailView.visible)
showThumbnails();
}
@ -399,31 +396,19 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
private function addContextMenuItems():void{
var contextMenu:ContextMenu = new ContextMenu();
contextMenu.hideBuiltInItems();
var contextMenuItems:Array = new Array();
var nextButton:ContextMenuItem = new ContextMenuItem(NEXT_BUTTON);
nextButton.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, menuItemHandler);
contextMenu.customItems.push(nextButton);
var nextButton:ContextMenuItem = new ContextMenuItem(ResourceUtil.getInstance().getString('bbb.presentation.forwardBtn.toolTip'));
nextButton.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, function(e:ContextMenuEvent):void { gotoNextSlide(); });
contextMenuItems.push(nextButton);
var previousButton:ContextMenuItem = new ContextMenuItem(PREVIOUS_BUTTON);
previousButton.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, menuItemHandler);
contextMenu.customItems.push(previousButton);
var previousButton:ContextMenuItem = new ContextMenuItem(ResourceUtil.getInstance().getString('bbb.presentation.backBtn.toolTip'));
previousButton.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, function(e:ContextMenuEvent):void { gotoPreviousSlide(); });
contextMenuItems.push(previousButton);
this.contextMenu = contextMenu;
this.customContextMenuItems = contextMenuItems;
}
private function menuItemHandler(e:ContextMenuEvent):void{
switch(e.target.caption){
case NEXT_BUTTON:
gotoNextSlide();
break;
case PREVIOUS_BUTTON:
gotoPreviousSlide();
break;
}
}
private function notifyOthersOfSharingPresentation(presentationName:String):void {
var shareEvent:PresenterCommands = new PresenterCommands(PresenterCommands.SHARE_PRESENTATION_COMMAND);
shareEvent.presentationName = presentationName;
@ -527,6 +512,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
if(Capabilities.hasAccessibility)
Accessibility.updateProperties();
addContextMenuItems();
}
private function localeChanged(e:Event):void{
@ -658,4 +645,4 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<!-- This spacer is to prevent the whiteboard toolbar from overlapping the fit-ot-page button -->
<mx:Spacer width="30" height="30" id="spacer4"/>
</mx:ControlBar>
</pres:MDIWindow>
</pres:CustomMdiWindow>

View File

@ -18,8 +18,8 @@
Author: Islam El-Ashi <ielashi@gmail.com>, <http://www.ielashi.com>
-->
<containers:MDIWindow xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:containers="flexlib.mdi.containers.*"
<containers:CustomMdiWindow xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:containers="org.bigbluebutton.common.*"
xmlns:mate="http://mate.asfusion.com/"
layout="absolute"
minWidth="160"
@ -38,8 +38,6 @@
import flash.utils.getTimer;
import flexlib.mdi.events.MDIWindowEvent;
import mx.accessibility.AlertAccImpl;
import mx.binding.utils.BindingUtils;
import mx.controls.Alert;
@ -210,4 +208,4 @@
<mx:Button width="26" height="26" click="btnSave_clickHandler(event)" icon="@Embed(source='images/ic_save_16px.png')" toolTip="{ResourceUtil.getInstance().getString('bbb.sharedNotes.save.toolTip')}"/>
</mx:HBox>
</mx:VBox>
</containers:MDIWindow>
</containers:CustomMdiWindow>

View File

@ -20,8 +20,8 @@
$Id: $
-->
<mdi:MDIWindow xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:mdi="flexlib.mdi.containers.*"
<mdi:CustomMdiWindow xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:mdi="org.bigbluebutton.common.*"
xmlns:flc="flexlib.controls.*"
implements="org.bigbluebutton.common.IBbbModuleWindow"
xmlns:mate="http://mate.asfusion.com/"
@ -614,4 +614,4 @@
</mx:VBox>
</mx:ControlBar>
</mdi:MDIWindow>
</mdi:CustomMdiWindow>

View File

@ -20,7 +20,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<MDIWindow xmlns="flexlib.mdi.containers.*"
<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="init()"
horizontalScrollPolicy="off"
@ -51,4 +51,4 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
]]>
</mx:Script>
</MDIWindow>
</CustomMdiWindow>

View File

@ -1,436 +1,435 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
This program is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 3.0 of the License, or (at your option) any later
version.
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<mx:VBox xmlns="flexlib.containers.*"
initialize="init()"
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:view="org.bigbluebutton.modules.whiteboard.views.*"
xmlns:wbBtns="org.bigbluebutton.modules.whiteboard.views.buttons.*"
xmlns:mate="http://mate.asfusion.com/"
creationComplete="onCreationComplete()"
visible="{showWhiteboardToolbar}"
includeInLayout="{showWhiteboardToolbar}"
styleName="whiteboardToolbarStyle"
hideEffect="{fadeOut}" showEffect="{fadeIn}">
<mate:Listener type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" method="presenterMode" />
<mate:Listener type="{MadePresenterEvent.SWITCH_TO_VIEWER_MODE}" method="viewerMode" />
<mate:Listener type="{StopWhiteboardModuleEvent.STOP_HIGHLIGHTER_MODULE_EVENT}" method="closeToolbar" />
<mate:Listener type="{ShortcutEvent.UNDO_WHITEBOARD}" method="undoShortcut" />
<mate:Listener type="{GraphicObjectFocusEvent.OBJECT_SELECTED}" method="graphicObjSelected" />
<mate:Listener type="{GraphicObjectFocusEvent.OBJECT_DESELECTED}" method="graphicObjDeselected" />
<mate:Listener type="{WhiteboardButtonEvent.WHITEBOARD_BUTTON_PRESSED}" method="handleWhiteboardButtonPressed"/>
<mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="refreshRole" />
<mate:Listener type="{NavigationEvent.GOTO_PAGE}" method="handleSlideChange" />
<mate:Listener type="{DisplaySlideEvent.DISPLAY_SLIDE_EVENT}" method="handleSlideLoaded" />
<mate:Listener type="{UploadEvent.PRESENTATION_READY}" method="handlePresentationSwitch" />
<mx:Style>
.colorPickerStyle {
backgroundColor:#E5E6E7;
columnCount:13;
horizontalGap:0;
previewHeight:22;
previewWidth:50;
swatchGridBackgroundColor:#000000;
swatchGridBorderSize:0;
swatchHeight:60;
swatchHighlightColor:#FFFFFF;
swatchHighlightSize:1;
swatchWidth:12;
textFieldWidth:72;
verticalGap:0;
}
</mx:Style>
<mx:Script>
<![CDATA[
import com.asfusion.mate.events.Listener;
import flash.ui.Keyboard;
import flexlib.mdi.events.MDIWindowEvent;
import mx.containers.ControlBar;
import mx.events.MoveEvent;
import mx.events.ResizeEvent;
import mx.managers.CursorManager;
import org.bigbluebutton.common.Images;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.main.events.MadePresenterEvent;
import org.bigbluebutton.main.events.ShortcutEvent;
import org.bigbluebutton.main.model.users.events.ChangeMyRole;
import org.bigbluebutton.modules.present.events.DisplaySlideEvent;
import org.bigbluebutton.modules.present.events.PresentationEvent;
import org.bigbluebutton.modules.present.events.NavigationEvent;
import org.bigbluebutton.modules.present.events.UploadEvent;
import org.bigbluebutton.modules.present.ui.views.PresentationWindow;
import org.bigbluebutton.modules.present.ui.views.SlideView;
import org.bigbluebutton.modules.whiteboard.business.shapes.DrawObject;
import org.bigbluebutton.modules.whiteboard.business.shapes.GraphicObject;
import org.bigbluebutton.modules.whiteboard.business.shapes.TextObject;
import org.bigbluebutton.modules.whiteboard.business.shapes.WhiteboardConstants;
import org.bigbluebutton.modules.whiteboard.events.GraphicObjectFocusEvent;
import org.bigbluebutton.modules.whiteboard.events.StopWhiteboardModuleEvent;
import org.bigbluebutton.modules.whiteboard.events.ToggleGridEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardButtonEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardDrawEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardPresenterEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardSettingResetEvent;
import org.bigbluebutton.modules.whiteboard.views.models.WhiteboardOptions;
import org.bigbluebutton.util.i18n.ResourceUtil;
private var images:Images = new Images();
[Bindable] private var hand_icon:Class = images.hand_icon;
[Bindable] private var pencil_icon:Class = images.pencil_icon;
[Bindable] private var undo_icon:Class = images.undo_icon;
[Bindable] private var delete_icon:Class = images.delete_icon;
[Bindable] private var rectangle_icon:Class = images.square_icon;
[Bindable] private var ellipse_icon:Class = images.circle_icon;
[Bindable] private var thick_icon:Class = images.whiteboard_thick;
[Bindable] private var thin_icon:Class = images.whiteboard_thin;
[Bindable] private var scribble_icon:Class = images.scribble_icon;
[Bindable] private var text_icon:Class = images.text_icon;
[Bindable] private var triangle_icon:Class = images.triangle_icon;
[Bindable] private var line_icon:Class = images.line_icon;
[Bindable] private var fill_icon:Class = images.fill_icon;
[Bindable] private var transparency_icon:Class = images.transparency_icon;
[Bindable] private var eraser_icon:Class = images.eraser_icon;
[Bindable] private var highlighter_icon:Class = images.highlighter_icon;
[Bindable] private var select_icon:Class = images.select_icon;
[Bindable] private var grid_icon:Class = images.grid_icon;
[Bindable] public var wbOptions:WhiteboardOptions;
[Bindable] private var baseIndex:int;
[Bindable] private var showWhiteboardToolbar:Boolean = false;
private static const LOG:String = "WB::WhiteboardToolbar - ";
private var mousedOver:Boolean = false;
private var slideLoaded:Boolean = false;
public var canvas:WhiteboardCanvas;
private var presentationWindow:PresentationWindow;
[Bindable] private var colorPickerColours:Array = ['0x000000', '0xFFFFFF' , '0xFF0000', '0xFF8800',
'0xCCFF00', '0x00FF00', '0x00FF88', '0x00FFFF', '0x0088FF', '0x0000FF', '0x8800FF', '0xFF00FF', '0xC0C0C0'];
private var _hideToolbarTimer:Timer = new Timer(500, 1);
private function init():void{
wbOptions = new WhiteboardOptions();
baseIndex = wbOptions.baseTabIndex;
}
private function onCreationComplete():void {
setToolType(WhiteboardConstants.TYPE_ZOOM, null);
_hideToolbarTimer.addEventListener(TimerEvent.TIMER, onHideToolbarTimerComplete);
}
private function handleWhiteboardButtonPressed(e:WhiteboardButtonEvent):void {
setToolType(e.graphicType, e.toolType);
}
private function setToolType(graphicType:String, toolType:String):void {
if (graphicType == WhiteboardConstants.TYPE_CLEAR) {
dispatchEvent(new WhiteboardDrawEvent(WhiteboardDrawEvent.CLEAR));
} else if (graphicType == WhiteboardConstants.TYPE_UNDO) {
sendUndoCommand();
} else {
canvas.setGraphicType(graphicType);
canvas.setTool(toolType);
if (panzoomBtn != null) {
panzoomBtn.setTool(graphicType, toolType);
}
if (scribbleBtn != null) {
scribbleBtn.setTool(graphicType, toolType);
}
if (rectangleBtn != null) {
rectangleBtn.setTool(graphicType, toolType);
}
if (circleBtn != null) {
circleBtn.setTool(graphicType, toolType);
}
if (triangleBtn != null) {
triangleBtn.setTool(graphicType, toolType);
}
if (lineBtn != null) {
lineBtn.setTool(graphicType, toolType);
}
if (textBtn != null) {
textBtn.setTool(graphicType, toolType);
}
}
}
protected function changeColor(e:Event):void {
canvas.changeColor(e);
}
protected function changeFillColor(e:Event):void {
canvas.changeFillColor(e);
}
protected function changeThickness(e:Event):void {
canvas.changeThickness(e);
}
protected function toggleFill():void {
canvas.toggleFill();
}
protected function toggleTransparency():void {
canvas.toggleTransparency();
}
private function presenterMode(e:MadePresenterEvent):void {
if (canvas == null) return;
canvas.makeTextObjectsEditable(e);
setToolType(WhiteboardConstants.TYPE_ZOOM, null);
}
private function viewerMode(e:MadePresenterEvent):void {
canvas.makeTextObjectsUneditable(e);
if (!toolbarAllowed()) {
checkVisibility();
if (panzoomBtn) {
panzoomBtn.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
}
}
private function undoShortcut(e:ShortcutEvent):void{
trace(LOG + "Ctrl-Z got into undoShortcut");
sendUndoCommand();
}
private function sendUndoCommand():void {
// if (!canvas.isPageEmpty()) {
dispatchEvent(new WhiteboardDrawEvent(WhiteboardDrawEvent.UNDO));
// }
}
public function positionToolbar(window:PresentationWindow):void {
trace(LOG + "Positioning whiteboard toolbar");
presentationWindow = window;
presentationWindow.addEventListener(MoveEvent.MOVE, setPositionAndDepth);
presentationWindow.addEventListener(ResizeEvent.RESIZE, setPositionAndDepth);
presentationWindow.addEventListener(MouseEvent.CLICK, setPositionAndDepth);
if (!wbOptions.keepToolbarVisible) {
window.presCtrlBar.addEventListener(MouseEvent.ROLL_OVER, handleMouseOut);
window.presCtrlBar.addEventListener(MouseEvent.ROLL_OUT, handleMouseIn);
window.addEventListener(MouseEvent.ROLL_OVER, handleMouseIn);
window.addEventListener(MouseEvent.ROLL_OUT, handleMouseOut);
this.addEventListener(MouseEvent.ROLL_OVER, handleMouseIn);
this.addEventListener(MouseEvent.ROLL_OUT, handleMouseOut);
} else {
var listener1:Listener = new Listener();
listener1.method = checkVisibility;
listener1.type = MadePresenterEvent.SWITCH_TO_PRESENTER_MODE;
var listener2:Listener = new Listener();
listener2.method = checkVisibility;
listener2.type = MadePresenterEvent.SWITCH_TO_VIEWER_MODE;
//Do an initial check to see if the toolbar should be visible
checkVisibility();
}
}
private function refreshRole(e:ChangeMyRole):void {
checkVisibility();
}
private function checkVisibility(e:MadePresenterEvent = null):void {
if (toolbarAllowed() && slideLoaded && (wbOptions.keepToolbarVisible || mousedOver) && !presentationWindow.minimized) {
setPositionAndDepth();
showToolbar();
} else {
hideToolbar();
}
}
private function showToolbar():void {
_hideToolbarTimer.reset();
showWhiteboardToolbar = true;
}
private function hideToolbar():void {
_hideToolbarTimer.reset();
_hideToolbarTimer.start();
}
private function onHideToolbarTimerComplete(event:TimerEvent):void {
showWhiteboardToolbar = false;
}
private function setPositionAndDepth(e:Event = null):void {
this.x = presentationWindow.x + presentationWindow.width - 43;
this.y = presentationWindow.y + 30;
parent.setChildIndex(this, parent.numChildren - 1);
}
private function closeToolbar(e:StopWhiteboardModuleEvent):void {
parent.removeChild(this);
}
private function handleMouseIn(e:MouseEvent):void {
mousedOver = true;
checkVisibility();
}
private function handleMouseOut(e:MouseEvent = null):void {
mousedOver = false;
checkVisibility();
}
private function handleSlideLoaded(e:DisplaySlideEvent):void {
slideLoaded = true;
checkVisibility();
}
private function handleSlideChange(e:NavigationEvent):void {
slideLoaded = false;
// don't switch the toolbar button on slide change
checkVisibility();
}
private function handlePresentationSwitch(e:UploadEvent):void {
slideLoaded = false;
if (panzoomBtn) {
panzoomBtn.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
checkVisibility();
}
private function graphicObjSelected(event:GraphicObjectFocusEvent):void {
var gobj:GraphicObject = event.data;
}
private function graphicObjDeselected(event:GraphicObjectFocusEvent):void {
var gobj:GraphicObject = event.data;
}
private function toolbarAllowed():Boolean {
if (wbOptions) {
if (wbOptions.whiteboardAccess == "presenter")
return isPresenter;
else if (wbOptions.whiteboardAccess == "moderator")
return isModerator || isPresenter;
else if (wbOptions.whiteboardAccess == "all")
return true;
else
return false;
} else
return false;
}
/** Helper method to test whether this user is the presenter */
private function get isPresenter():Boolean {
return UsersUtil.amIPresenter();
}
private function get isModerator():Boolean {
return UsersUtil.amIModerator();
}
]]>
</mx:Script>
<mx:Fade id="fadeOut" duration="200" alphaFrom="1.0" alphaTo="0.0" />
<mx:Fade id="fadeIn" duration="200" alphaFrom="0.0" alphaTo="1.0" />
<!-- Now, every 'tool' has two types of identifiers, one is found in WhiteboardConstants
that identifies the "category" of the tool (ex. shape vs text), and the other specifies the
tool itself (ex. line tool vs triangle tool, even though both are "shapes")
-->
<wbBtns:PanZoomButton id="panzoomBtn"
tabIndex="{baseIndex}"
visible="{showWhiteboardToolbar}"/>
<mx:Spacer height="10" visible="{showWhiteboardToolbar}"/>
<wbBtns:ScribbleButton id="scribbleBtn"
tabIndex="{baseIndex+1}"
visible="{showWhiteboardToolbar}"/>
<wbBtns:RectangleButton id="rectangleBtn"
tabIndex="{baseIndex+2}"
visible="{showWhiteboardToolbar}"/>
<wbBtns:CircleButton id="circleBtn"
tabIndex="{baseIndex+3}"
visible="{showWhiteboardToolbar}"/>
<wbBtns:TriangleButton id="triangleBtn"
tabIndex="{baseIndex+4}"
visible="{showWhiteboardToolbar}"/>
<wbBtns:LineButton id="lineBtn"
tabIndex="{baseIndex+5}"
visible="{showWhiteboardToolbar}"/>
<wbBtns:TextButton id="textBtn"
tabIndex="{baseIndex+6}"
visible="{showWhiteboardToolbar}"/>
<mx:Spacer height="5" visible="{showWhiteboardToolbar}"/>
<wbBtns:ClearButton id="clearBtn"
tabIndex="{baseIndex+7}"
visible="{showWhiteboardToolbar}"/>
<wbBtns:UndoButton id="undoBtn"
tabIndex="{baseIndex+8}"
visible="{showWhiteboardToolbar}"/>
<mx:Spacer height="5" visible="{showWhiteboardToolbar}"/>
<!--
Properties that were removed from original color picker:
swatchPanelStyleName="colorPickerStyle"
dataProvider="{colorPickerColours}"
-->
<!-- Layout is really bad right now, and is confusing. Basically, there are two
of ColorPickers, one for the "line" color for the outlines of shapes, and the other for
the "fill" color that is used only if "fill" is enabled in WhiteboardCanvasModel
-->
<mx:ColorPicker change="changeColor(event)" id="cpik" visible="{showWhiteboardToolbar}"
selectedColor="0x000000" width="30" dataProvider="{colorPickerColours}" swatchPanelStyleName="colorPickerStyle"
toolTip="{ResourceUtil.getInstance().getString('bbb.highlighter.toolbar.color')}"
tabIndex="{baseIndex+9}"
accessibilityName="{ResourceUtil.getInstance().getString('bbb.highlighter.toolbar.color')}"/>
<mx:Spacer height="3" visible="{showWhiteboardToolbar}"/>
<mx:Image source="{thick_icon}" horizontalAlign="center" width="30" visible="{showWhiteboardToolbar}"/>
<mx:VSlider height="50" id="sld" change="changeThickness(event)" visible="{showWhiteboardToolbar}"
toolTip="{ResourceUtil.getInstance().getString('bbb.highlighter.toolbar.thickness.accessibilityName')}"
minimum="1" maximum="30"
useHandCursor="true" value="2" showDataTip="true" snapInterval="1" dataTipOffset="0" labelOffset="0"
tabIndex="{baseIndex+10}"
accessibilityName="{ResourceUtil.getInstance().getString('bbb.highlighter.toolbar.thickness.accessibilityName')}" />
<mx:Image source="{thin_icon}" horizontalAlign="center" width="30" visible="{showWhiteboardToolbar}"/>
</mx:VBox>
<?xml version="1.0" encoding="utf-8"?>
<!--
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
This program is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 3.0 of the License, or (at your option) any later
version.
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<mx:VBox xmlns="flexlib.containers.*"
initialize="init()"
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:view="org.bigbluebutton.modules.whiteboard.views.*"
xmlns:wbBtns="org.bigbluebutton.modules.whiteboard.views.buttons.*"
xmlns:mate="http://mate.asfusion.com/"
creationComplete="onCreationComplete()"
visible="{showWhiteboardToolbar}"
includeInLayout="{showWhiteboardToolbar}"
styleName="whiteboardToolbarStyle"
hideEffect="{fadeOut}" showEffect="{fadeIn}">
<mate:Listener type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" method="presenterMode" />
<mate:Listener type="{MadePresenterEvent.SWITCH_TO_VIEWER_MODE}" method="viewerMode" />
<mate:Listener type="{StopWhiteboardModuleEvent.STOP_HIGHLIGHTER_MODULE_EVENT}" method="closeToolbar" />
<mate:Listener type="{ShortcutEvent.UNDO_WHITEBOARD}" method="undoShortcut" />
<mate:Listener type="{GraphicObjectFocusEvent.OBJECT_SELECTED}" method="graphicObjSelected" />
<mate:Listener type="{GraphicObjectFocusEvent.OBJECT_DESELECTED}" method="graphicObjDeselected" />
<mate:Listener type="{WhiteboardButtonEvent.WHITEBOARD_BUTTON_PRESSED}" method="handleWhiteboardButtonPressed"/>
<mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="refreshRole" />
<mate:Listener type="{NavigationEvent.GOTO_PAGE}" method="handleSlideChange" />
<mate:Listener type="{DisplaySlideEvent.DISPLAY_SLIDE_EVENT}" method="handleSlideLoaded" />
<mate:Listener type="{UploadEvent.PRESENTATION_READY}" method="handlePresentationSwitch" />
<mx:Style>
.colorPickerStyle {
backgroundColor:#E5E6E7;
columnCount:13;
horizontalGap:0;
previewHeight:22;
previewWidth:50;
swatchGridBackgroundColor:#000000;
swatchGridBorderSize:0;
swatchHeight:60;
swatchHighlightColor:#FFFFFF;
swatchHighlightSize:1;
swatchWidth:12;
textFieldWidth:72;
verticalGap:0;
}
</mx:Style>
<mx:Script>
<![CDATA[
import com.asfusion.mate.events.Listener;
import flash.ui.Keyboard;
import mx.containers.ControlBar;
import mx.events.MoveEvent;
import mx.events.ResizeEvent;
import mx.managers.CursorManager;
import org.bigbluebutton.common.Images;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.main.events.MadePresenterEvent;
import org.bigbluebutton.main.events.ShortcutEvent;
import org.bigbluebutton.main.model.users.events.ChangeMyRole;
import org.bigbluebutton.modules.present.events.DisplaySlideEvent;
import org.bigbluebutton.modules.present.events.PresentationEvent;
import org.bigbluebutton.modules.present.events.NavigationEvent;
import org.bigbluebutton.modules.present.events.UploadEvent;
import org.bigbluebutton.modules.present.ui.views.PresentationWindow;
import org.bigbluebutton.modules.present.ui.views.SlideView;
import org.bigbluebutton.modules.whiteboard.business.shapes.DrawObject;
import org.bigbluebutton.modules.whiteboard.business.shapes.GraphicObject;
import org.bigbluebutton.modules.whiteboard.business.shapes.TextObject;
import org.bigbluebutton.modules.whiteboard.business.shapes.WhiteboardConstants;
import org.bigbluebutton.modules.whiteboard.events.GraphicObjectFocusEvent;
import org.bigbluebutton.modules.whiteboard.events.StopWhiteboardModuleEvent;
import org.bigbluebutton.modules.whiteboard.events.ToggleGridEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardButtonEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardDrawEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardPresenterEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardSettingResetEvent;
import org.bigbluebutton.modules.whiteboard.views.models.WhiteboardOptions;
import org.bigbluebutton.util.i18n.ResourceUtil;
private var images:Images = new Images();
[Bindable] private var hand_icon:Class = images.hand_icon;
[Bindable] private var pencil_icon:Class = images.pencil_icon;
[Bindable] private var undo_icon:Class = images.undo_icon;
[Bindable] private var delete_icon:Class = images.delete_icon;
[Bindable] private var rectangle_icon:Class = images.square_icon;
[Bindable] private var ellipse_icon:Class = images.circle_icon;
[Bindable] private var thick_icon:Class = images.whiteboard_thick;
[Bindable] private var thin_icon:Class = images.whiteboard_thin;
[Bindable] private var scribble_icon:Class = images.scribble_icon;
[Bindable] private var text_icon:Class = images.text_icon;
[Bindable] private var triangle_icon:Class = images.triangle_icon;
[Bindable] private var line_icon:Class = images.line_icon;
[Bindable] private var fill_icon:Class = images.fill_icon;
[Bindable] private var transparency_icon:Class = images.transparency_icon;
[Bindable] private var eraser_icon:Class = images.eraser_icon;
[Bindable] private var highlighter_icon:Class = images.highlighter_icon;
[Bindable] private var select_icon:Class = images.select_icon;
[Bindable] private var grid_icon:Class = images.grid_icon;
[Bindable] public var wbOptions:WhiteboardOptions;
[Bindable] private var baseIndex:int;
[Bindable] private var showWhiteboardToolbar:Boolean = false;
private static const LOG:String = "WB::WhiteboardToolbar - ";
private var mousedOver:Boolean = false;
private var slideLoaded:Boolean = false;
public var canvas:WhiteboardCanvas;
private var presentationWindow:PresentationWindow;
[Bindable] private var colorPickerColours:Array = ['0x000000', '0xFFFFFF' , '0xFF0000', '0xFF8800',
'0xCCFF00', '0x00FF00', '0x00FF88', '0x00FFFF', '0x0088FF', '0x0000FF', '0x8800FF', '0xFF00FF', '0xC0C0C0'];
private var _hideToolbarTimer:Timer = new Timer(500, 1);
private function init():void{
wbOptions = new WhiteboardOptions();
baseIndex = wbOptions.baseTabIndex;
}
private function onCreationComplete():void {
setToolType(WhiteboardConstants.TYPE_ZOOM, null);
_hideToolbarTimer.addEventListener(TimerEvent.TIMER, onHideToolbarTimerComplete);
}
private function handleWhiteboardButtonPressed(e:WhiteboardButtonEvent):void {
setToolType(e.graphicType, e.toolType);
}
private function setToolType(graphicType:String, toolType:String):void {
if (graphicType == WhiteboardConstants.TYPE_CLEAR) {
dispatchEvent(new WhiteboardDrawEvent(WhiteboardDrawEvent.CLEAR));
} else if (graphicType == WhiteboardConstants.TYPE_UNDO) {
sendUndoCommand();
} else {
canvas.setGraphicType(graphicType);
canvas.setTool(toolType);
if (panzoomBtn != null) {
panzoomBtn.setTool(graphicType, toolType);
}
if (scribbleBtn != null) {
scribbleBtn.setTool(graphicType, toolType);
}
if (rectangleBtn != null) {
rectangleBtn.setTool(graphicType, toolType);
}
if (circleBtn != null) {
circleBtn.setTool(graphicType, toolType);
}
if (triangleBtn != null) {
triangleBtn.setTool(graphicType, toolType);
}
if (lineBtn != null) {
lineBtn.setTool(graphicType, toolType);
}
if (textBtn != null) {
textBtn.setTool(graphicType, toolType);
}
}
}
protected function changeColor(e:Event):void {
canvas.changeColor(e);
}
protected function changeFillColor(e:Event):void {
canvas.changeFillColor(e);
}
protected function changeThickness(e:Event):void {
canvas.changeThickness(e);
}
protected function toggleFill():void {
canvas.toggleFill();
}
protected function toggleTransparency():void {
canvas.toggleTransparency();
}
private function presenterMode(e:MadePresenterEvent):void {
if (canvas == null) return;
canvas.makeTextObjectsEditable(e);
setToolType(WhiteboardConstants.TYPE_ZOOM, null);
}
private function viewerMode(e:MadePresenterEvent):void {
canvas.makeTextObjectsUneditable(e);
if (!toolbarAllowed()) {
checkVisibility();
if (panzoomBtn) {
panzoomBtn.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
}
}
private function undoShortcut(e:ShortcutEvent):void{
trace(LOG + "Ctrl-Z got into undoShortcut");
sendUndoCommand();
}
private function sendUndoCommand():void {
// if (!canvas.isPageEmpty()) {
dispatchEvent(new WhiteboardDrawEvent(WhiteboardDrawEvent.UNDO));
// }
}
public function positionToolbar(window:PresentationWindow):void {
trace(LOG + "Positioning whiteboard toolbar");
presentationWindow = window;
presentationWindow.addEventListener(MoveEvent.MOVE, setPositionAndDepth);
presentationWindow.addEventListener(ResizeEvent.RESIZE, setPositionAndDepth);
presentationWindow.addEventListener(MouseEvent.CLICK, setPositionAndDepth);
if (!wbOptions.keepToolbarVisible) {
window.presCtrlBar.addEventListener(MouseEvent.ROLL_OVER, handleMouseOut);
window.presCtrlBar.addEventListener(MouseEvent.ROLL_OUT, handleMouseIn);
window.addEventListener(MouseEvent.ROLL_OVER, handleMouseIn);
window.addEventListener(MouseEvent.ROLL_OUT, handleMouseOut);
this.addEventListener(MouseEvent.ROLL_OVER, handleMouseIn);
this.addEventListener(MouseEvent.ROLL_OUT, handleMouseOut);
} else {
var listener1:Listener = new Listener();
listener1.method = checkVisibility;
listener1.type = MadePresenterEvent.SWITCH_TO_PRESENTER_MODE;
var listener2:Listener = new Listener();
listener2.method = checkVisibility;
listener2.type = MadePresenterEvent.SWITCH_TO_VIEWER_MODE;
//Do an initial check to see if the toolbar should be visible
checkVisibility();
}
}
private function refreshRole(e:ChangeMyRole):void {
checkVisibility();
}
private function checkVisibility(e:MadePresenterEvent = null):void {
if (toolbarAllowed() && slideLoaded && (wbOptions.keepToolbarVisible || mousedOver) && !presentationWindow.minimized) {
setPositionAndDepth();
showToolbar();
} else {
hideToolbar();
}
}
private function showToolbar():void {
_hideToolbarTimer.reset();
showWhiteboardToolbar = true;
}
private function hideToolbar():void {
_hideToolbarTimer.reset();
_hideToolbarTimer.start();
}
private function onHideToolbarTimerComplete(event:TimerEvent):void {
showWhiteboardToolbar = false;
}
private function setPositionAndDepth(e:Event = null):void {
this.x = presentationWindow.x + presentationWindow.width - 43;
this.y = presentationWindow.y + 30;
parent.setChildIndex(this, parent.numChildren - 1);
}
private function closeToolbar(e:StopWhiteboardModuleEvent):void {
parent.removeChild(this);
}
private function handleMouseIn(e:MouseEvent):void {
mousedOver = true;
checkVisibility();
}
private function handleMouseOut(e:MouseEvent = null):void {
mousedOver = false;
checkVisibility();
}
private function handleSlideLoaded(e:DisplaySlideEvent):void {
slideLoaded = true;
checkVisibility();
}
private function handleSlideChange(e:NavigationEvent):void {
slideLoaded = false;
// don't switch the toolbar button on slide change
checkVisibility();
}
private function handlePresentationSwitch(e:UploadEvent):void {
slideLoaded = false;
if (panzoomBtn) {
panzoomBtn.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
checkVisibility();
}
private function graphicObjSelected(event:GraphicObjectFocusEvent):void {
var gobj:GraphicObject = event.data;
}
private function graphicObjDeselected(event:GraphicObjectFocusEvent):void {
var gobj:GraphicObject = event.data;
}
private function toolbarAllowed():Boolean {
if (wbOptions) {
if (wbOptions.whiteboardAccess == "presenter")
return isPresenter;
else if (wbOptions.whiteboardAccess == "moderator")
return isModerator || isPresenter;
else if (wbOptions.whiteboardAccess == "all")
return true;
else
return false;
} else
return false;
}
/** Helper method to test whether this user is the presenter */
private function get isPresenter():Boolean {
return UsersUtil.amIPresenter();
}
private function get isModerator():Boolean {
return UsersUtil.amIModerator();
}
]]>
</mx:Script>
<mx:Fade id="fadeOut" duration="200" alphaFrom="1.0" alphaTo="0.0" />
<mx:Fade id="fadeIn" duration="200" alphaFrom="0.0" alphaTo="1.0" />
<!-- Now, every 'tool' has two types of identifiers, one is found in WhiteboardConstants
that identifies the "category" of the tool (ex. shape vs text), and the other specifies the
tool itself (ex. line tool vs triangle tool, even though both are "shapes")
-->
<wbBtns:PanZoomButton id="panzoomBtn"
tabIndex="{baseIndex}"
visible="{showWhiteboardToolbar}"/>
<mx:Spacer height="10" visible="{showWhiteboardToolbar}"/>
<wbBtns:ScribbleButton id="scribbleBtn"
tabIndex="{baseIndex+1}"
visible="{showWhiteboardToolbar}"/>
<wbBtns:RectangleButton id="rectangleBtn"
tabIndex="{baseIndex+2}"
visible="{showWhiteboardToolbar}"/>
<wbBtns:CircleButton id="circleBtn"
tabIndex="{baseIndex+3}"
visible="{showWhiteboardToolbar}"/>
<wbBtns:TriangleButton id="triangleBtn"
tabIndex="{baseIndex+4}"
visible="{showWhiteboardToolbar}"/>
<wbBtns:LineButton id="lineBtn"
tabIndex="{baseIndex+5}"
visible="{showWhiteboardToolbar}"/>
<wbBtns:TextButton id="textBtn"
tabIndex="{baseIndex+6}"
visible="{showWhiteboardToolbar}"/>
<mx:Spacer height="5" visible="{showWhiteboardToolbar}"/>
<wbBtns:ClearButton id="clearBtn"
tabIndex="{baseIndex+7}"
visible="{showWhiteboardToolbar}"/>
<wbBtns:UndoButton id="undoBtn"
tabIndex="{baseIndex+8}"
visible="{showWhiteboardToolbar}"/>
<mx:Spacer height="5" visible="{showWhiteboardToolbar}"/>
<!--
Properties that were removed from original color picker:
swatchPanelStyleName="colorPickerStyle"
dataProvider="{colorPickerColours}"
-->
<!-- Layout is really bad right now, and is confusing. Basically, there are two
of ColorPickers, one for the "line" color for the outlines of shapes, and the other for
the "fill" color that is used only if "fill" is enabled in WhiteboardCanvasModel
-->
<mx:ColorPicker change="changeColor(event)" id="cpik" visible="{showWhiteboardToolbar}"
selectedColor="0x000000" width="30" dataProvider="{colorPickerColours}" swatchPanelStyleName="colorPickerStyle"
toolTip="{ResourceUtil.getInstance().getString('bbb.highlighter.toolbar.color')}"
tabIndex="{baseIndex+9}"
accessibilityName="{ResourceUtil.getInstance().getString('bbb.highlighter.toolbar.color')}"/>
<mx:Spacer height="3" visible="{showWhiteboardToolbar}"/>
<mx:Image source="{thick_icon}" horizontalAlign="center" width="30" visible="{showWhiteboardToolbar}"/>
<mx:VSlider height="50" id="sld" change="changeThickness(event)" visible="{showWhiteboardToolbar}"
toolTip="{ResourceUtil.getInstance().getString('bbb.highlighter.toolbar.thickness.accessibilityName')}"
minimum="1" maximum="30"
useHandCursor="true" value="2" showDataTip="true" snapInterval="1" dataTipOffset="0" labelOffset="0"
tabIndex="{baseIndex+10}"
accessibilityName="{ResourceUtil.getInstance().getString('bbb.highlighter.toolbar.thickness.accessibilityName')}" />
<mx:Image source="{thin_icon}" horizontalAlign="center" width="30" visible="{showWhiteboardToolbar}"/>
</mx:VBox>