first pass at multi whiteboard cursors

This commit is contained in:
Chad Pilkey 2017-05-25 23:45:27 -04:00
parent b6176ac736
commit 09ec1e6151
44 changed files with 525 additions and 336 deletions

View File

@ -76,7 +76,6 @@ public interface IBigBlueButtonInGW {
void clear(String meetingID);
void removePresentation(String meetingID, String presentationID);
void getPresentationInfo(String meetingID, String requesterID, String replyTo);
void sendCursorUpdate(String meetingID, double xPercent, double yPercent);
void resizeAndMoveSlide(String meetingID, double xOffset, double yOffset, double widthRatio, double heightRatio);
void gotoSlide(String meetingID, String page);
void sharePresentation(String meetingID, String presentationID, boolean share);
@ -110,7 +109,8 @@ public interface IBigBlueButtonInGW {
void clearPublicChatHistory(String meetingID, String requesterID);
// Whiteboard
void sendWhiteboardAnnotation(String meetingID, String requesterID, java.util.Map<String, Object> annotation);
void sendWhiteboardAnnotation(String meetingID, String requesterID, java.util.Map<String, Object> annotation);
void sendCursorPosition(String meetingID, String requesterID, double xPercent, double yPercent);
void requestWhiteboardAnnotationHistory(String meetingID, String requesterID, String whiteboardId, String replyTo);
void clearWhiteboard(String meetingID, String requesterID, String whiteboardId);
void undoWhiteboard(String meetingID, String requesterID, String whiteboardId);

View File

@ -10,7 +10,6 @@ import org.bigbluebutton.common.messages.RemovePresentationMessage;
import org.bigbluebutton.common.messages.ResizeAndMoveSlideMessage;
import org.bigbluebutton.common.messages.SendConversionCompletedMessage;
import org.bigbluebutton.common.messages.SendConversionUpdateMessage;
import org.bigbluebutton.common.messages.SendCursorUpdateMessage;
import org.bigbluebutton.common.messages.SendPageCountErrorMessage;
import org.bigbluebutton.common.messages.SendSlideGeneratedMessage;
import org.bigbluebutton.common.messages.SharePresentationMessage;
@ -118,9 +117,6 @@ public class PresentationMessageListener implements MessageHandler {
} else if (RemovePresentationMessage.REMOVE_PRESENTATION.equals(messageName)) {
RemovePresentationMessage msg = RemovePresentationMessage.fromJson(message);
bbbInGW.removePresentation(msg.meetingId, msg.presentationId);
} else if (SendCursorUpdateMessage.SEND_CURSOR_UPDATE.equals(messageName)) {
SendCursorUpdateMessage msg = SendCursorUpdateMessage.fromJson(message);
bbbInGW.sendCursorUpdate(msg.meetingId, msg.xPercent, msg.yPercent);
} else if (SharePresentationMessage.SHARE_PRESENTATION.equals(messageName)) {
SharePresentationMessage msg = SharePresentationMessage.fromJson(message);
bbbInGW.sharePresentation(msg.meetingId, msg.presentationId, msg.share);

View File

@ -7,6 +7,7 @@ import org.bigbluebutton.common.messages.ModifyWhiteboardAccessRequestMessage;
import org.bigbluebutton.common.messages.GetWhiteboardAccessRequestMessage;
import org.bigbluebutton.common.messages.MessagingConstants;
import org.bigbluebutton.common.messages.RequestWhiteboardAnnotationHistoryRequestMessage;
import org.bigbluebutton.common.messages.SendCursorPositionMessage;
import org.bigbluebutton.common.messages.SendWhiteboardAnnotationRequestMessage;
import org.bigbluebutton.common.messages.UndoWhiteboardRequest;
import org.bigbluebutton.core.api.IBigBlueButtonInGW;
@ -52,6 +53,9 @@ public class WhiteboardMessageReceiver implements MessageHandler {
} else if (SendWhiteboardAnnotationRequestMessage.SEND_WHITEBOARD_ANNOTATION_REQUEST.equals(messageName)) {
SendWhiteboardAnnotationRequestMessage msg = SendWhiteboardAnnotationRequestMessage.fromJson(message);
bbbInGW.sendWhiteboardAnnotation(msg.meetingId, msg.requesterId, msg.annotation);
} else if (SendCursorPositionMessage.SEND_CURSOR_POSITION.equals(messageName)) {
SendCursorPositionMessage msg = SendCursorPositionMessage.fromJson(message);
bbbInGW.sendCursorPosition(msg.meetingId, msg.requesterId, msg.xPercent, msg.yPercent);
}
}
}

View File

@ -18,13 +18,17 @@
*/
package org.bigbluebutton.core.recorders.events;
public class CursorUpdateRecordEvent extends AbstractPresentationRecordEvent{
public class CursorUpdateRecordEvent extends AbstractWhiteboardRecordEvent{
public CursorUpdateRecordEvent() {
super();
setEvent("CursorMoveEvent");
}
public void setUserId(String userId) {
eventMap.put("userId", userId);
}
public void setXPercent(double percent) {
eventMap.put("xOffset", Double.toString(percent));
}

View File

@ -367,10 +367,6 @@ class BigBlueButtonInGW(
eventBus.publish(BigBlueButtonEvent(meetingID, new GetPresentationInfo(meetingID, requesterID, replyTo)))
}
def sendCursorUpdate(meetingID: String, xPercent: Double, yPercent: Double) {
eventBus.publish(BigBlueButtonEvent(meetingID, new SendCursorUpdate(meetingID, xPercent, yPercent)))
}
def resizeAndMoveSlide(meetingID: String, xOffset: Double, yOffset: Double, widthRatio: Double, heightRatio: Double) {
eventBus.publish(BigBlueButtonEvent(meetingID, new ResizeAndMoveSlide(meetingID, xOffset, yOffset, widthRatio, heightRatio)))
}
@ -466,6 +462,10 @@ class BigBlueButtonInGW(
}
}
def sendCursorPosition(meetingID: String, requesterID: String, xPercent: Double, yPercent: Double) {
eventBus.publish(BigBlueButtonEvent(meetingID, new SendCursorPositionRequest(meetingID, requesterID, xPercent, yPercent)))
}
def requestWhiteboardAnnotationHistory(meetingID: String, requesterID: String, whiteboardId: String, replyTo: String) {
eventBus.publish(BigBlueButtonEvent(meetingID, new GetWhiteboardShapesRequest(meetingID, requesterID, whiteboardId, replyTo)))
}

View File

@ -86,7 +86,6 @@ class MessageSenderActor(val service: MessageSender)
case msg: ClearPresentationOutMsg => handleClearPresentationOutMsg(msg)
case msg: RemovePresentationOutMsg => handleRemovePresentationOutMsg(msg)
case msg: GetPresentationInfoOutMsg => handleGetPresentationInfoOutMsg(msg)
case msg: SendCursorUpdateOutMsg => handleSendCursorUpdateOutMsg(msg)
case msg: ResizeAndMoveSlideOutMsg => handleResizeAndMoveSlideOutMsg(msg)
case msg: GotoSlideOutMsg => handleGotoSlideOutMsg(msg)
case msg: SharePresentationOutMsg => handleSharePresentationOutMsg(msg)
@ -137,6 +136,7 @@ class MessageSenderActor(val service: MessageSender)
case msg: LockLayoutEvent => handleLockLayoutEvent(msg)
case msg: GetWhiteboardShapesReply => handleGetWhiteboardShapesReply(msg)
case msg: SendWhiteboardAnnotationEvent => handleSendWhiteboardAnnotationEvent(msg)
case msg: CursorPositionUpdatedEvent => handleCursorPositionUpdatedEvent(msg)
case msg: ClearWhiteboardEvent => handleClearWhiteboardEvent(msg)
case msg: UndoWhiteboardEvent => handleUndoWhiteboardEvent(msg)
case msg: ModifiedWhiteboardAccessEvent => handleModifiedWhiteboardAccessEvent(msg)
@ -381,11 +381,6 @@ class MessageSenderActor(val service: MessageSender)
service.send(MessagingConstants.FROM_PRESENTATION_CHANNEL, json)
}
private def handleSendCursorUpdateOutMsg(msg: SendCursorUpdateOutMsg) {
val json = PesentationMessageToJsonConverter.sendCursorUpdateOutMsgToJson(msg)
service.send(MessagingConstants.FROM_PRESENTATION_CHANNEL, json)
}
private def handleResizeAndMoveSlideOutMsg(msg: ResizeAndMoveSlideOutMsg) {
val json = PesentationMessageToJsonConverter.resizeAndMoveSlideOutMsgToJson(msg)
service.send(MessagingConstants.FROM_PRESENTATION_CHANNEL, json)
@ -748,6 +743,11 @@ class MessageSenderActor(val service: MessageSender)
service.send(MessagingConstants.FROM_WHITEBOARD_CHANNEL, json)
}
private def handleCursorPositionUpdatedEvent(msg: CursorPositionUpdatedEvent) {
val json = WhiteboardMessageToJsonConverter.cursorPositionUpdatedEventToJson(msg)
service.send(MessagingConstants.FROM_WHITEBOARD_CHANNEL, json)
}
private def handleClearWhiteboardEvent(msg: ClearWhiteboardEvent) {
val json = WhiteboardMessageToJsonConverter.clearWhiteboardEventToJson(msg)
service.send(MessagingConstants.FROM_WHITEBOARD_CHANNEL, json)

View File

@ -66,7 +66,6 @@ class RecorderActor(val recorder: RecorderApplication)
case msg: ClearPublicChatHistoryReply => handleClearPublicChatHistoryReply(msg)
case msg: ClearPresentationOutMsg => handleClearPresentationOutMsg(msg)
case msg: RemovePresentationOutMsg => handleRemovePresentationOutMsg(msg)
case msg: SendCursorUpdateOutMsg => handleSendCursorUpdateOutMsg(msg)
case msg: ResizeAndMoveSlideOutMsg => handleResizeAndMoveSlideOutMsg(msg)
case msg: GotoSlideOutMsg => handleGotoSlideOutMsg(msg)
case msg: SharePresentationOutMsg => handleSharePresentationOutMsg(msg)
@ -86,6 +85,7 @@ class RecorderActor(val recorder: RecorderApplication)
case msg: VoiceRecordingStarted => handleVoiceRecordingStarted(msg)
case msg: VoiceRecordingStopped => handleVoiceRecordingStopped(msg)
case msg: SendWhiteboardAnnotationEvent => handleSendWhiteboardAnnotationEvent(msg)
case msg: CursorPositionUpdatedEvent => handleCursorPositionUpdatedEvent(msg)
case msg: ClearWhiteboardEvent => handleClearWhiteboardEvent(msg)
case msg: UndoWhiteboardEvent => handleUndoWhiteboardEvent(msg)
case msg: EditCaptionHistoryReply => handleEditCaptionHistoryReply(msg)
@ -196,18 +196,6 @@ class RecorderActor(val recorder: RecorderApplication)
}
}
private def handleSendCursorUpdateOutMsg(msg: SendCursorUpdateOutMsg) {
if (msg.recorded) {
val event = new CursorUpdateRecordEvent();
event.setMeetingId(msg.meetingID);
event.setTimestamp(TimestampGenerator.generateTimestamp);
event.setXPercent(msg.xPercent);
event.setYPercent(msg.yPercent);
recorder.record(msg.meetingID, event);
}
}
private def handleEndAndKickAll(msg: EndAndKickAll): Unit = {
if (msg.recorded) {
val ev = new ParticipantEndAndKickAllRecordEvent();
@ -444,6 +432,19 @@ class RecorderActor(val recorder: RecorderApplication)
}
private def handleCursorPositionUpdatedEvent(msg: CursorPositionUpdatedEvent) {
if (msg.recorded) {
val event = new CursorUpdateRecordEvent();
event.setMeetingId(msg.meetingID);
event.setTimestamp(TimestampGenerator.generateTimestamp);
event.setUserId(msg.requesterID);
event.setXPercent(msg.xPercent);
event.setYPercent(msg.yPercent);
recorder.record(msg.meetingID, event);
}
}
private def handleClearWhiteboardEvent(msg: ClearWhiteboardEvent) {
if (msg.recorded) {
val event = new ClearPageWhiteboardRecordEvent()

View File

@ -137,7 +137,6 @@ case class BroadcastLayoutRequest(meetingID: String, requesterID: String, layout
case class ClearPresentation(meetingID: String) extends InMessage
case class RemovePresentation(meetingID: String, presentationID: String) extends InMessage
case class GetPresentationInfo(meetingID: String, requesterID: String, replyTo: String) extends InMessage
case class SendCursorUpdate(meetingID: String, xPercent: Double, yPercent: Double) extends InMessage
case class ResizeAndMoveSlide(meetingID: String, xOffset: Double, yOffset: Double,
widthRatio: Double, heightRatio: Double) extends InMessage
case class GotoSlide(meetingID: String, page: String) extends InMessage
@ -194,6 +193,7 @@ case class VoiceConfRecordingStartedMessage(voiceConfId: String, recordStream: S
/////////////////////////////////////////////////////////////////////////////////////
case class SendWhiteboardAnnotationRequest(meetingID: String, requesterID: String, annotation: AnnotationVO) extends InMessage
case class SendCursorPositionRequest(meetingID: String, requesterID: String, xPercent: Double, yPercent: Double) extends InMessage
case class GetWhiteboardShapesRequest(meetingID: String, requesterID: String, whiteboardId: String, replyTo: String) extends InMessage
case class ClearWhiteboardRequest(meetingID: String, requesterID: String, whiteboardId: String) extends InMessage
case class UndoWhiteboardRequest(meetingID: String, requesterID: String, whiteboardId: String) extends InMessage

View File

@ -62,7 +62,6 @@ object MessageNames {
val PRESENTATION_PAGE_COUNT_ERROR = "presentation_page_count_error_message"
val PRESENTATION_SLIDE_GENERATED = "presentation_slide_generated_message"
val PRESENTATION_CONVERSION_COMPLETED = "presentation_conversion_completed_message"
val PRESENTATION_CURSOR_UPDATED = "presentation_cursor_updated_message"
val SEND_VOICE_USERS_REQUEST = "send_voice_users_request"
val MUTE_MEETING_REQUEST = "mute_meeting_request"
val IS_MEETING_MUTED = "is_meeting_muted_request"
@ -163,6 +162,7 @@ object MessageNames {
val PRESENTATION_PAGE_GENERATED = "presentation_page_generated_message"
val GET_WHITEBOARD_SHAPES_REPLY = "get_whiteboard_shapes_reply"
val SEND_WHITEBOARD_SHAPE = "send_whiteboard_shape_message"
val CURSOR_POSITION_UPDATED = "cursor_position_updated_message"
val UNDO_WHITEBOARD_MESSAGE = "undo_whiteboard_message"
val MODIFIED_WHITEBOARD_ACCESS = "modified_whiteboard_access_message"
val GET_WHITEBOARD_ACCESS_REPLY = "get_whiteboard_access_reply"

View File

@ -108,7 +108,6 @@ case class ClearPresentationOutMsg(meetingID: String, recorded: Boolean) extends
case class RemovePresentationOutMsg(meetingID: String, recorded: Boolean, presentationID: String) extends IOutMessage
case class GetPresentationInfoOutMsg(meetingID: String, recorded: Boolean, requesterID: String,
info: CurrentPresentationInfo, replyTo: String) extends IOutMessage
case class SendCursorUpdateOutMsg(meetingID: String, recorded: Boolean, xPercent: Double, yPercent: Double) extends IOutMessage
case class ResizeAndMoveSlideOutMsg(meetingID: String, recorded: Boolean, page: Page) extends IOutMessage
case class GotoSlideOutMsg(meetingID: String, recorded: Boolean, page: Page) extends IOutMessage
case class SharePresentationOutMsg(meetingID: String, recorded: Boolean, presentation: Presentation) extends IOutMessage
@ -145,6 +144,7 @@ case class GetCurrentPollReplyMessage(meetingID: String, recorded: Boolean, requ
// Whiteboard
case class GetWhiteboardShapesReply(meetingID: String, recorded: Boolean, requesterID: String, whiteboardId: String, shapes: Array[AnnotationVO], replyTo: String) extends IOutMessage
case class SendWhiteboardAnnotationEvent(meetingID: String, recorded: Boolean, requesterID: String, whiteboardId: String, shape: AnnotationVO) extends IOutMessage
case class CursorPositionUpdatedEvent(meetingID: String, recorded: Boolean, requesterID: String, xPercent: Double, yPercent: Double) extends IOutMessage
case class ClearWhiteboardEvent(meetingID: String, recorded: Boolean, requesterID: String, whiteboardId: String, fullClear: Boolean) extends IOutMessage
case class UndoWhiteboardEvent(meetingID: String, recorded: Boolean, requesterID: String, whiteboardId: String, shapeId: String) extends IOutMessage
case class ModifiedWhiteboardAccessEvent(meetingID: String, recorded: Boolean, requesterID: String, multiUser: Boolean) extends IOutMessage

View File

@ -11,8 +11,6 @@ trait PresentationApp {
val outGW: OutMessageGateway
private var cursorLocation = new CursorLocation
def handlePreuploadedPresentations(msg: PreuploadedPresentations) {
val pres = msg.presentations
@ -83,11 +81,6 @@ trait PresentationApp {
outGW.send(new GetPresentationInfoOutMsg(mProps.meetingID, mProps.recorded, msg.requesterID, presentationInfo, msg.replyTo))
}
def handleSendCursorUpdate(msg: SendCursorUpdate) {
cursorLocation = new CursorLocation(msg.xPercent, msg.yPercent)
outGW.send(new SendCursorUpdateOutMsg(mProps.meetingID, mProps.recorded, msg.xPercent, msg.yPercent))
}
def handleResizeAndMoveSlide(msg: ResizeAndMoveSlide) {
// Force coordinate that are out-of-bounds inside valid values
val xOffset = if (msg.xOffset <= 0) msg.xOffset else 0

View File

@ -2,7 +2,6 @@ package org.bigbluebutton.core.apps
case class CurrentPresenter(userId: String, name: String, assignedBy: String)
case class CurrentPresentationInfo(presenter: CurrentPresenter, presentations: Seq[Presentation])
case class CursorLocation(xPercent: Double = 0D, yPercent: Double = 0D)
case class Presentation(id: String, name: String, current: Boolean = false,
pages: scala.collection.immutable.HashMap[String, Page], downloadable: Boolean)

View File

@ -47,6 +47,10 @@ trait WhiteboardApp {
}
def handleSendCursorPositionRequest(msg: SendCursorPositionRequest) {
outGW.send(new CursorPositionUpdatedEvent(mProps.meetingID, mProps.recorded, msg.requesterID, msg.xPercent, msg.yPercent))
}
def handleGetWhiteboardShapesRequest(msg: GetWhiteboardShapesRequest) {
//println("WB: Received page history [" + msg.whiteboardId + "]")
val history = liveMeeting.wbModel.getHistory(msg.whiteboardId);

View File

@ -3,7 +3,6 @@ package org.bigbluebutton.core.apps
import java.util.ArrayList;
import org.bigbluebutton.core.util.jhotdraw.BezierWrapper
import org.bigbluebutton.core.util.jhotdraw.PathData
import scala.collection.immutable.List
import scala.collection.immutable.HashMap

View File

@ -85,16 +85,6 @@ object PesentationMessageToJsonConverter {
Util.buildJson(header, payload)
}
def sendCursorUpdateOutMsgToJson(msg: SendCursorUpdateOutMsg): String = {
val payload = new java.util.HashMap[String, Any]()
payload.put(Constants.MEETING_ID, msg.meetingID)
payload.put(Constants.X_PERCENT, msg.xPercent)
payload.put(Constants.Y_PERCENT, msg.yPercent)
val header = Util.buildHeader(MessageNames.PRESENTATION_CURSOR_UPDATED, None)
Util.buildJson(header, payload)
}
def resizeAndMoveSlideOutMsgToJson(msg: ResizeAndMoveSlideOutMsg): String = {
val payload = new java.util.HashMap[String, Any]()
payload.put(Constants.MEETING_ID, msg.meetingID)

View File

@ -53,6 +53,17 @@ object WhiteboardMessageToJsonConverter {
Util.buildJson(header, payload)
}
def cursorPositionUpdatedEventToJson(msg: CursorPositionUpdatedEvent): String = {
val payload = new java.util.HashMap[String, Any]()
payload.put(Constants.MEETING_ID, msg.meetingID)
payload.put(Constants.REQUESTER_ID, msg.requesterID)
payload.put(Constants.X_PERCENT, msg.xPercent)
payload.put(Constants.Y_PERCENT, msg.yPercent)
val header = Util.buildHeader(MessageNames.CURSOR_POSITION_UPDATED, None)
Util.buildJson(header, payload)
}
def clearWhiteboardEventToJson(msg: ClearWhiteboardEvent): String = {
val payload = new java.util.HashMap[String, Any]()
payload.put(Constants.MEETING_ID, msg.meetingID)

View File

@ -97,13 +97,13 @@ class MeetingActor(val mProps: MeetingProperties,
case msg: PresentationConversionCompleted => handlePresentationConversionCompleted(msg)
case msg: RemovePresentation => handleRemovePresentation(msg)
case msg: GetPresentationInfo => handleGetPresentationInfo(msg)
case msg: SendCursorUpdate => handleSendCursorUpdate(msg)
case msg: ResizeAndMoveSlide => handleResizeAndMoveSlide(msg)
case msg: GotoSlide => handleGotoSlide(msg)
case msg: SharePresentation => handleSharePresentation(msg)
case msg: GetSlideInfo => handleGetSlideInfo(msg)
case msg: PreuploadedPresentations => handlePreuploadedPresentations(msg)
case msg: SendWhiteboardAnnotationRequest => handleSendWhiteboardAnnotationRequest(msg)
case msg: SendCursorPositionRequest => handleSendCursorPositionRequest(msg)
case msg: GetWhiteboardShapesRequest => handleGetWhiteboardShapesRequest(msg)
case msg: ClearWhiteboardRequest => handleClearWhiteboardRequest(msg)
case msg: UndoWhiteboardRequest => handleUndoWhiteboardRequest(msg)

View File

@ -4,16 +4,18 @@ import java.util.HashMap;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class PresentationCursorUpdateMessage implements ISubscribedMessage {
public static final String PRESENTATION_CURSOR_UPDATED = "presentation_cursor_updated_message";
public class CursorPositionUpdatedMessage implements ISubscribedMessage {
public static final String CURSOR_POSITION_UPDATED = "cursor_position_updated_message";
public final String VERSION = "0.0.1";
public final String meetingId;
public final String requesterId;
public final double xPercent;
public final double yPercent;
public PresentationCursorUpdateMessage(String meetingId, double xPercent, double yPercent) {
public CursorPositionUpdatedMessage(String meetingId, String requesterId, double xPercent, double yPercent) {
this.meetingId = meetingId;
this.requesterId = requesterId;
this.xPercent = xPercent;
this.yPercent = yPercent;
}
@ -21,15 +23,16 @@ public class PresentationCursorUpdateMessage implements ISubscribedMessage {
public String toJson() {
HashMap<String, Object> payload = new HashMap<String, Object>();
payload.put(Constants.MEETING_ID, meetingId);
payload.put(Constants.REQUESTER_ID, requesterId);
payload.put(Constants.X_PERCENT, xPercent);
payload.put(Constants.Y_PERCENT, yPercent);
java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(PRESENTATION_CURSOR_UPDATED, VERSION, null);
java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(CURSOR_POSITION_UPDATED, VERSION, null);
return MessageBuilder.buildJson(header, payload);
}
public static PresentationCursorUpdateMessage fromJson(String message) {
public static CursorPositionUpdatedMessage fromJson(String message) {
JsonParser parser = new JsonParser();
JsonObject obj = (JsonObject) parser.parse(message);
@ -39,15 +42,17 @@ public class PresentationCursorUpdateMessage implements ISubscribedMessage {
if (header.has("name")) {
String messageName = header.get("name").getAsString();
if (PRESENTATION_CURSOR_UPDATED.equals(messageName)) {
if (CURSOR_POSITION_UPDATED.equals(messageName)) {
if (payload.has(Constants.MEETING_ID)
&& payload.has(Constants.REQUESTER_ID)
&& payload.has(Constants.X_PERCENT)
&& payload.has(Constants.Y_PERCENT)) {
String meetingId = payload.get(Constants.MEETING_ID).getAsString();
String requesterId = payload.get(Constants.REQUESTER_ID).getAsString();
double xPercent = payload.get(Constants.X_PERCENT).getAsDouble();
double yPercent = payload.get(Constants.Y_PERCENT).getAsDouble();
return new PresentationCursorUpdateMessage(meetingId, xPercent, yPercent);
return new CursorPositionUpdatedMessage(meetingId, requesterId, xPercent, yPercent);
}
}
}

View File

@ -5,16 +5,18 @@ import java.util.HashMap;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class SendCursorUpdateMessage implements IBigBlueButtonMessage {
public static final String SEND_CURSOR_UPDATE = "send_cursor_update";
public class SendCursorPositionMessage implements IBigBlueButtonMessage {
public static final String SEND_CURSOR_POSITION = "send_cursor_position";
public static final String VERSION = "0.0.1";
public final String meetingId;
public final String requesterId;
public final double xPercent;
public final double yPercent;
public SendCursorUpdateMessage(String meetingId, double xPercent, double yPercent){
public SendCursorPositionMessage(String meetingId, String requesterId, double xPercent, double yPercent){
this.meetingId = meetingId;
this.requesterId = requesterId;
this.xPercent = xPercent;
this.yPercent = yPercent;
}
@ -22,15 +24,16 @@ public class SendCursorUpdateMessage implements IBigBlueButtonMessage {
public String toJson() {
HashMap<String, Object> payload = new HashMap<String, Object>();
payload.put(Constants.MEETING_ID, meetingId);
payload.put(Constants.REQUESTER_ID, requesterId);
payload.put(Constants.X_PERCENT, xPercent);
payload.put(Constants.Y_PERCENT, yPercent);
java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(SEND_CURSOR_UPDATE, VERSION, null);
java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(SEND_CURSOR_POSITION, VERSION, null);
return MessageBuilder.buildJson(header, payload);
}
public static SendCursorUpdateMessage fromJson(String message) {
public static SendCursorPositionMessage fromJson(String message) {
JsonParser parser = new JsonParser();
JsonObject obj = (JsonObject) parser.parse(message);
@ -40,15 +43,17 @@ public class SendCursorUpdateMessage implements IBigBlueButtonMessage {
if (header.has("name")) {
String messageName = header.get("name").getAsString();
if (SEND_CURSOR_UPDATE.equals(messageName)) {
if (SEND_CURSOR_POSITION.equals(messageName)) {
if (payload.has(Constants.MEETING_ID)
&& payload.has(Constants.REQUESTER_ID)
&& payload.has(Constants.X_PERCENT)
&& payload.has(Constants.Y_PERCENT)) {
String meetingId = payload.get(Constants.MEETING_ID).getAsString();
String requesterId = payload.get(Constants.REQUESTER_ID).getAsString();
double xPercent = payload.get(Constants.X_PERCENT).getAsDouble();
double yPercent = payload.get(Constants.Y_PERCENT).getAsDouble();
return new SendCursorUpdateMessage(meetingId, xPercent, yPercent);
return new SendCursorPositionMessage(meetingId, requesterId, xPercent, yPercent);
}
}
}

View File

@ -10,7 +10,6 @@ import org.bigbluebutton.common.messages.GoToSlideReplyMessage;
import org.bigbluebutton.common.messages.PresentationConversionDoneMessage;
import org.bigbluebutton.common.messages.PresentationConversionErrorMessage;
import org.bigbluebutton.common.messages.PresentationConversionProgressMessage;
import org.bigbluebutton.common.messages.PresentationCursorUpdateMessage;
import org.bigbluebutton.common.messages.PresentationPageGeneratedReplyMessage;
import org.bigbluebutton.common.messages.PresentationPageResizedMessage;
import org.bigbluebutton.common.messages.PresentationRemovedMessage;
@ -55,9 +54,6 @@ public class PresentationClientMessageSender {
case PresentationPageGeneratedReplyMessage.PRESENTATION_PAGE_GENERATED:
processPresentationPageGeneratedReply(message);
break;
case PresentationCursorUpdateMessage.PRESENTATION_CURSOR_UPDATED:
processPresentationCursorUpdate(message);
break;
case PresentationConversionErrorMessage.PRESENTATION_CONVERSION_ERROR:
processPresentationConversionError(message);
break;
@ -227,23 +223,6 @@ public class PresentationClientMessageSender {
}
}
private void processPresentationCursorUpdate(String json) {
PresentationCursorUpdateMessage msg = PresentationCursorUpdateMessage.fromJson(json);
if (msg != null) {
Map<String, Object> args = new HashMap<String, Object>();
args.put("meetingID", msg.meetingId);
args.put("xPercent", msg.xPercent);
args.put("yPercent", msg.yPercent);
Map<String, Object> message = new HashMap<String, Object>();
Gson gson = new Gson();
message.put("msg", gson.toJson(args));
BroadcastClientMessage m = new BroadcastClientMessage(msg.meetingId, "PresentationCursorUpdateCommand", message);
service.sendMessage(m);
}
}
private void processPresentationPageGeneratedReply(String json) {
PresentationPageGeneratedReplyMessage msg = PresentationPageGeneratedReplyMessage.fromJson(json);
if (msg != null) {

View File

@ -4,6 +4,7 @@ import java.util.HashMap;
import java.util.Map;
import org.bigbluebutton.common.messages.ClearWhiteboardReplyMessage;
import org.bigbluebutton.common.messages.CursorPositionUpdatedMessage;
import org.bigbluebutton.common.messages.GetWhiteboardShapesReplyMessage;
import org.bigbluebutton.common.messages.GetWhiteboardAccessReplyMessage;
import org.bigbluebutton.common.messages.SendWhiteboardAnnotationReplyMessage;
@ -59,6 +60,12 @@ public class WhiteboardClientMessageSender {
processSendWhiteboardAnnotationReplyMessage(swarm);
}
break;
case CursorPositionUpdatedMessage.CURSOR_POSITION_UPDATED:
CursorPositionUpdatedMessage cpum = CursorPositionUpdatedMessage.fromJson(message);
if (cpum != null) {
processCursorPositionUpdatedMessage(cpum);
}
break;
case ModifiedWhiteboardAccessMessage.MODIFIED_WHITEBOARD_ACCESS:
ModifiedWhiteboardAccessMessage mwam = ModifiedWhiteboardAccessMessage.fromJson(message);
if (mwam != null) {
@ -100,6 +107,20 @@ public class WhiteboardClientMessageSender {
service.sendMessage(b);
}
private void processCursorPositionUpdatedMessage(CursorPositionUpdatedMessage msg) {
Map<String, Object> args = new HashMap<String, Object>();
args.put("requesterId", msg.requesterId);
args.put("xPercent", msg.xPercent);
args.put("yPercent", msg.yPercent);
Map<String, Object> message = new HashMap<String, Object>();
Gson gson = new Gson();
message.put("msg", gson.toJson(args));
BroadcastClientMessage m = new BroadcastClientMessage(msg.meetingId, "WhiteboardCursorPositionUpdatedCommand", message);
service.sendMessage(m);
}
private void processGetWhiteboardShapesReplyMessage(GetWhiteboardShapesReplyMessage msg) {

View File

@ -180,11 +180,6 @@ public class MessagePublisher {
}
public void sendCursorUpdate(String meetingID, double xPercent, double yPercent) {
SendCursorUpdateMessage msg = new SendCursorUpdateMessage(meetingID, xPercent, yPercent);
sender.send(MessagingConstants.TO_PRESENTATION_CHANNEL, msg.toJson());
}
public void resizeAndMoveSlide(String meetingID, double xOffset, double yOffset, double widthRatio, double heightRatio) {
ResizeAndMoveSlideMessage msg = new ResizeAndMoveSlideMessage(meetingID, xOffset, yOffset, widthRatio, heightRatio);
sender.send(MessagingConstants.TO_PRESENTATION_CHANNEL, msg.toJson());
@ -262,11 +257,17 @@ public class MessagePublisher {
DeskShareGetInfoRequestMessage msg = new DeskShareGetInfoRequestMessage(meetingID, requesterID, replyTo);
sender.send(MessagingConstants.FROM_VOICE_CONF_SYSTEM_CHAN, msg.toJson());
}
public void sendWhiteboardAnnotation(String meetingID, String requesterID, Map<String, Object> annotation) {
SendWhiteboardAnnotationRequestMessage msg = new SendWhiteboardAnnotationRequestMessage(meetingID, requesterID, annotation);
sender.send(MessagingConstants.TO_WHITEBOARD_CHANNEL, msg.toJson());
}
public void sendCursorPosition(String meetingID, String requesterID, double xPercent, double yPercent) {
SendCursorPositionMessage msg = new SendCursorPositionMessage(meetingID, requesterID, xPercent, yPercent);
sender.send(MessagingConstants.TO_WHITEBOARD_CHANNEL, msg.toJson());
}
public void requestWhiteboardAnnotationHistory(String meetingID, String requesterID, String whiteboardId, String replyTo) {
RequestWhiteboardAnnotationHistoryRequestMessage msg = new RequestWhiteboardAnnotationHistoryRequestMessage(meetingID, requesterID, whiteboardId, replyTo);
sender.send(MessagingConstants.TO_WHITEBOARD_CHANNEL, msg.toJson());

View File

@ -77,11 +77,6 @@ public class PresentationApplication {
red5BBBInGW.getPresentationInfo(meetingID, requesterID, replyTo);
}
public void sendCursorUpdate(String meetingID, Double xPercent, Double yPercent) {
red5BBBInGW.sendCursorUpdate(meetingID, xPercent, yPercent);
}
public void resizeAndMoveSlide(String meetingID, Double xOffset, Double yOffset, Double widthRatio, Double heightRatio) {
red5BBBInGW.resizeAndMoveSlide(meetingID, xOffset, yOffset, widthRatio, heightRatio);

View File

@ -73,29 +73,6 @@ public class PresentationService {
presentationApplication.sharePresentation(scope.getName(), presentationID, share);
}
public void sendCursorUpdate(Map<String, Object> msg) {
IScope scope = Red5.getConnectionLocal().getScope();
Double xPercent;
if (msg.get("xPercent") instanceof Integer) {
Integer tempXOffset = (Integer) msg.get("xPercent");
xPercent = tempXOffset.doubleValue();
} else {
xPercent = (Double) msg.get("xPercent");
}
Double yPercent;
if (msg.get("yPercent") instanceof Integer) {
Integer tempYOffset = (Integer) msg.get("yPercent");
yPercent = tempYOffset.doubleValue();
} else {
yPercent = (Double) msg.get("yPercent");
}
presentationApplication.sendCursorUpdate(scope.getName(), xPercent, yPercent);
}
public void resizeAndMoveSlide(Map<String, Object> msg) {
Double xOffset;
if (msg.get("xOffset") instanceof Integer) {

View File

@ -99,6 +99,10 @@ public class WhiteboardApplication implements IApplication {
public void sendWhiteboardAnnotation(String meetingID, String requesterID, java.util.Map<String, Object> shape) {
red5BBBInGW.sendWhiteboardAnnotation(meetingID, requesterID, shape);
}
public void sendCursorPosition(String meetingID, String requesterID, Double xPercent, Double yPercent) {
red5BBBInGW.sendCursorPosition(meetingID, requesterID, xPercent, yPercent);
}
public void clearWhiteboard(String meetingID, String requesterID, String whiteboardId) {
red5BBBInGW.clearWhiteboard(meetingID, requesterID, whiteboardId);

View File

@ -24,6 +24,7 @@ import org.bigbluebutton.red5.BigBlueButtonSession;
import org.bigbluebutton.red5.Constants;
import org.red5.logging.Red5LoggerFactory;
import org.red5.server.api.Red5;
import org.red5.server.api.scope.IScope;
import org.slf4j.Logger;
public class WhiteboardService {
@ -47,19 +48,6 @@ public class WhiteboardService {
return false;
}
public void sendAnnotation(Map<String, Object> annotation) {
// for (Map.Entry<String, Object> entry : annotation.entrySet()) {
// String key = entry.getKey();
// Object value = entry.getValue();
// if (key.equals("points")) {
// String points = "points=[";
// ArrayList<Double> v = (ArrayList<Double>) value;
// log.debug(points + pointsToString(v) + "]");
// } else {
// log.debug(key + "=[" + value + "]");
// }
// }
String meetingID = getMeetingId();
String requesterID = getBbbSession().getInternalUserID();
@ -68,18 +56,29 @@ public class WhiteboardService {
}
}
/*private String pointsToString(ArrayList<Double> points){
String datapoints = "";
for (Double i : points) {
datapoints += i + ",";
}
// Trim the trailing comma
// log.debug("Data Point = " + datapoints);
return datapoints.substring(0, datapoints.length() - 1);
public void sendCursorPosition(Map<String, Object> msg) {
String meetingID = getMeetingId();
String requesterID = getBbbSession().getInternalUserID();
Double xPercent;
if (msg.get("xPercent") instanceof Integer) {
Integer tempXOffset = (Integer) msg.get("xPercent");
xPercent = tempXOffset.doubleValue();
} else {
xPercent = (Double) msg.get("xPercent");
}
// application.sendShape(shape, type, color, thickness, fill, fillColor, transparency, id, status);
Double yPercent;
}*/
if (msg.get("yPercent") instanceof Integer) {
Integer tempYOffset = (Integer) msg.get("yPercent");
yPercent = tempYOffset.doubleValue();
} else {
yPercent = (Double) msg.get("yPercent");
}
application.sendCursorPosition(meetingID, requesterID, xPercent, yPercent);
}
public void requestAnnotationHistory(Map<String, Object> message) {
log.info("WhiteboardApplication - requestAnnotationHistory");

View File

@ -229,15 +229,5 @@ package org.bigbluebutton.modules.present.business
public function zoomSlide(e:PresenterCommands):void{
sender.move(e.xOffset, e.yOffset, e.slideToCanvasWidthRatio, e.slideToCanvasHeightRatio);
}
/**
* Update the presenter cursor within the presentation window
* @param e
*
*/
public function sendCursorUpdate(e:PresenterCommands):void{
sender.sendCursorUpdate(e.xPercent, e.yPercent);
}
}
}

View File

@ -34,7 +34,6 @@ package org.bigbluebutton.modules.present.events
public static const RESET_ZOOM:String = "RESTORE_ZOOM";
public static const MOVE:String = "MOVE_COMMAND";
public static const SHARE_PRESENTATION_COMMAND:String = "SHARE_PRESENTATION_COMMAND";
public static const SEND_CURSOR_UPDATE:String = "SEND_CURSOR_UPDATE";
//Parameter for the slide navigation events
public var slideNumber:Number;
@ -45,10 +44,6 @@ package org.bigbluebutton.modules.present.events
//Parameters for the resize event
public var newSizeInPercent:Number;
//Parameters for the cursor event
public var xPercent:Number;
public var yPercent:Number;
//Parameters for the move event
public var xOffset:Number;
public var yOffset:Number;

View File

@ -108,10 +108,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<EventHandlers type="{GetListOfPresentationsRequest.GET_LIST_OF_PRESENTATIONS}" >
<MethodInvoker generator="{PresentProxy}" method="handleGetListOfPresentationsRequest" />
</EventHandlers>
<EventHandlers type="{PresenterCommands.SEND_CURSOR_UPDATE}" >
<MethodInvoker generator="{PresentProxy}" method="sendCursorUpdate" arguments="{event}" />
</EventHandlers>
<EventHandlers type="{PresenterCommands.RESIZE}" >
<MethodInvoker generator="{PresentProxy}" method="resizeSlide" arguments="{event}" />

View File

@ -5,7 +5,6 @@ package org.bigbluebutton.modules.present.services
import mx.collections.ArrayCollection;
import org.bigbluebutton.modules.present.commands.ChangePageCommand;
import org.bigbluebutton.modules.present.events.CursorEvent;
import org.bigbluebutton.modules.present.events.PageChangedEvent;
import org.bigbluebutton.modules.present.events.PresentationChangedEvent;
import org.bigbluebutton.modules.present.events.RemovePresentationEvent;
@ -35,13 +34,6 @@ package org.bigbluebutton.modules.present.services
dispatcher = new Dispatcher();
}
public function cursorMoved(x: Number, y: Number):void {
var e:CursorEvent = new CursorEvent(CursorEvent.UPDATE_CURSOR);
e.xPercent = x;
e.yPercent = y;
dispatcher.dispatchEvent(e);
}
public function pageChanged(page: PageVO):void {
var np: Page = model.getPage(page.id);
if (np != null) {

View File

@ -60,9 +60,6 @@ package org.bigbluebutton.modules.present.services.messaging
//LOGGER.info("Presentation: received message " + messageName);
switch (messageName) {
case "PresentationCursorUpdateCommand":
handlePresentationCursorUpdateCommand(message);
break;
case "goToSlideCallback":
handleGotoSlideCallback(message);
break;
@ -101,14 +98,6 @@ package org.bigbluebutton.modules.present.services.messaging
}
private function handlePresentationCursorUpdateCommand(msg:Object):void {
// trace(LOG + "*** handlePresentationCursorUpdateCommand " + msg.msg + " **** \n");
var map:Object = JSON.parse(msg.msg);
if (map.hasOwnProperty("xPercent") && map.hasOwnProperty("yPercent")) {
service.cursorMoved(map.xPercent, map.yPercent);
}
}
private function handleGotoSlideCallback(msg:Object) : void {
var map:Object = JSON.parse(msg.msg);

View File

@ -27,29 +27,6 @@ package org.bigbluebutton.modules.present.services.messaging
private static const LOGGER:ILogger = getClassLogger(MessageSender);
/**
* Send an event to the server to update the presenter's cursor view on the client
* @param xPercent
* @param yPercent
*
*/
public function sendCursorUpdate(xPercent:Number, yPercent:Number):void{
var message:Object = new Object();
message["xPercent"] = xPercent;
message["yPercent"] = yPercent;
var _nc:ConnectionManager = BBB.initConnectionManager();
_nc.sendMessage("presentation.sendCursorUpdate",
function(result:String):void { // On successful result
//LOGGER.debug(result);
},
function(status:String):void { // status - On error occurred
LOGGER.error(status);
},
message
);
}
/**
* Sends an event to the server to update the clients with the new slide position
* @param slideXPosition

View File

@ -28,15 +28,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
x="{slideModel.viewportX}" y="{slideModel.viewportY}"
creationComplete="onCreationComplete()"
verticalScrollPolicy="off"
horizontalScrollPolicy="off"
rollOut="hideCursor()" styleName="presentationSlideViewStyle"
horizontalScrollPolicy="off"
styleName="presentationSlideViewStyle"
xmlns:views="org.bigbluebutton.modules.present.views.*">
<mate:Listener type="{PageChangedEvent.PRESENTATION_PAGE_CHANGED_EVENT}" method="handlePageChangedEvent" />
<mate:Listener type="{PageLoadedEvent.PAGE_LOADED_EVENT}" method="handlePageLoadedEvent" />
<mate:Listener type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" method="handleSwitchToPresenterEvent" />
<mate:Listener type="{MadePresenterEvent.SWITCH_TO_VIEWER_MODE}" method="handleSwitchToViewerEvent" />
<mate:Listener type="{CursorEvent.UPDATE_CURSOR}" method="handleUpdateCursorEvent" />
<mate:Listener type="{ShortcutEvent.FOCUS_SLIDE}" method="focusSlide" />
<mx:Script>
<![CDATA[
@ -46,7 +45,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import mx.collections.Sort;
import mx.collections.SortField;
import mx.containers.Canvas;
import mx.managers.CursorManager;
import org.as3commons.logging.api.ILogger;
import org.as3commons.logging.api.getClassLogger;
@ -55,7 +53,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import org.bigbluebutton.main.events.MadePresenterEvent;
import org.bigbluebutton.main.events.ShortcutEvent;
import org.bigbluebutton.modules.present.commands.GoToPageCommand;
import org.bigbluebutton.modules.present.events.CursorEvent;
import org.bigbluebutton.modules.present.events.DisplaySlideEvent;
import org.bigbluebutton.modules.present.events.PageChangedEvent;
import org.bigbluebutton.modules.present.events.PageLoadedEvent;
@ -73,8 +70,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
[Bindable] public var zoomPercentage:Number = 100;
public static const ZOOM_STEP:int = 5;
public static const THUMBNAILS_CLOSED:String = "ThumbnailsClosed";
private var cursor:Shape;
private var whiteboardCanvas:WhiteboardCanvas;
private var dispatcher:Dispatcher = new Dispatcher();
@ -84,21 +80,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private var pageCache:ArrayCollection = new ArrayCollection();
// Send update of mouse location to other users.
private var _sendCurrentMouseLocTimer:Timer = new Timer(100);
private var _lastMouseXPosition:Number = 0;
private var _lastMouseYPosition:Number = 0;
private function onCreationComplete():void {
slideLoader.width = this.width;
slideLoader.height = this.height;
cursor = new Shape();
cursor.graphics.lineStyle(6, 0xFF0000, 0.6);
cursor.graphics.drawCircle(0,0,2.5);
this.rawChildren.addChild(cursor);
cursor.visible = false;
this.setChildIndex(thumbnailView, this.numChildren - 1);
/*
@ -340,8 +325,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private function becomeViewer():void {
removeEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheelZoomEvent);
this.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
_sendCurrentMouseLocTimer.stop();
_sendCurrentMouseLocTimer.removeEventListener(TimerEvent.TIMER, mouseCursorUpdateTimerListener);
}
/**
@ -361,9 +344,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheelZoomEvent);
this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
_sendCurrentMouseLocTimer.addEventListener(TimerEvent.TIMER, mouseCursorUpdateTimerListener);
_sendCurrentMouseLocTimer.start();
notifyOthersOfZoomEvent();
notifyOthersOfZoomEvent();
}
/**
@ -373,53 +354,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
becomePresenter();
}
public function mouseCursorUpdateTimerListener(e:TimerEvent):void{
if (noSlideContentLoaded()) return;
notifyOthersOfPresentersCursorPosition(this.mouseX, this.mouseY);
}
/**
* Broadcast to other participants the location fo the mouse cursor.
*/
private function notifyOthersOfPresentersCursorPosition(cursorXPosition:int, cursorYPosition:int):void {
// Only update the other users if the mouse moved a certain delta
if ( (Math.abs(cursorXPosition - _lastMouseXPosition) < 0.1)
&& (Math.abs(cursorYPosition - _lastMouseYPosition) < 0.1) ) {
return;
}
if (cursorXPosition > this.width || cursorXPosition < 1
|| cursorYPosition > this.height || cursorYPosition < 1) {
// LogUtil.debug("Cursor outside the window...not sending [" + cursorXPosition + "," + cursorYPosition + "]");
return;
}
_lastMouseXPosition = cursorXPosition;
_lastMouseYPosition = cursorYPosition;
var command:PresenterCommands = new PresenterCommands(PresenterCommands.SEND_CURSOR_UPDATE);
command.xPercent = cursorXPosition / this.width;
command.yPercent = cursorYPosition / this.height;
dispatchEvent(command);
}
/**
* Handle notification from presenter about the location of the mouse cursor.
*/
private function handleUpdateCursorEvent(e:CursorEvent):void{
if (noSlideContentLoaded()) return;
cursor.x = e.xPercent * this.width;
cursor.y = e.yPercent * this.height;
if (isCursorOutsideWindow(e)) {
hideCursor()
} else {
showCursor();
}
}
private function noSlideContentLoaded():Boolean {
return slideLoader.content == null
}
@ -443,20 +377,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
dispEvent.slideHeight = slideRealHeight;
dispatcher.dispatchEvent(dispEvent);
}
private function isCursorOutsideWindow(e:CursorEvent):Boolean {
return (e.xPercent > 1 && e.yPercent > 1)
|| (cursor.x > this.width || cursor.x < 1
|| cursor.y > this.height || cursor.y < 1);
}
private function showCursor():void {
cursor.visible = true;
}
private function hideCursor():void{
cursor.visible = false;
}
public function acceptOverlayCanvas(overlay:WhiteboardCanvas):void{
whiteboardCanvas = overlay;

View File

@ -23,6 +23,7 @@ package org.bigbluebutton.modules.whiteboard
import flash.events.FocusEvent;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.utils.Dictionary;
import org.as3commons.logging.api.ILogger;
import org.as3commons.logging.api.getClassLogger;
@ -42,6 +43,7 @@ package org.bigbluebutton.modules.whiteboard
import org.bigbluebutton.modules.whiteboard.models.WhiteboardModel;
import org.bigbluebutton.modules.whiteboard.views.TextUpdateListener;
import org.bigbluebutton.modules.whiteboard.views.WhiteboardCanvas;
import org.bigbluebutton.modules.whiteboard.views.WhiteboardCursor;
/**
* Class to handle displaying of received annotations from the server.
@ -52,11 +54,13 @@ package org.bigbluebutton.modules.whiteboard
private var whiteboardModel:WhiteboardModel;
private var wbCanvas:WhiteboardCanvas;
private var _annotationsList:Array = new Array();
private var _cursors:Object = new Object();
private var shapeFactory:ShapeFactory = new ShapeFactory();
private var textUpdateListener:TextUpdateListener = new TextUpdateListener();
private var width:Number;
private var height:Number;
private var presenterId:String;
public function setDependencies(whiteboardCanvas:WhiteboardCanvas, whiteboardModel:WhiteboardModel):void {
wbCanvas = whiteboardCanvas;
@ -209,6 +213,32 @@ package org.bigbluebutton.modules.whiteboard
}
}
}
public function drawCursor(userId:String, xPercent:Number, yPercent:Number):void {
if (!_cursors.hasOwnProperty(userId)) {
var newCursor:WhiteboardCursor = new WhiteboardCursor(userId, xPercent, yPercent, shapeFactory.parentWidth, shapeFactory.parentHeight, presenterId == userId);
wbCanvas.addCursor(newCursor);
_cursors[userId] = newCursor;
} else {
(_cursors[userId] as WhiteboardCursor).updatePosition(xPercent, yPercent);
}
}
public function presenterChange(amIPresenter:Boolean, presenterId:String):void {
this.presenterId = presenterId;
for(var j:String in _cursors) {
(_cursors[j] as WhiteboardCursor).updatePresenter(j == presenterId);
}
}
public function userLeft(userId:String):void {
if (_cursors.hasOwnProperty(userId)) {
wbCanvas.removeCursorChild(_cursors[userId]);
delete _cursors[userId];
}
}
public function zoomCanvas(width:Number, height:Number):void{
shapeFactory.setParentDim(width, height);
@ -218,6 +248,10 @@ package org.bigbluebutton.modules.whiteboard
for (var i:int = 0; i < this._annotationsList.length; i++){
redrawGraphic(this._annotationsList[i] as GraphicObject, i);
}
for(var j:String in _cursors) {
(_cursors[j] as WhiteboardCursor).updateParentSize(width, height);
}
}
private function redrawGraphic(gobj:GraphicObject, objIndex:int):void {

View File

@ -26,6 +26,7 @@ package org.bigbluebutton.modules.whiteboard
import org.bigbluebutton.modules.whiteboard.business.shapes.ShapeFactory;
import org.bigbluebutton.modules.whiteboard.models.WhiteboardModel;
import org.bigbluebutton.modules.whiteboard.views.AnnotationIDGenerator;
import org.bigbluebutton.modules.whiteboard.views.CursorPositionListener;
import org.bigbluebutton.modules.whiteboard.views.IDrawListener;
import org.bigbluebutton.modules.whiteboard.views.PencilDrawListener;
import org.bigbluebutton.modules.whiteboard.views.ShapeDrawListener;
@ -39,32 +40,23 @@ package org.bigbluebutton.modules.whiteboard
public class WhiteboardCanvasModel {
private var _wbCanvas:WhiteboardCanvas;
private var drawListeners:Array = new Array();
private var cursorPositionListener:CursorPositionListener;
private var wbTool:WhiteboardTool = new WhiteboardTool();
private var shapeFactory:ShapeFactory = new ShapeFactory();
private var idGenerator:AnnotationIDGenerator = new AnnotationIDGenerator();
/* represents the max number of 'points' enumerated in 'segment' before
sending an update to server. Used to prevent spamming red5 with unnecessary packets */
private var sendShapeFrequency:uint = 30;
/* same as above, except a faster interval may be desirable when erasing, for aesthetics */
private var sendEraserFrequency:uint = 20;
private var width:Number;
private var height:Number;
public function setDependencies(canvas:WhiteboardCanvas, displayModel:WhiteboardCanvasDisplayModel):void {
public function setDependencies(canvas:WhiteboardCanvas):void {
_wbCanvas = canvas;
drawListeners.push(new PencilDrawListener(idGenerator, _wbCanvas, shapeFactory));
drawListeners.push(new ShapeDrawListener(idGenerator, _wbCanvas, shapeFactory));
drawListeners.push(new TextDrawListener(idGenerator, _wbCanvas, shapeFactory));
cursorPositionListener = new CursorPositionListener(_wbCanvas, shapeFactory);
}
public function zoomCanvas(width:Number, height:Number):void {
shapeFactory.setParentDim(width, height);
this.width = width;
this.height = height;
shapeFactory.setParentDim(width, height);
}
public function changeFontStyle(font:String):void {
@ -112,6 +104,14 @@ package org.bigbluebutton.modules.whiteboard
public function changeThickness(thickness:uint):void {
wbTool.thickness = thickness;
}
public function presenterChange(amIPresenter:Boolean, presenterId:String):void {
cursorPositionListener.presenterChange(amIPresenter);
}
public function multiUserChange(multiUser:Boolean):void {
cursorPositionListener.multiUserChange(multiUser);
}
/** Helper method to test whether this user is the presenter */
private function get isPresenter():Boolean {

View File

@ -16,19 +16,18 @@
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
*
*/
package org.bigbluebutton.modules.present.events
{
package org.bigbluebutton.modules.whiteboard.events {
import flash.events.Event;
public class CursorEvent extends Event
{
public static const UPDATE_CURSOR:String = "UPDATE_CURSOR";
public class WhiteboardCursorEvent extends Event {
public static const SEND_CURSOR_POSITION:String = "SEND_CURSOR_POSITION";
public static const RECEIVED_CURSOR_POSITION:String = "RECEIVE_CURSOR_POSITION";
public var xPercent:Number;
public var yPercent:Number;
public var userId:String;
public function CursorEvent(type:String)
{
public function WhiteboardCursorEvent(type:String) {
super(type, true, false);
}

View File

@ -32,6 +32,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import org.bigbluebutton.modules.whiteboard.events.StartWhiteboardModuleEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardAccessEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardButtonEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardCursorEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardDrawEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardUpdateReceived;
import org.bigbluebutton.modules.whiteboard.managers.WhiteboardManager;
@ -80,6 +81,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<MethodInvoker generator="{WhiteboardService}" method="undoGraphic" arguments="{event}" />
</EventHandlers>
<EventHandlers type="{WhiteboardCursorEvent.SEND_CURSOR_POSITION}" >
<MethodInvoker generator="{WhiteboardService}" method="sendCursorPosition" arguments="{event}" />
</EventHandlers>
<EventHandlers type="{GetWhiteboardShapesCommand.GET_SHAPES}" >
<MethodInvoker generator="{WhiteboardService}" method="getAnnotationHistory" arguments="{event}" />
</EventHandlers>

View File

@ -31,6 +31,7 @@ package org.bigbluebutton.modules.whiteboard.models
import org.bigbluebutton.modules.whiteboard.business.shapes.DrawObject;
import org.bigbluebutton.modules.whiteboard.commands.GetWhiteboardShapesCommand;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardAccessEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardCursorEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardDrawEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardUpdateReceived;
@ -153,11 +154,19 @@ package org.bigbluebutton.modules.whiteboard.models
var event:WhiteboardAccessEvent = new WhiteboardAccessEvent(WhiteboardAccessEvent.MODIFIED_WHITEBOARD_ACCESS);
event.multiUser = multiUser;
dispatchEvent(event);
}
}
public function get multiUser():Boolean {
return _multiUser;
}
public function updateCursorPosition(userId:String, xPercent:Number, yPercent:Number):void {
var event:WhiteboardCursorEvent = new WhiteboardCursorEvent(WhiteboardCursorEvent.RECEIVED_CURSOR_POSITION);
event.userId = userId;
event.xPercent = xPercent;
event.yPercent = yPercent;
dispatchEvent(event);
}
public function get multiUser():Boolean {
return _multiUser;
}
}
}

View File

@ -49,16 +49,19 @@ package org.bigbluebutton.modules.whiteboard.services
break;
case "WhiteboardAccessModifiedCommand":
handleWhiteboardAccessModifiedCommand(message);
break;
break;
case "WhiteboardNewAnnotationCommand":
handleNewAnnotationCommand(message);
break;
case "WhiteboardClearCommand":
handleClearCommand(message);
break;
break;
case "WhiteboardUndoCommand":
handleUndoCommand(message);
break;
break;
case "WhiteboardCursorPositionUpdatedCommand":
handleCursorPositionUpdatedCommand(message);
break;
default:
// LogUtil.warn("Cannot handle message [" + messageName + "]");
}
@ -124,5 +127,11 @@ package org.bigbluebutton.modules.whiteboard.services
}
}
}
private function handleCursorPositionUpdatedCommand(message:Object):void {
var map:Object = JSON.parse(message.msg);
whiteboardModel.updateCursorPosition(map.requesterId, map.xPercent, map.yPercent);
}
}
}

View File

@ -143,5 +143,28 @@ package org.bigbluebutton.modules.whiteboard.services
e.annotation.annotation
);
}
/**
* Send an event to the server to update the user's cursor position
* @param xPercent
* @param yPercent
*
*/
public function sendCursorPosition(xPercent:Number, yPercent:Number):void {
var message:Object = new Object();
message["xPercent"] = xPercent;
message["yPercent"] = yPercent;
var _nc:ConnectionManager = BBB.initConnectionManager();
_nc.sendMessage("whiteboard.sendCursorPosition",
function(result:String):void { // On successful result
//LOGGER.debug(result);
},
function(status:String):void { // status - On error occurred
LOGGER.error(status);
},
message
);
}
}
}

View File

@ -21,8 +21,9 @@ package org.bigbluebutton.modules.whiteboard.services
import org.as3commons.logging.api.ILogger;
import org.as3commons.logging.api.getClassLogger;
import org.bigbluebutton.modules.whiteboard.commands.GetWhiteboardShapesCommand;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardDrawEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardAccessEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardCursorEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardDrawEvent;
import org.bigbluebutton.modules.whiteboard.models.WhiteboardModel;
public class WhiteboardService
@ -66,6 +67,8 @@ package org.bigbluebutton.modules.whiteboard.services
sender.sendShape(e);
}
public function sendCursorPosition(e:WhiteboardCursorEvent):void {
sender.sendCursorPosition(e.xPercent, e.yPercent);
}
}
}

View File

@ -0,0 +1,87 @@
package org.bigbluebutton.modules.whiteboard.views {
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.utils.Timer;
import org.bigbluebutton.modules.whiteboard.business.shapes.ShapeFactory;
public class CursorPositionListener {
private var _wbCanvas:WhiteboardCanvas;
private var _shapeFactory:ShapeFactory;
private var _timer:Timer;
private var _lastXPosition:Number;
private var _lastYPosition:Number;
private var _amIPresenter:Boolean;
private var _multiUser:Boolean;
public function CursorPositionListener(wbCanvas:WhiteboardCanvas, shapeFactory:ShapeFactory) {
_wbCanvas = wbCanvas;
_shapeFactory = shapeFactory;
_lastXPosition = -1;
_lastYPosition = 1;
_timer = new Timer(100);
_timer.addEventListener(TimerEvent.TIMER, onTimerInterval);
}
public function presenterChange(amIPresenter:Boolean):void {
_amIPresenter = amIPresenter;
verifyTimerState();
}
public function multiUserChange(multiUser:Boolean):void {
_multiUser = multiUser;
verifyTimerState();
}
private function verifyTimerState():void {
if (_amIPresenter || _multiUser) {
startTimer();
} else {
stopTimer();
}
}
private function startTimer():void {
if (!_timer.running) {
_timer.start();
}
}
private function stopTimer():void {
if (_timer.running) {
_timer.stop();
checkMousePosition(-1, -1)
}
}
private function onTimerInterval(e:TimerEvent):void {
checkMousePosition(_wbCanvas.mouseX, _wbCanvas.mouseY);
}
private function checkMousePosition(x:Number, y:Number):void {
// check if mouse position is within bounds
if (isXYOutsideCanvas(x, y)){
x = -1;
y = -1;
}
if (x != _lastXPosition || y != _lastYPosition) {
_lastXPosition = x;
_lastYPosition = y;
var np:Point = _shapeFactory.normalizePoint(x, y);
_wbCanvas.sendCursorPositionToServer(np.x, np.y);
}
}
private function isXYOutsideCanvas(x:Number, y:Number):Boolean {
return (x < 0 || y < 0 || x > _wbCanvas.width || y > _wbCanvas.height);
}
}
}

View File

@ -25,12 +25,15 @@ package org.bigbluebutton.modules.whiteboard.views {
import flash.display.DisplayObject;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import mx.containers.Canvas;
import mx.managers.CursorManager;
import org.bigbluebutton.common.Images;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.main.events.MadePresenterEvent;
import org.bigbluebutton.main.events.UserLeftEvent;
import org.bigbluebutton.modules.whiteboard.WhiteboardCanvasDisplayModel;
import org.bigbluebutton.modules.whiteboard.WhiteboardCanvasModel;
import org.bigbluebutton.modules.whiteboard.business.shapes.DrawObject;
@ -39,6 +42,7 @@ package org.bigbluebutton.modules.whiteboard.views {
import org.bigbluebutton.modules.whiteboard.commands.GetWhiteboardShapesCommand;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardAccessEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardButtonEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardCursorEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardDrawEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardUpdateReceived;
import org.bigbluebutton.modules.whiteboard.models.Annotation;
@ -52,8 +56,9 @@ package org.bigbluebutton.modules.whiteboard.views {
private var textToolbar:WhiteboardTextToolbar;
private var graphicObjectHolder:Canvas = new Canvas();
private var images:Images = new Images();
private var cursorObjectHolder:Canvas = new Canvas();
private var images:Images = new Images();
[Bindable] private var pencil_icon:Class = images.pencil_icon;
[Bindable] private var rectangle_icon:Class = images.square_icon;
[Bindable] private var triangle_icon:Class = images.triangle_icon;
@ -64,12 +69,14 @@ package org.bigbluebutton.modules.whiteboard.views {
private var whiteboardEnabled:Boolean = false;
private var currentWhiteboardId:String;
private var dispatcher:Dispatcher = new Dispatcher();
public function WhiteboardCanvas(wbModel:WhiteboardModel):void {
canvasModel = new WhiteboardCanvasModel();
canvasDisplayModel = new WhiteboardCanvasDisplayModel();
//set up model cross dependencies
canvasModel.setDependencies(this, canvasDisplayModel);
canvasModel.setDependencies(this);
canvasDisplayModel.setDependencies(this, wbModel);
whiteboardToolbar = new WhiteboardToolbar();
@ -87,17 +94,36 @@ package org.bigbluebutton.modules.whiteboard.views {
graphicObjectHolder.clipContent = true;
graphicObjectHolder.tabFocusEnabled = false;
addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
//create the cursor display container
this.addChild(cursorObjectHolder);
cursorObjectHolder.x = 0;
cursorObjectHolder.y = 0;
cursorObjectHolder.clipContent = true;
cursorObjectHolder.tabFocusEnabled = false;
wbModel.addEventListener(WhiteboardUpdateReceived.NEW_ANNOTATION, onNewAnnotationEvent);
wbModel.addEventListener(WhiteboardUpdateReceived.RECEIVED_ANNOTATION_HISTORY, onReceivedAnnotationsHistory);
wbModel.addEventListener(WhiteboardUpdateReceived.CLEAR_ANNOTATIONS, onClearAnnotations);
wbModel.addEventListener(WhiteboardUpdateReceived.UNDO_ANNOTATION, onUndoAnnotation);
wbModel.addEventListener(WhiteboardAccessEvent.MODIFIED_WHITEBOARD_ACCESS, onModifiedAccess);
wbModel.addEventListener(WhiteboardCursorEvent.RECEIVED_CURSOR_POSITION, onReceivedCursorPosition);
whiteboardToolbar.addEventListener(WhiteboardButtonEvent.ENABLE_WHITEBOARD, onEnableWhiteboardEvent);
whiteboardToolbar.addEventListener(WhiteboardButtonEvent.DISABLE_WHITEBOARD, onDisableWhiteboardEvent);
var stpl:Listener = new Listener();
stpl.type = MadePresenterEvent.SWITCH_TO_PRESENTER_MODE;
stpl.method = onSwitchToPresenterEvent;
var stvl:Listener = new Listener();
stvl.type = MadePresenterEvent.SWITCH_TO_VIEWER_MODE;
stvl.method = onSwitchToViewerEvent;
presenterChange(UsersUtil.amIPresenter(), UsersUtil.getPresenterUserID());
var ull:Listener = new Listener();
ull.type = UserLeftEvent.LEFT;
ull.method = onUserLeftEvent;
}
public function attachToReceivingObject(ro:IWhiteboardReceiver):void {
@ -107,14 +133,19 @@ package org.bigbluebutton.modules.whiteboard.views {
private function registerForMouseEvents():void {
addEventListener(MouseEvent.MOUSE_DOWN, doMouseDown);
addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
}
private function unregisterForMouseEvents():void {
removeEventListener(MouseEvent.MOUSE_DOWN, doMouseDown);
removeEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
removeEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
}
private function doMouseUp(event:MouseEvent):void {
canvasModel.doMouseUp(Math.min(Math.max(parent.mouseX, 0), parent.width) - this.x, Math.min(Math.max(parent.mouseY, 0), parent.height) - this.y);
var mousePoint:Point = getMouseXY();
canvasModel.doMouseUp(mousePoint.x, mousePoint.y);
stage.removeEventListener(MouseEvent.MOUSE_UP, doMouseUp);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, doMouseMove);
@ -130,7 +161,8 @@ package org.bigbluebutton.modules.whiteboard.views {
}
private function doMouseMove(event:MouseEvent):void {
canvasModel.doMouseMove(Math.min(Math.max(parent.mouseX, 0), parent.width-1) - this.x, Math.min(Math.max(parent.mouseY, 0), parent.height-1) - this.y);
var mousePoint:Point = getMouseXY();
canvasModel.doMouseMove(mousePoint.x, mousePoint.y);
}
public function changeColor(e:Event):void {
@ -145,24 +177,28 @@ package org.bigbluebutton.modules.whiteboard.views {
// LogUtil.debug("DISPATCHING SEND sendGraphicToServer [" + type + "]");
var event:WhiteboardDrawEvent = new WhiteboardDrawEvent(WhiteboardDrawEvent.SEND_SHAPE);
event.annotation = gobj;
var dispatcher:Dispatcher = new Dispatcher();
dispatcher.dispatchEvent(event);
dispatcher.dispatchEvent(event);
}
public function sendUndoToServer():void {
var event:WhiteboardDrawEvent = new WhiteboardDrawEvent(WhiteboardDrawEvent.UNDO);
event.wbId = currentWhiteboardId;
var dispatcher:Dispatcher = new Dispatcher();
dispatcher.dispatchEvent(event);
}
public function sendClearToServer():void {
var event:WhiteboardDrawEvent = new WhiteboardDrawEvent(WhiteboardDrawEvent.CLEAR);
event.wbId = currentWhiteboardId;
var dispatcher:Dispatcher = new Dispatcher();
dispatcher.dispatchEvent(event);
}
public function sendCursorPositionToServer(x:Number, y:Number):void {
var event:WhiteboardCursorEvent = new WhiteboardCursorEvent(WhiteboardCursorEvent.SEND_CURSOR_POSITION);
event.xPercent = x;
event.yPercent = y;
dispatcher.dispatchEvent(event);
}
public function setGraphicType(type:String):void {
if (canvasModel == null) return;
canvasModel.setGraphicType(type);
@ -214,16 +250,21 @@ package org.bigbluebutton.modules.whiteboard.views {
CursorManager.removeCursor(CursorManager.currentCursorID);
}
public function doesContain(child:DisplayObject):Boolean {
private function getMouseXY():Point {
return new Point(Math.min(Math.max(parent.mouseX, 0), parent.width-1) - this.x, Math.min(Math.max(parent.mouseY, 0), parent.height-1) - this.y);
}
private function presenterChange(amIPresenter:Boolean, presenterId:String):void {
canvasModel.presenterChange(amIPresenter, presenterId);
canvasDisplayModel.presenterChange(amIPresenter, presenterId);
}
public function doesContainGraphic(child:DisplayObject):Boolean {
return this.graphicObjectHolder.rawChildren.contains(child);
}
public function getMouseXY():Array {
return [Math.min(Math.max(parent.mouseX, 0), parent.width-2) - this.x, Math.min(Math.max(parent.mouseY, 0), parent.height-2) - this.y];
}
public function removeGraphic(child:DisplayObject):void {
if (doesContain(child)) this.graphicObjectHolder.rawChildren.removeChild(child);
if (doesContainGraphic(child)) this.graphicObjectHolder.rawChildren.removeChild(child);
else trace("Does not contain");
}
@ -231,6 +272,18 @@ package org.bigbluebutton.modules.whiteboard.views {
this.graphicObjectHolder.rawChildren.addChild(child);
}
private function doesContainCursor(cursor:DisplayObject):Boolean {
return this.cursorObjectHolder.rawChildren.contains(cursor);
}
public function addCursor(cursor:DisplayObject):void {
this.cursorObjectHolder.rawChildren.addChild(cursor);
}
public function removeCursorChild(cursor:DisplayObject):void {
if (doesContainCursor(cursor)) this.cursorObjectHolder.rawChildren.removeChild(cursor);
}
public function textToolbarSyncProxy(tobj:TextObject):void {
textToolbar.syncPropsWith(tobj);
}
@ -243,6 +296,8 @@ package org.bigbluebutton.modules.whiteboard.views {
public function zoomCanvas(width:Number, height:Number):void {
graphicObjectHolder.width = width;
graphicObjectHolder.height = height;
cursorObjectHolder.width = width;
cursorObjectHolder.height = height;
this.width = width;
this.height = height;
canvasDisplayModel.zoomCanvas(width, height);
@ -282,9 +337,14 @@ package org.bigbluebutton.modules.whiteboard.views {
private function onModifiedAccess(e:WhiteboardAccessEvent):void {
//if (e.whiteboardId == currentWhiteboardId) {
whiteboardToolbar.whiteboardAccessModified(e.multiUser);
canvasModel.multiUserChange(e.multiUser);
//}
}
private function onReceivedCursorPosition(e:WhiteboardCursorEvent):void {
canvasDisplayModel.drawCursor(e.userId, e.xPercent, e.yPercent);
}
private function onEnableWhiteboardEvent(e:WhiteboardButtonEvent):void {
e.stopPropagation();
@ -298,5 +358,17 @@ package org.bigbluebutton.modules.whiteboard.views {
this.whiteboardEnabled = false;
setWhiteboardInteractable();
}
private function onSwitchToPresenterEvent(e:MadePresenterEvent):void {
presenterChange(true, e.userID);
}
private function onSwitchToViewerEvent(e:MadePresenterEvent):void {
presenterChange(false, e.userID);
}
private function onUserLeftEvent(e:UserLeftEvent):void {
canvasDisplayModel.userLeft(e.userID);
}
}
}

View File

@ -0,0 +1,102 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2017 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.modules.whiteboard.views {
import flash.display.Shape;
public class WhiteboardCursor extends Shape {
private static const PRESENTER_COLOR:uint = 0xFF0000;
private static const OTHER_COLOR:uint = 0x00FF00;
private var _userId:String;
private var _origX:Number;
private var _origY:Number;
private var _parentWidth:Number;
private var _parentHeight:Number;
private var _isPresenter:Boolean;
public function WhiteboardCursor(userId:String, x:Number, y:Number, parentWidth:Number, parentHeight:Number, isPresenter:Boolean) {
_userId = userId;
_origX = x;
_origY = y;
_parentWidth = parentWidth;
_parentHeight = parentHeight;
_isPresenter = isPresenter;
drawCursor();
setPosition();
}
public function updatePosition(x:Number, y:Number):void {
_origX = x;
_origY = y;
setPosition();
}
public function updateParentSize(parentWidth:Number, parentHeight:Number):void {
_parentWidth = parentWidth;
_parentHeight = parentHeight;
setPosition();
}
public function updatePresenter(isPresenter:Boolean):void {
_isPresenter = isPresenter;
drawCursor();
}
private function setPosition():void {
x = denormalize(_origX, _parentWidth);
y = denormalize(_origY, _parentHeight);
if (isCursorOutsideWindow()) {
hideCursor()
} else {
showCursor();
}
}
private function showCursor():void {
visible = true;
}
private function hideCursor():void{
visible = false;
}
private function isCursorOutsideWindow():Boolean {
return (_origX > 100 || _origX < 0 ||
_origY > 100 || _origY < 0);
}
private function drawCursor():void {
var cursorColor:uint = (_isPresenter ? PRESENTER_COLOR : OTHER_COLOR);
graphics.clear();
graphics.lineStyle(6, cursorColor, 0.6);
graphics.drawCircle(0,0,2.5);
}
private function denormalize(val:Number, side:Number):Number {
return (val*side)/100.0;
}
}
}