Modified: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.html
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.html?rev=1739063&r1=1739062&r2=1739063&view=diff
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.html
 (original)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.html
 Thu Apr 14 11:46:52 2016
@@ -19,16 +19,22 @@
   
 -->
 <html xmlns:wicket="http://wicket.apache.org";>
+<wicket:head>
+       <script type="text/javascript">
+               Wicket.Event.subscribe("/websocket/closed", function(jqEvent, 
msg) {
+                       //FIXME add Error dialog should be displayed 
+               });
+       </script>
+</wicket:head>
 <wicket:panel>
-       <div id="swfloading"
-               style="z-index: 666666; position: absolute; top: 50%; left: 
50%;">
-               <img src="images/ajax-loader.gif" />
+       <div wicket:id="roomContainer" style="height: 100%">
+               <div class="room menu" wicket:id="roomMenu"></div>
+               <div class="room sidebar left" wicket:id="sidebar"></div>
+               <div class="room wb area">
+                       <div class="wb" wicket:id="whiteboard"></div>
+               </div>
+               <div wicket:id="activitiesPanel"></div>
        </div>
-       <noscript>Please enable JavaScript in order to use this 
application.</noscript>
-       <script type="text/javascript" wicket:id="init"></script>
-       <div wicket:id="invite"></div>
-       <div wicket:id="createPoll"></div>
-       <div wicket:id="vote"></div>
-       <div wicket:id="pollResults"></div>
+       <div wicket:id="accessDenied"></div>
 </wicket:panel>
-</html>
\ No newline at end of file
+</html>

Modified: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java?rev=1739063&r1=1739062&r2=1739063&view=diff
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
 (original)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
 Thu Apr 14 11:46:52 2016
@@ -19,280 +19,335 @@
 package org.apache.openmeetings.web.room;
 
 import static org.apache.openmeetings.util.OpenmeetingsVariables.webAppRootKey;
+import static org.apache.openmeetings.web.app.Application.addUserToRoom;
 import static org.apache.openmeetings.web.app.Application.getBean;
 import static org.apache.openmeetings.web.app.Application.getRoomUsers;
-import static org.apache.openmeetings.web.app.WebSession.getLanguage;
-import static org.apache.openmeetings.web.app.WebSession.getSid;
 import static org.apache.openmeetings.web.app.WebSession.getUserId;
-import static org.apache.openmeetings.web.room.RoomBroadcaster.getClient;
-import static 
org.apache.openmeetings.web.util.CallbackFunctionHelper.getNamedFunction;
-import static org.apache.wicket.ajax.attributes.CallbackParameter.explicit;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.net.MalformedURLException;
+import java.net.URL;
 
-import org.apache.openmeetings.core.session.SessionManager;
-import org.apache.openmeetings.db.dao.room.InvitationDao;
-import org.apache.openmeetings.db.dao.room.PollDao;
-import org.apache.openmeetings.db.dao.room.RoomDao;
-import org.apache.openmeetings.db.dao.server.SOAPLoginDao;
-import org.apache.openmeetings.db.dao.server.ServerDao;
-import org.apache.openmeetings.db.dao.server.SessiondataDao;
-import org.apache.openmeetings.db.entity.room.Client;
-import org.apache.openmeetings.db.entity.server.SOAPLogin;
-import org.apache.openmeetings.db.entity.server.Server;
-import org.apache.openmeetings.web.app.WebSession;
+import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
+import org.apache.openmeetings.db.dao.calendar.AppointmentDao;
+import org.apache.openmeetings.db.dao.user.UserDao;
+import org.apache.openmeetings.db.entity.calendar.Appointment;
+import org.apache.openmeetings.db.entity.calendar.MeetingMember;
+import org.apache.openmeetings.db.entity.room.Room;
+import org.apache.openmeetings.db.entity.room.RoomGroup;
+import org.apache.openmeetings.db.entity.room.RoomModerator;
+import org.apache.openmeetings.db.entity.user.GroupUser;
+import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.db.util.AuthLevelUtil;
+import org.apache.openmeetings.web.app.Application;
+import org.apache.openmeetings.web.app.Client;
 import org.apache.openmeetings.web.common.BasePanel;
-import org.apache.openmeetings.web.room.poll.CreatePollDialog;
-import org.apache.openmeetings.web.room.poll.PollResultsDialog;
-import org.apache.openmeetings.web.room.poll.VoteDialog;
+import org.apache.openmeetings.web.room.activities.ActivitiesPanel;
+import org.apache.openmeetings.web.room.activities.Activity;
+import org.apache.openmeetings.web.room.menu.RoomMenuPanel;
+import org.apache.openmeetings.web.room.message.RoomMessage;
+import org.apache.openmeetings.web.room.sidebar.RoomSidebar;
 import org.apache.wicket.Component;
-import org.apache.wicket.RuntimeConfigurationType;
-import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
 import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
 import org.apache.wicket.ajax.AjaxRequestTarget;
+import 
org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;
 import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
-import org.apache.wicket.markup.head.CssHeaderItem;
+import org.apache.wicket.event.IEvent;
 import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
 import org.apache.wicket.markup.head.PriorityHeaderItem;
-import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.request.mapper.parameter.PageParameters;
-import org.apache.wicket.request.mapper.parameter.PageParametersEncoder;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.protocol.ws.WebSocketSettings;
+import org.apache.wicket.protocol.ws.api.IWebSocketConnection;
+import org.apache.wicket.protocol.ws.api.event.WebSocketPushPayload;
+import org.apache.wicket.protocol.ws.api.registry.IWebSocketConnectionRegistry;
+import org.apache.wicket.protocol.ws.api.registry.PageIdKey;
+import org.apache.wicket.protocol.ws.concurrent.Executor;
 import org.apache.wicket.request.resource.JavaScriptResourceReference;
 import org.apache.wicket.request.resource.ResourceReference;
-import org.apache.wicket.util.string.StringValue;
-import org.apache.wicket.util.time.Duration;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
 
+import com.googlecode.wicket.jquery.core.JQueryBehavior;
+import com.googlecode.wicket.jquery.ui.widget.dialog.DialogButton;
+import com.googlecode.wicket.jquery.ui.widget.dialog.DialogButtons;
+import com.googlecode.wicket.jquery.ui.widget.dialog.DialogIcon;
+import com.googlecode.wicket.jquery.ui.widget.dialog.MessageDialog;
+
+@AuthorizeInstantiation("Room")
 public class RoomPanel extends BasePanel {
+       //TODO demoTime - demo timer
        private static final long serialVersionUID = 1L;
-       private static final String WICKET_ROOM_ID = "wicketroomid";
-       public static final String PARAM_PUBLIC_SID = "publicSid";
-       public static final String PARAM_URL = "url";
        private static final Logger log = 
Red5LoggerFactory.getLogger(RoomPanel.class, webAppRootKey);
-       private final InvitationDialog invite;
-       private final CreatePollDialog createPoll;
-       private final VoteDialog vote;
-       private final PollResultsDialog pollResults;
-       private final StartSharingEventBehavior startSharing;
-       private Long roomId = null;
-       
-       public RoomPanel(String id) {
-               this(id, new PageParameters());
-       }
-       
-       private String getFlashFile() {
-               return RuntimeConfigurationType.DEVELOPMENT == 
getApplication().getConfigurationType()
-                               ? "maindebug.swf11.swf" : "main.swf11.swf";
-       }
-       
-       private static PageParameters addServer(PageParameters pp, Server s) {
-               return pp.add("protocol", s.getProtocol()).add("host", 
s.getAddress()).add("port", s.getPort()).add("context", s.getWebapp());
-       }
-       
-       public static PageParameters addServer(Long roomId, boolean addBasic) {
-               PageParameters pp = new PageParameters();
-               if (addBasic) {
-                       pp.add("wicketsid", getSid()).add(WICKET_ROOM_ID, 
roomId).add("language", getLanguage());
-               }
-               List<Server> serverList = 
getBean(ServerDao.class).getActiveServers();
+       private final Room r;
+       private final Client client;
+       private final RoomMenuPanel menu;
+       private final RoomSidebar sidebar;
+       private final WebMarkupContainer room = new 
WebMarkupContainer("roomContainer");
+       private final AbstractDefaultAjaxBehavior aab = new 
AbstractDefaultAjaxBehavior() {
+               private static final long serialVersionUID = 1L;
 
-               long minimum = -1;
-               Server result = null;
-               HashMap<Server, List<Long>> activeRoomsMap = new 
HashMap<Server, List<Long>>();
-               for (Server server : serverList) {
-                       List<Long> roomIds = 
getBean(SessionManager.class).getActiveRoomIdsByServer(server);
-                       if (roomIds.contains(roomId)) {
-                               // if the room is already opened on a server, 
redirect the user to that one,
-                               log.debug("Room is already opened on a server " 
+ server.getAddress());
-                               return addServer(pp, server);
+               @Override
+               protected void respond(AjaxRequestTarget target) {
+                       target.appendJavaScript("setHeight();");
+                       //TODO SID etc
+                       ConfigurationDao cfgDao = 
getBean(ConfigurationDao.class);
+                       try {
+                               URL url = new URL(cfgDao.getBaseUrl());
+                               String path = url.getPath();
+                               path = path.substring(1, path.indexOf('/', 2) + 
1);
+                               broadcast(new RoomMessage(r.getId(), 
RoomMessage.Type.roomEnter));
+                               getMainPage().getChat().roomEnter(r, target);
+                       } catch (MalformedURLException e) {
+                               log.error("Error while constructing room 
parameters", e);
                        }
-                       activeRoomsMap.put(server, roomIds);
                }
-               for (Map.Entry<Server, List<Long>> entry : 
activeRoomsMap.entrySet()) {
-                       List<Long> roomIds = entry.getValue();
-                       long capacity = 
getBean(RoomDao.class).getRoomsCapacityByIds(roomIds);
-                       if (minimum < 0 || capacity < minimum) {
-                               minimum = capacity;
-                               result = entry.getKey();
-                       }
-                       log.debug("Checking server: " + entry.getKey() + " 
Number of rooms " + roomIds.size() + " RoomIds: "
-                                       + roomIds + " max(Sum): " + capacity);
-               }
-               return result == null ? pp : addServer(pp, result);
-       }
-
-       public RoomPanel(String id, Long roomId) {
-               this(id, addServer(roomId, true));
-       }
+       };
+       private final ActivitiesPanel activities;
        
-       public RoomPanel(String id, PageParameters pp) {
+       public RoomPanel(String id, Room r) {
                super(id);
-               //OK let's find the room
-               try {
-                       StringValue room = pp.get(WICKET_ROOM_ID);
-                       StringValue secureHash = pp.get(WebSession.SECURE_HASH);
-                       StringValue invitationHash = 
pp.get(WebSession.INVITATION_HASH);
-                       if (!room.isEmpty()) {
-                               roomId = room.toLongObject();
-                       } else if (!secureHash.isEmpty()) {
-                               if 
(WebSession.get().signIn(secureHash.toString(), false)) {
-                                       SOAPLogin soapLogin = 
getBean(SOAPLoginDao.class).get(secureHash.toString());
-                                       roomId = soapLogin.getRoomId();
-                                       pp = 
pp.mergeWith(RoomPanel.addServer(roomId, false));
-                               }
-                               //TODO access denied
-                       } else if (!invitationHash.isEmpty()) {
-                               roomId = 
getBean(InvitationDao.class).getInvitationByHashCode(invitationHash.toString(), 
true).getRoom().getId();
-                       }
-               } catch (Exception e) {
-                       //no-op
-               }
-               StringValue swfVal = pp.get("swf");
-               PageParameters spp = new PageParameters(pp);
-               if (roomId != null) {
-                       spp.mergeWith(new PageParameters().add(WICKET_ROOM_ID, 
roomId));
-               }
-               String swf = (swfVal.isEmpty() ? getFlashFile() : 
swfVal.toString())
-                               + new 
PageParametersEncoder().encodePageParameters(spp);
-               add(new Label("init", String.format("initSwf('%s');", 
swf)).setEscapeModelStrings(false));
-               add(new AbstractAjaxTimerBehavior(Duration.minutes(5)) {
-                       private static final long serialVersionUID = 1L;
-
-                       @Override
-                       protected void onTimer(AjaxRequestTarget target) {
-                               
getBean(SessiondataDao.class).checkSession(WebSession.getSid()); //keep SID 
alive
-                       }
-               });
-               add(invite = new InvitationDialog("invite", roomId));
-               add(createPoll = new CreatePollDialog("createPoll", roomId));
-               add(vote = new VoteDialog("vote", roomId));
-               add(pollResults = new PollResultsDialog("pollResults", roomId));
-               add(startSharing = new StartSharingEventBehavior(roomId));
-               if (roomId != null && roomId.longValue() > 0) {
-                       add(new AbstractDefaultAjaxBehavior() {
-                               private static final long serialVersionUID = 1L;
-       
-                               @Override
-                               protected void respond(AjaxRequestTarget 
target) {
-                                       invite.updateModel(target);
-                                       invite.open(target);
-                               }
-                               
-                               @Override
-                               public void renderHead(Component component, 
IHeaderResponse response) {
-                                       super.renderHead(component, response);
-                                       response.render(new 
PriorityHeaderItem(JavaScriptHeaderItem.forScript(getNamedFunction("openInvitation",
 this), "openInvitation")));
-                               }
-                       });
-                       add(new AbstractDefaultAjaxBehavior() {
-                               private static final long serialVersionUID = 1L;
-       
-                               @Override
-                               protected void respond(AjaxRequestTarget 
target) {
-                                       String publicSid = getPublicSid();
-                                       Client c = getClient(publicSid);
-                                       if (c != null && c.getIsMod()) {
-                                               createPoll.updateModel(target, 
publicSid);
-                                               createPoll.open(target);
+               this.r = r;
+               Component accessDenied = new 
WebMarkupContainer("accessDenied").setVisible(false);
+               boolean allowed = false;
+               String deniedMessage = null;
+               if (r.isAppointment()) {
+                       Appointment a = 
getBean(AppointmentDao.class).getByRoom(r.getId());
+                       if (a != null && !a.isDeleted()) {
+                               allowed = 
a.getOwner().getId().equals(getUserId());
+                               log.debug("appointed room, isOwner ? " + 
allowed);
+                               if (!allowed) {
+                                       for (MeetingMember mm : 
a.getMeetingMembers()) {
+                                               if (mm.getUser().getId() == 
getUserId()) {
+                                                       allowed = true;
+                                                       break;
+                                               }
                                        }
                                }
-                               
-                               @Override
-                               public void renderHead(Component component, 
IHeaderResponse response) {
-                                       super.renderHead(component, response);
-                                       response.render(new 
PriorityHeaderItem(JavaScriptHeaderItem.forScript(getNamedFunction("createPoll",
 this, explicit(PARAM_PUBLIC_SID)), "createPoll")));
+                               /*
+                               TODO need to be reviewed
+                               Calendar c = WebSession.getCalendar();
+                               if (c.getTime().after(a.getStart()) && 
c.getTime().before(a.getEnd())) {
+                                       allowed = true;
+                               } else {
+                                       SimpleDateFormat sdf = new 
SimpleDateFormat("yyyy/MM/dd HH:mm"); //FIXME format
+                                       deniedMessage = 
Application.getString(1271) + String.format(" %s - %s", 
sdf.format(a.getStart()), sdf.format(a.getEnd()));
                                }
-                       });
-                       add(new AbstractDefaultAjaxBehavior() {
-                               private static final long serialVersionUID = 1L;
-       
-                               @Override
-                               protected void respond(AjaxRequestTarget 
target) {
-                                       Client c = getClient(getPublicSid());
-                                       if (c != null) {
-                                               pollResults.updateModel(target, 
c.getIsMod());
-                                               pollResults.open(target);
+                               */
+                       }
+               } else {
+                       allowed = r.getIspublic() || (r.getOwnerId() != null && 
r.getOwnerId().equals(getUserId()));
+                       log.debug("public ? " + r.getIspublic() + ", ownedId ? 
" + r.getOwnerId() + " " + allowed);
+                       if (!allowed) {
+                               User u = 
getBean(UserDao.class).get(getUserId());
+                               for (RoomGroup ro : r.getRoomGroups()) {
+                                       for (GroupUser ou : u.getGroupUsers()) {
+                                               if 
(ro.getGroup().getId().equals(ou.getGroup().getId())) {
+                                                       allowed = true;
+                                                       break;
+                                               }
                                        }
-                               }
-                               
-                               @Override
-                               public void renderHead(Component component, 
IHeaderResponse response) {
-                                       super.renderHead(component, response);
-                                       response.render(new 
PriorityHeaderItem(JavaScriptHeaderItem.forScript(getNamedFunction("pollResults",
 this, explicit(PARAM_PUBLIC_SID)), "pollResults")));
-                               }
-                       });
-                       add(new AbstractDefaultAjaxBehavior() {
-                               private static final long serialVersionUID = 1L;
-       
-                               @Override
-                               protected void respond(AjaxRequestTarget 
target) {
-                                       if 
(getBean(PollDao.class).hasPoll(roomId) && 
!getBean(PollDao.class).hasVoted(roomId, getUserId()) && 
getClient(getPublicSid()) != null) {
-                                               vote.updateModel(target);
-                                               vote.open(target);
+                                       if (allowed) {
+                                               break;
                                        }
                                }
-                               
-                               @Override
-                               public void renderHead(Component component, 
IHeaderResponse response) {
-                                       super.renderHead(component, response);
-                                       response.render(new 
PriorityHeaderItem(JavaScriptHeaderItem.forScript(getNamedFunction("vote", 
this, explicit(PARAM_PUBLIC_SID)), "vote")));
+                       }
+               }
+               if (!allowed) {
+                       if (deniedMessage == null) {
+                               deniedMessage = Application.getString(1599);
+                       }
+                       accessDenied = new ExpiredMessageDialog("accessDenied", 
deniedMessage);
+                       room.setVisible(false);
+               }
+               client = new Client(r.getId());
+               room.add((menu = new RoomMenuPanel("roomMenu", 
this)).setVisible(!r.getHideTopBar()));
+               room.add(new SwfPanel("whiteboard", client));
+               room.add(aab);
+               room.add(sidebar = new RoomSidebar("sidebar", this));
+               room.add((activities = new ActivitiesPanel("activitiesPanel", 
r.getId())).setVisible(!r.isActivitiesHidden()));
+               add(room, accessDenied);
+       }
+
+       @Override
+       public void onEvent(IEvent<?> event) {
+               if (event.getPayload() instanceof WebSocketPushPayload) {
+                       WebSocketPushPayload wsEvent = (WebSocketPushPayload) 
event.getPayload();
+                       if (wsEvent.getMessage() instanceof RoomMessage) {
+                               RoomMessage m = 
(RoomMessage)wsEvent.getMessage();
+                               IPartialPageRequestHandler handler = 
wsEvent.getHandler();
+                               switch (m.getType()) {
+                                       case pollCreated:
+                                               if (getUserId() != 
m.getUserId()) {
+                                                       
menu.pollCreated(handler);
+                                               }
+                                       case pollClosed:
+                                       case pollDeleted:
+                                       case voted:
+                                       case rightUpdated:
+                                               menu.update(handler);
+                                               break;
+                                       case roomEnter:
+                                               menu.update(handler);
+                                               sidebar.updateUsers(handler);
+                                               
//activities.addActivity(m.getUid(), m.getSentUserId(), 
Activity.Type.roomEnter, handler);
+                                               break;
+                                       case roomExit:
+                                               //TODO check user/remove tab
+                                               sidebar.updateUsers(handler);
+                                               
activities.addActivity(m.getUid(), m.getUserId(), Activity.Type.roomExit, 
handler);
+                                               break;
+                                       case requestRightModerator:
+                                               if (isModerator(getUserId(), 
r.getId())) {
+                                                       
activities.addActivity(m.getUid(), m.getUserId(), 
Activity.Type.requestRightModerator, handler);
+                                               }
+                                               break;
+                                       default:
+                                               break;
                                }
-                       });
-                       add(new AbstractDefaultAjaxBehavior() {
-                               private static final long serialVersionUID = 1L;
-       
-                               @Override
-                               protected void respond(AjaxRequestTarget 
target) {
-                                       startSharing.respond(target);
+                       }
+               }
+               super.onEvent(event);
+       }
+       
+       @Override
+       protected void onBeforeRender() {
+               super.onBeforeRender();
+               if (room.isVisible()) {
+                       addUserToRoom(client, getPage().getPageId());
+                       User u = getBean(UserDao.class).get(getUserId());
+                       //TODO do we need to check GroupModerationRights ????
+                       if (AuthLevelUtil.hasAdminLevel(u.getRights())) {
+                               client.getRights().add(Client.Right.moderator);
+                       } else {
+                               if (!r.isModerated() && 1 == 
getRoomUsers(r.getId()).size()) {
+                                       
client.getRights().add(Client.Right.moderator);
+                               } else if (r.isModerated()) {
+                                       //TODO why do we need supermoderator 
????
+                                       for (RoomModerator rm : 
r.getModerators()) {
+                                               if (getUserId() == 
rm.getUser().getId()) {
+                                                       
client.getRights().add(Client.Right.moderator);
+                                                       break;
+                                               }
+                                       }
                                }
-                               
-                               @Override
-                               public void renderHead(Component component, 
IHeaderResponse response) {
-                                       super.renderHead(component, response);
-                                       response.render(new 
PriorityHeaderItem(JavaScriptHeaderItem.forScript(getNamedFunction("startSharing",
 this, explicit(PARAM_PUBLIC_SID), explicit(PARAM_URL)), "startSharing")));
+                       }
+               }
+       }
+       
+       public static void broadcast(final RoomMessage m) {
+               WebSocketSettings settings = 
WebSocketSettings.Holder.get(Application.get());
+               IWebSocketConnectionRegistry reg = 
settings.getConnectionRegistry();
+               Executor executor = settings.getWebSocketPushMessageExecutor();
+               for (Client c : getRoomUsers(m.getRoomId())) {
+                       try {
+                               final IWebSocketConnection wsConnection = 
reg.getConnection(Application.get(), c.getSessionId(), new 
PageIdKey(c.getPageId()));
+                               if (wsConnection != null) {
+                                       executor.run(new Runnable() {
+                                               @Override
+                                               public void run() {
+                                                       
wsConnection.sendMessage(m);
+                                               }
+                                       });
                                }
-                       });
+                       } catch (Exception e) {
+                               log.error("Error while broadcasting message to 
room", e);
+                       }
                }
        }
-
+       
        public static boolean isModerator(long userId, long roomId) {
-               for (org.apache.openmeetings.web.app.Client c : 
getRoomUsers(roomId)) {
-                       if (c.getUserId() == userId && 
c.hasRight(org.apache.openmeetings.web.app.Client.Right.moderator)) {
+               for (Client c : getRoomUsers(roomId)) {
+                       if (c.getUserId() == userId && 
c.hasRight(Client.Right.moderator)) {
                                return true;
                        }
                }
                return false;
        }
        
+       public static void sendRoom(long roomId, String msg) {
+               IWebSocketConnectionRegistry reg = 
WebSocketSettings.Holder.get(Application.get()).getConnectionRegistry();
+               for (Client c : getRoomUsers(roomId)) {
+                       try {
+                               reg.getConnection(Application.get(), 
c.getSessionId(), new PageIdKey(c.getPageId())).sendMessage(msg);
+                       } catch (Exception e) {
+                               log.error("Error while sending message to 
room", e);
+                       }
+               }
+       }
+       
        @Override
        public void onMenuPanelLoad(IPartialPageRequestHandler handler) {
-               handler.add(getMainPage().getHeader().setVisible(false), 
getMainPage().getMenu().setVisible(false)
-                               , 
getMainPage().getTopLinks().setVisible(false));
-               //handler.appendJavaScript("roomLoad();");
+               handler.add(getMainPage().getHeader().setVisible(false), 
getMainPage().getTopControls().setVisible(false));
+               if (r.isChatHidden()) {
+                       getMainPage().getChat().toggle(handler, false);
+               }
+               handler.appendJavaScript("roomLoad();");
        }
        
+       @Override
+       public void cleanup(IPartialPageRequestHandler handler) {
+               handler.add(getMainPage().getHeader().setVisible(true), 
getMainPage().getTopControls().setVisible(true));
+               if (r.isChatHidden()) {
+                       getMainPage().getChat().toggle(handler, true);
+               }
+               
handler.appendJavaScript("$(window).off('resize.openmeetings');");
+               RoomMenuPanel.roomExit(this);
+               getMainPage().getChat().roomExit(r, handler);
+       }
+
        private static ResourceReference newResourceReference() {
-               return new JavaScriptResourceReference(RoomPanel.class, 
"swf-functions.js");
+               return new JavaScriptResourceReference(RoomPanel.class, 
"room.js");
        }
        
        @Override
        public void renderHead(IHeaderResponse response) {
                super.renderHead(response);
                response.render(new 
PriorityHeaderItem(JavaScriptHeaderItem.forReference(newResourceReference())));
-               response.render(new 
PriorityHeaderItem(JavaScriptHeaderItem.forUrl("js/history.js")));
-               response.render(new 
PriorityHeaderItem(JavaScriptHeaderItem.forUrl("js/openmeetings_functions.js")));
-               response.render(new 
PriorityHeaderItem(CssHeaderItem.forUrl("css/history.css")));
-               //FIXME TODO ugly HACK
-               if 
(WebSession.get().getClientInfo().getProperties().isBrowserMozillaFirefox()) {
-                       response.render(new 
PriorityHeaderItem(CssHeaderItem.forCSS(".ui-widget-overlay{opacity: 1 
!important;}", "linux-ff-veil-hack")));
+               if (room.isVisible()) {
+                       
response.render(OnDomReadyHeaderItem.forScript(aab.getCallbackScript()));
+               }
+       }
+
+       class ExpiredMessageDialog extends MessageDialog {
+               private static final long serialVersionUID = 1L;
+               public boolean autoOpen = false;
+               
+               public ExpiredMessageDialog(String id, String message) {
+                       super(id, Application.getString(204), message, 
DialogButtons.OK, DialogIcon.ERROR);
+                       autoOpen = true;
+               }
+               
+               @Override
+               public boolean isModal() {
+                       return true;
                }
+               
+               @Override
+               public void onConfigure(JQueryBehavior behavior) {
+                       super.onConfigure(behavior);
+                       behavior.setOption("autoOpen", autoOpen);
+               }
+               
+               @Override
+               public void onClose(IPartialPageRequestHandler handler, 
DialogButton button) {
+                       menu.exit(handler);
+               }
+       }
+       
+       public Room getRoom() {
+               return r;
        }
        
-       private String getPublicSid() {
-               return 
getRequest().getRequestParameters().getParameterValue(PARAM_PUBLIC_SID).toString();
+       public Client getClient() {
+               return client;
+       }
+       
+       public RoomSidebar getSidebar() {
+               return sidebar;
+       }
+
+       public ActivitiesPanel getActivities() {
+               return activities;
        }
 }

Added: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/SwfPanel.html
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/SwfPanel.html?rev=1739063&view=auto
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/SwfPanel.html
 (added)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/SwfPanel.html
 Thu Apr 14 11:46:52 2016
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+      http://www.apache.org/licenses/LICENSE-2.0
+         
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  
+-->
+<html xmlns:wicket="http://wicket.apache.org";>
+<wicket:panel>
+       <div id="swfloading" style="z-index: 666666; position: absolute; top: 
50%; left: 50%;">
+               <img src="images/ajax-loader.gif" />
+       </div>
+       <noscript>Please enable JavaScript in order to use this 
application.</noscript>
+       <script type="text/javascript" wicket:id="init"></script>
+</wicket:panel>
+</html>

Added: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/SwfPanel.java
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/SwfPanel.java?rev=1739063&view=auto
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/SwfPanel.java
 (added)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/SwfPanel.java
 Thu Apr 14 11:46:52 2016
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.web.room;
+
+import static org.apache.openmeetings.util.OpenmeetingsVariables.webAppRootKey;
+import static org.apache.openmeetings.web.app.Application.getBean;
+import static org.apache.openmeetings.web.app.WebSession.getLanguage;
+import static org.apache.openmeetings.web.app.WebSession.getSid;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.openmeetings.core.session.SessionManager;
+import org.apache.openmeetings.db.dao.room.InvitationDao;
+import org.apache.openmeetings.db.dao.room.RoomDao;
+import org.apache.openmeetings.db.dao.server.SOAPLoginDao;
+import org.apache.openmeetings.db.dao.server.ServerDao;
+import org.apache.openmeetings.db.dao.server.SessiondataDao;
+import org.apache.openmeetings.db.entity.server.SOAPLogin;
+import org.apache.openmeetings.db.entity.server.Server;
+import org.apache.openmeetings.web.app.Client;
+import org.apache.openmeetings.web.app.WebSession;
+import org.apache.openmeetings.web.common.BasePanel;
+import org.apache.wicket.RuntimeConfigurationType;
+import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.head.CssHeaderItem;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.PriorityHeaderItem;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.mapper.parameter.PageParametersEncoder;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.request.resource.ResourceReference;
+import org.apache.wicket.util.string.StringValue;
+import org.apache.wicket.util.time.Duration;
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+
+public class SwfPanel extends BasePanel {
+       private static final long serialVersionUID = 1L;
+       private static final String WICKET_ROOM_ID = "wicketroomid";
+       public static final String PARAM_PUBLIC_SID = "publicSid";
+       public static final String PARAM_URL = "url";
+       private static final Logger log = 
Red5LoggerFactory.getLogger(SwfPanel.class, webAppRootKey);
+       private Long roomId = null;
+       
+       public SwfPanel(String id) {
+               this(id, new PageParameters());
+       }
+       
+       public SwfPanel(String id, Client c) {
+               this(id, addServer(c.getRoomId(), true).add("uid", c.getUid()));
+       }
+       
+       public SwfPanel(String id, PageParameters pp) {
+               super(id);
+               //OK let's find the room
+               try {
+                       StringValue room = pp.get(WICKET_ROOM_ID);
+                       StringValue secureHash = pp.get(WebSession.SECURE_HASH);
+                       StringValue invitationHash = 
pp.get(WebSession.INVITATION_HASH);
+                       if (!room.isEmpty()) {
+                               roomId = room.toLongObject();
+                       } else if (!secureHash.isEmpty()) {
+                               if 
(WebSession.get().signIn(secureHash.toString(), false)) {
+                                       SOAPLogin soapLogin = 
getBean(SOAPLoginDao.class).get(secureHash.toString());
+                                       roomId = soapLogin.getRoomId();
+                                       pp = 
pp.mergeWith(SwfPanel.addServer(roomId, false));
+                               }
+                               //TODO access denied
+                       } else if (!invitationHash.isEmpty()) {
+                               roomId = 
getBean(InvitationDao.class).getInvitationByHashCode(invitationHash.toString(), 
true).getRoom().getId();
+                       }
+               } catch (Exception e) {
+                       //no-op
+               }
+               StringValue swfVal = pp.get("swf");
+               PageParameters spp = new PageParameters(pp);
+               if (roomId != null) {
+                       spp.mergeWith(new PageParameters().add(WICKET_ROOM_ID, 
roomId));
+               }
+               String swf = (swfVal.isEmpty() ? getFlashFile() : 
swfVal.toString())
+                               + new 
PageParametersEncoder().encodePageParameters(spp);
+               add(new Label("init", String.format("initSwf('%s');", 
swf)).setEscapeModelStrings(false));
+               add(new AbstractAjaxTimerBehavior(Duration.minutes(5)) {
+                       private static final long serialVersionUID = 1L;
+
+                       @Override
+                       protected void onTimer(AjaxRequestTarget target) {
+                               
getBean(SessiondataDao.class).checkSession(WebSession.getSid()); //keep SID 
alive
+                       }
+               });
+       }
+
+       private static ResourceReference newResourceReference() {
+               return new JavaScriptResourceReference(SwfPanel.class, 
"swf-functions.js");
+       }
+       
+       @Override
+       public void renderHead(IHeaderResponse response) {
+               super.renderHead(response);
+               response.render(new 
PriorityHeaderItem(JavaScriptHeaderItem.forReference(newResourceReference())));
+               response.render(new 
PriorityHeaderItem(JavaScriptHeaderItem.forUrl("js/history.js")));
+               response.render(new 
PriorityHeaderItem(JavaScriptHeaderItem.forUrl("js/openmeetings_functions.js")));
+               response.render(new 
PriorityHeaderItem(CssHeaderItem.forUrl("css/history.css")));
+               //FIXME TODO ugly HACK
+               if 
(WebSession.get().getClientInfo().getProperties().isBrowserMozillaFirefox()) {
+                       response.render(new 
PriorityHeaderItem(CssHeaderItem.forCSS(".ui-widget-overlay{opacity: 1 
!important;}", "ff-veil-hack")));
+               }
+       }
+
+       private String getFlashFile() {
+               return RuntimeConfigurationType.DEVELOPMENT == 
getApplication().getConfigurationType()
+                               ? "maindebug.swf11.swf" : "main.swf11.swf";
+       }
+       
+       private static PageParameters addServer(PageParameters pp, Server s) {
+               return pp.add("protocol", s.getProtocol()).add("host", 
s.getAddress()).add("port", s.getPort()).add("context", s.getWebapp());
+       }
+       
+       public static PageParameters addServer(Long roomId, boolean addBasic) {
+               PageParameters pp = new PageParameters();
+               if (addBasic) {
+                       pp.add("wicketsid", getSid()).add(WICKET_ROOM_ID, 
roomId).add("language", getLanguage());
+               }
+               List<Server> serverList = 
getBean(ServerDao.class).getActiveServers();
+
+               long minimum = -1;
+               Server result = null;
+               HashMap<Server, List<Long>> activeRoomsMap = new 
HashMap<Server, List<Long>>();
+               for (Server server : serverList) {
+                       List<Long> roomIds = 
getBean(SessionManager.class).getActiveRoomIdsByServer(server);
+                       if (roomIds.contains(roomId)) {
+                               // if the room is already opened on a server, 
redirect the user to that one,
+                               log.debug("Room is already opened on a server " 
+ server.getAddress());
+                               return addServer(pp, server);
+                       }
+                       activeRoomsMap.put(server, roomIds);
+               }
+               for (Map.Entry<Server, List<Long>> entry : 
activeRoomsMap.entrySet()) {
+                       List<Long> roomIds = entry.getValue();
+                       long capacity = 
getBean(RoomDao.class).getRoomsCapacityByIds(roomIds);
+                       if (minimum < 0 || capacity < minimum) {
+                               minimum = capacity;
+                               result = entry.getKey();
+                       }
+                       log.debug("Checking server: " + entry.getKey() + " 
Number of rooms " + roomIds.size() + " RoomIds: "
+                                       + roomIds + " max(Sum): " + capacity);
+               }
+               return result == null ? pp : addServer(pp, result);
+       }
+}

Added: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/ActivitiesPanel.html
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/ActivitiesPanel.html?rev=1739063&view=auto
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/ActivitiesPanel.html
 (added)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/ActivitiesPanel.html
 Thu Apr 14 11:46:52 2016
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+      http://www.apache.org/licenses/LICENSE-2.0
+         
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  
+-->
+<html xmlns:wicket="http://wicket.apache.org";>
+<wicket:panel>
+       <div class="ui-widget-header">
+               <div onclick="toggleActivities();" class="clickable control 
block ui-widget-header ui-state-active"><div class="ui-icon ui-icon-carat-1-n 
sort-icon"></div><div class="label"><wicket:message key="1363"/></div></div>
+       </div>
+       <div wicket:id="container" class="area ui-widget-content">
+               <div wicket:id="activities" class="activity item 
ui-helper-clearfix ui-corner-all">
+                       <span wicket:id="close" class="ui-icon ui-icon-close 
ui-corner-all align-right clickable" wicket:message="title:85"></span>
+                       <div wicket:id="text"></div>
+               </div>
+       </div>
+</wicket:panel>
+</html>

Added: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/ActivitiesPanel.java
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/ActivitiesPanel.java?rev=1739063&view=auto
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/ActivitiesPanel.java
 (added)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/ActivitiesPanel.java
 Thu Apr 14 11:46:52 2016
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.web.room.activities;
+
+import static org.apache.openmeetings.util.OpenmeetingsVariables.webAppRootKey;
+import static org.apache.openmeetings.web.app.Application.getBean;
+import static org.apache.openmeetings.web.app.WebSession.getUserId;
+import static org.apache.openmeetings.web.room.RoomPanel.isModerator;
+import static 
org.apache.openmeetings.web.util.CallbackFunctionHelper.getNamedFunction;
+import static org.apache.wicket.ajax.attributes.CallbackParameter.explicit;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.openmeetings.db.dao.user.UserDao;
+import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.web.common.BasePanel;
+import org.apache.openmeetings.web.room.activities.Activity.Type;
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.behavior.AttributeAppender;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.CssHeaderItem;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.PriorityHeaderItem;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+
+public class ActivitiesPanel extends BasePanel {
+       private static final long serialVersionUID = 1L;
+       private static final Logger log = 
Red5LoggerFactory.getLogger(ActivitiesPanel.class, webAppRootKey);
+       private static final String PARAM_UID = "uid";
+       private static final String ACTION = "action";
+       private static final String PARAM_ROOM_ID = "roomid";
+       private enum Action {
+               accept, decline, close
+       };
+       private static ThreadLocal<DateFormat> df = new 
ThreadLocal<DateFormat>() {
+               @Override
+               protected DateFormat initialValue() {
+                       return new SimpleDateFormat("HH:mm:ss");
+               };
+       };
+       private final Map<String, Activity> activities = new LinkedHashMap<>();
+       private final long roomId;
+       private final WebMarkupContainer container = new 
WebMarkupContainer("container");
+       private final AbstractDefaultAjaxBehavior action = new 
AbstractDefaultAjaxBehavior() {
+               private static final long serialVersionUID = 1L;
+
+               @Override
+               protected void respond(AjaxRequestTarget target) {
+                       try {
+                               String uid = 
getRequest().getRequestParameters().getParameterValue(PARAM_UID).toString(); 
+                               long roomId = 
getRequest().getRequestParameters().getParameterValue(PARAM_ROOM_ID).toLong();
+                               assert(ActivitiesPanel.this.roomId == roomId);
+                               Action action = 
Action.valueOf(getRequest().getRequestParameters().getParameterValue(ACTION).toString());
+                               Activity a = activities.get(uid);
+                               if (a != null) {
+                                       if (action == Action.close && 
(a.getType() == Type.roomEnter || a.getType() == Type.roomExit)) {
+                                               activities.remove(uid);
+                                               update(target);
+                                       } else if (isModerator(getUserId(), 
roomId)) {
+                                               switch (a.getType()) {
+                                                       case 
requestRightModerator:
+                                                               break;
+                                                       default:
+                                                               break;  
+                                               }
+                                       }
+                               } else {
+                                       log.error("It seems like we are being 
hacked!!!!");
+                               }
+                       } catch (Exception e) {
+                               log.error("Unexpected exception while 
processing activity action", e);
+                       }
+               }
+               
+               @Override
+               public void renderHead(Component component, IHeaderResponse 
response) {
+                       super.renderHead(component, response);
+                       response.render(new 
PriorityHeaderItem(JavaScriptHeaderItem.forScript(getNamedFunction("activityAction",
 this, explicit(PARAM_ROOM_ID), explicit(ACTION), explicit(PARAM_UID)), 
"activityAction")));
+               }
+       };
+       private ListView<Activity> lv = new ListView<Activity>("activities", 
new ArrayList<Activity>()) {
+               private static final long serialVersionUID = 1L;
+
+               @Override
+               protected void populateItem(ListItem<Activity> item) {
+                       Activity a = item.getModelObject();
+                       String text = "";
+                       switch (a.getType()) {
+                               case roomEnter:
+                                       text = ""; // TODO should this be fixed?
+                                       item.setVisible(false);
+                                       break;
+                               case roomExit:
+                               {
+                                       User u = 
getBean(UserDao.class).get(a.getSender());
+                                       text = String.format("%s %s %s [%s]", 
u.getFirstname(), u.getLastname(), getString("1367"), 
df.get().format(a.getCreated()));
+                               }
+                                       break;
+                               case requestRightModerator:
+                               {
+                                       User u = 
getBean(UserDao.class).get(a.getSender());
+                                       text = String.format("%s %s %s [%s]", 
u.getFirstname(), u.getLastname(), 
getString("room.action.request.right.moderator"), 
df.get().format(a.getCreated()));
+                                       //FIXME TODO actions
+                               }
+                               //ask question 693
+                                       break;
+                       }
+                       item.add(new WebMarkupContainer("close").add(new 
AttributeAppender("onclick", String.format("activityAction(%s, '%s', '%s');", 
roomId, Action.close.name(), a.getUid()))));
+                       item.add(new Label("text", text));
+                       item.add(AttributeAppender.append("class", 
getClass(a)));
+               }
+               
+               private String getClass(Activity a) {
+                       switch (a.getType()) {
+                               case requestRightModerator:
+                                       return "ui-state-highlight";
+                               case roomEnter:
+                               case roomExit:
+                       }
+                       return "ui-state-default";
+               }
+       };
+
+       public void addActivity(String uid, Long userId, Activity.Type type, 
IPartialPageRequestHandler handler) {
+               //if (getUserId() != userId) {//FIXME should be replaced with 
client-id
+                       activities.put(uid, new Activity(uid, userId,  type));
+                       update(handler);
+               //}
+       }
+
+       public void update(IPartialPageRequestHandler handler) {
+               lv.setList(new ArrayList<>(activities.values()));
+               handler.add(container);
+       }
+       
+       public ActivitiesPanel(String id, long roomId) {
+               super(id);
+               this.roomId = roomId;
+               setOutputMarkupPlaceholderTag(true);
+               setMarkupId(id);
+               add(container.add(lv).setOutputMarkupId(true));
+               add(action);
+       }
+       
+       @Override
+       public void renderHead(IHeaderResponse response) {
+               super.renderHead(response);
+               response.render(new 
PriorityHeaderItem(JavaScriptHeaderItem.forReference(new 
JavaScriptResourceReference(ActivitiesPanel.class, "activities.js"))));
+               response.render(CssHeaderItem.forUrl("css/activities.css"));
+       }
+}

Added: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/Activity.java
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/Activity.java?rev=1739063&view=auto
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/Activity.java
 (added)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/Activity.java
 Thu Apr 14 11:46:52 2016
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.web.room.activities;
+
+import java.io.Serializable;
+import java.util.Date;
+
+public class Activity implements Serializable {
+       private static final long serialVersionUID = 1L;
+       public enum Type {
+               roomEnter
+               , roomExit
+               , requestRightModerator
+       }
+       private final String uid;
+       private final Long sender;
+       private final Date created;
+       private final Type type;
+       
+       public Activity(String uid, Long sender, Type type) {
+               this.uid = uid;
+               this.sender = sender;
+               this.type = type;
+               this.created = new Date();
+       }
+
+       public String getUid() {
+               return uid;
+       }
+
+       public Long getSender() {
+               return sender;
+       }
+
+       public Type getType() {
+               return type;
+       }
+
+       public Date getCreated() {
+               return created;
+       }
+}

Added: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/activities.js
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/activities.js?rev=1739063&view=auto
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/activities.js
 (added)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/activities.js
 Thu Apr 14 11:46:52 2016
@@ -0,0 +1,40 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+var closedHeight = "20px", openedHeight = "345px";
+function openActivities() {
+       var activities = $('#activitiesPanel');
+       if (activities.height() < 24) {
+               $('.control.block .ui-icon', 
activities).removeClass('ui-icon-carat-1-n').addClass('ui-icon-carat-1-s');
+               activities.animate({height: openedHeight}, 1000);
+       }
+}
+function closeActivities() {
+       var activities = $('#activitiesPanel');
+       if (activities.height() > 24) {
+               $('.control.block .ui-icon', 
activities).removeClass('ui-icon-carat-1-s').addClass('ui-icon-carat-1-n');
+               activities.animate({height: closedHeight}, 1000);
+       }
+}
+function toggleActivities() {
+       if ($('#activitiesPanel').height() < 24) {
+               openActivities();
+       } else {
+               closeActivities();
+       }
+}

Copied: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/InvitationDialog.java
 (from r1739057, 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/InvitationDialog.java)
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/InvitationDialog.java?p2=openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/InvitationDialog.java&p1=openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/InvitationDialog.java&r1=1739057&r2=1739063&rev=1739063&view=diff
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/InvitationDialog.java
 (original)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/InvitationDialog.java
 Thu Apr 14 11:46:52 2016
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.openmeetings.web.room;
+package org.apache.openmeetings.web.room.menu;
 
 import static org.apache.openmeetings.util.OpenmeetingsVariables.webAppRootKey;
 import static org.apache.openmeetings.web.app.Application.getBean;

Added: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.html
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.html?rev=1739063&view=auto
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.html
 (added)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.html
 Thu Apr 14 11:46:52 2016
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+      http://www.apache.org/licenses/LICENSE-2.0
+         
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  
+-->
+<html xmlns:wicket="http://wicket.apache.org";>
+<wicket:panel>
+       <div wicket:id="roomMenu"></div>
+       <div class="room menu right">
+               <span wicket:id="ask" class="icon ask"></span>
+               <span wicket:id="share" class="icon share"></span>
+               <span wicket:id="recording" class="room recording"></span>
+               <span wicket:id="roomName" class="room name"></span>
+       </div>
+       <div wicket:id="invite"></div>
+       <div wicket:id="createPoll"></div>
+       <div wicket:id="vote"></div>
+       <div wicket:id="pollResults"></div>
+</wicket:panel>
+</html>

Added: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java?rev=1739063&view=auto
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
 (added)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
 Thu Apr 14 11:46:52 2016
@@ -0,0 +1,241 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.web.room.menu;
+
+import static 
org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_APPLICATION_BASE_URL;
+import static 
org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_REDIRECT_URL_FOR_EXTERNAL_KEY;
+import static org.apache.openmeetings.web.app.Application.getBean;
+import static org.apache.openmeetings.web.app.Application.removeUserFromRoom;
+import static org.apache.openmeetings.web.app.WebSession.getUserId;
+import static org.apache.openmeetings.web.util.OmUrlFragment.ROOMS_PUBLIC;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
+import org.apache.openmeetings.db.dao.room.PollDao;
+import org.apache.openmeetings.db.dao.user.UserDao;
+import org.apache.openmeetings.db.entity.room.Room;
+import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.db.entity.user.User.Right;
+import org.apache.openmeetings.web.app.Application;
+import org.apache.openmeetings.web.app.Client;
+import org.apache.openmeetings.web.app.WebSession;
+import org.apache.openmeetings.web.common.OmButton;
+import org.apache.openmeetings.web.common.menu.MenuPanel;
+import org.apache.openmeetings.web.common.menu.RoomMenuItem;
+import org.apache.openmeetings.web.room.RoomPanel;
+import org.apache.openmeetings.web.room.message.RoomMessage;
+import org.apache.openmeetings.web.room.poll.CreatePollDialog;
+import org.apache.openmeetings.web.room.poll.PollResultsDialog;
+import org.apache.openmeetings.web.room.poll.VoteDialog;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.behavior.AttributeAppender;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.request.flow.RedirectToUrlException;
+import org.apache.wicket.util.string.Strings;
+
+import com.googlecode.wicket.jquery.ui.widget.menu.IMenuItem;
+
+public class RoomMenuPanel extends Panel {
+       private static final long serialVersionUID = 1L;
+       private final InvitationDialog invite;
+       private final CreatePollDialog createPoll;
+       private final VoteDialog vote;
+       private final PollResultsDialog pollResults;
+       private final MenuPanel menuPanel;
+       private final StartSharingButton shareBtn;
+       private final OmButton askBtn = new OmButton("ask") {
+               private static final long serialVersionUID = 1L;
+               {
+                       setOutputMarkupPlaceholderTag(true);
+                       setVisible(false);
+               }
+               @Override
+               protected void onClick(AjaxRequestTarget target) {
+                       RoomPanel.broadcast(new 
RoomMessage(room.getRoom().getId(), RoomMessage.Type.requestRightModerator));
+               }
+       };
+       private final RoomPanel room;
+       private final RoomMenuItem exitMenuItem = new 
RoomMenuItem(Application.getString(308), Application.getString(309), "room menu 
exit") {
+               private static final long serialVersionUID = 1L;
+
+               @Override
+               public void onClick(AjaxRequestTarget target) {
+                       exit(target);
+               }
+       };
+       private final RoomMenuItem filesMenu = new 
RoomMenuItem(Application.getString(245), null, false);
+       private final RoomMenuItem actionsMenu = new 
RoomMenuItem(Application.getString(635), null, false);
+       private final RoomMenuItem inviteMenuItem = new 
RoomMenuItem(Application.getString(213), Application.getString(1489), false) {
+               private static final long serialVersionUID = 1L;
+
+               @Override
+               public void onClick(AjaxRequestTarget target) {
+                       invite.updateModel(target);
+                       invite.open(target);
+               }
+       };
+       private final RoomMenuItem shareMenuItem = new 
RoomMenuItem(Application.getString(239), Application.getString(1480), false) {
+               private static final long serialVersionUID = 1L;
+
+               @Override
+               public void onClick(AjaxRequestTarget target) {
+                       shareBtn.onClick(target);
+               }
+       };
+       private final RoomMenuItem applyModerMenuItem = new 
RoomMenuItem(Application.getString(784), Application.getString(1481), false);
+       private final RoomMenuItem applyWbMenuItem = new 
RoomMenuItem(Application.getString(785), Application.getString(1492), false);
+       private final RoomMenuItem applyAvMenuItem = new 
RoomMenuItem(Application.getString(786), Application.getString(1482), false);
+       private final RoomMenuItem pollCreateMenuItem = new 
RoomMenuItem(Application.getString(24), Application.getString(1483), false) {
+               private static final long serialVersionUID = 1L;
+
+               @Override
+               public void onClick(AjaxRequestTarget target) {
+                       createPoll.updateModel(target, null); //TODO FIXME
+                       createPoll.open(target);
+               }
+       };
+       private final RoomMenuItem pollVoteMenuItem = new 
RoomMenuItem(Application.getString(42), Application.getString(1485), false) {
+               private static final long serialVersionUID = 1L;
+
+               @Override
+               public void onClick(AjaxRequestTarget target) {
+                       vote.updateModel(target);
+                       vote.open(target);
+               }
+       };
+       private final RoomMenuItem pollResultMenuItem = new 
RoomMenuItem(Application.getString(37), Application.getString(1484), false) {
+               private static final long serialVersionUID = 1L;
+
+               @Override
+               public void onClick(AjaxRequestTarget target) {
+                       pollResults.updateModel(target, 
room.getClient().hasRight(Client.Right.moderator));
+                       pollResults.open(target);
+               }
+       };
+       private final RoomMenuItem sipDialerMenuItem = new 
RoomMenuItem(Application.getString(1447), Application.getString(1488), false);
+
+       public RoomMenuPanel(String id, final RoomPanel room) {
+               super(id);
+               this.room = room;
+               Room r = room.getRoom();
+               add((menuPanel = new MenuPanel("roomMenu", 
getMenu())).setVisible(!r.getHideTopBar()));
+               add(askBtn);
+               add(new Label("roomName", r.getName()));
+               add(new Label("recording", "Recording 
started").setVisible(false)); //FIXME add/remove
+               add(shareBtn = new StartSharingButton("share", 
room.getClient()));
+               add(invite = new InvitationDialog("invite", 
room.getRoom().getId()));
+               add(createPoll = new CreatePollDialog("createPoll", 
room.getRoom().getId()));
+               add(vote = new VoteDialog("vote", room.getRoom().getId()));
+               add(pollResults = new PollResultsDialog("pollResults", 
room.getRoom().getId()));
+       }
+       
+       @Override
+       protected void onInitialize() {
+               super.onInitialize();
+               askBtn.add(new AttributeAppender("title", getString("906")));
+       }
+       
+       private List<IMenuItem> getMenu() {
+               List<IMenuItem> menu = new ArrayList<>();
+               exitMenuItem.setEnabled(false);
+               exitMenuItem.setTop(true);
+               menu.add(exitMenuItem);
+               
+               filesMenu.getItems().add(new 
RoomMenuItem(Application.getString(15), Application.getString(1479)));
+               filesMenu.setTop(true);
+               menu.add(filesMenu);
+               
+               actionsMenu.setTop(true);
+               actionsMenu.getItems().add(inviteMenuItem);
+               actionsMenu.getItems().add(shareMenuItem); //FIXME 
enable/disable
+               actionsMenu.getItems().add(applyModerMenuItem); //FIXME 
enable/disable
+               actionsMenu.getItems().add(applyWbMenuItem); //FIXME 
enable/disable
+               actionsMenu.getItems().add(applyAvMenuItem); //FIXME 
enable/disable
+               actionsMenu.getItems().add(pollCreateMenuItem);
+               actionsMenu.getItems().add(pollResultMenuItem); //FIXME 
enable/disable
+               actionsMenu.getItems().add(pollVoteMenuItem); //FIXME 
enable/disable
+               actionsMenu.getItems().add(sipDialerMenuItem);
+               actionsMenu.getItems().add(new 
RoomMenuItem(Application.getString(1126), Application.getString(1490)));
+               menu.add(actionsMenu);
+               return menu;
+       }
+       
+       public void update(IPartialPageRequestHandler handler) {
+               boolean pollExists = 
getBean(PollDao.class).hasPoll(room.getRoom().getId());
+               User u = getBean(UserDao.class).get(getUserId());
+               boolean notExternalUser = u.getType() != User.Type.external && 
u.getType() != User.Type.contact;
+               exitMenuItem.setEnabled(notExternalUser);//TODO check this
+               filesMenu.setEnabled(room.getSidebar().isShowFiles());
+               actionsMenu.setEnabled(!room.getRoom().getHideActionsMenu());
+               boolean moder = 
room.getClient().hasRight(Client.Right.moderator);
+               inviteMenuItem.setEnabled(notExternalUser && moder);
+               //TODO add check "sharing started"
+               Room r = room.getRoom();
+               boolean shareVisible = Room.Type.interview != r.getType() && 
!r.getHideScreenSharing() && moder;
+               shareMenuItem.setEnabled(shareVisible);
+               shareBtn.setVisible(shareMenuItem.isEnabled());
+               //FIXME TODO apply* should be enabled if moder is in room
+               applyModerMenuItem.setEnabled(!moder);
+               applyWbMenuItem.setEnabled(!moder);
+               applyAvMenuItem.setEnabled(!moder);
+               pollCreateMenuItem.setEnabled(moder);
+               pollVoteMenuItem.setEnabled(pollExists && notExternalUser && 
!getBean(PollDao.class).hasVoted(r.getId(), getUserId()));
+               pollResultMenuItem.setEnabled(pollExists || 
getBean(PollDao.class).getArchived(r.getId()).size() > 0);
+               //TODO sip menus
+               menuPanel.update(handler);
+               //FIXME TODO add ask question button
+               //FIXME TODO askBtn should be visible if moder is in room
+               handler.add(askBtn.setVisible(!moder), 
shareBtn.setVisible(shareVisible));
+       }
+
+       public void pollCreated(IPartialPageRequestHandler handler) {
+               vote.updateModel(handler);
+               vote.open(handler);
+       }
+       
+       public void exit(IPartialPageRequestHandler handler) {
+               if (WebSession.getRights().contains(Right.Dashboard)) {
+                       room.getMainPage().updateContents(ROOMS_PUBLIC, 
handler);
+                       roomExit(room, false);
+               } else {
+                       String url = 
getBean(ConfigurationDao.class).getConfValue(CONFIG_REDIRECT_URL_FOR_EXTERNAL_KEY,
 String.class, "");
+                       if (Strings.isEmpty(url)) {
+                               url = 
getBean(ConfigurationDao.class).getConfValue(CONFIG_APPLICATION_BASE_URL, 
String.class, "");
+                       }
+                       throw new RedirectToUrlException(url);
+               }
+       }
+
+       public static void roomExit(RoomPanel room) {
+               roomExit(room, true);
+       }
+       
+       public static void roomExit(RoomPanel room, boolean broadcast) {
+               Client c = room.getClient();
+               removeUserFromRoom(c);
+               if (broadcast) {
+                       RoomMessage m = new RoomMessage(c.getRoomId(), 
c.getUserId(), RoomMessage.Type.roomExit);
+                       RoomPanel.broadcast(m);
+               }
+       }
+}

Copied: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/StartSharingButton.java
 (from r1739057, 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/StartSharingEventBehavior.java)
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/StartSharingButton.java?p2=openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/StartSharingButton.java&p1=openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/StartSharingEventBehavior.java&r1=1739057&r2=1739063&rev=1739063&view=diff
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/StartSharingEventBehavior.java
 (original)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/StartSharingButton.java
 Thu Apr 14 11:46:52 2016
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.openmeetings.web.room;
+package org.apache.openmeetings.web.room.menu;
 
 import static 
org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SCREENSHARING_ALLOW_REMOTE;
 import static 
org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SCREENSHARING_FPS;
@@ -26,9 +26,6 @@ import static org.apache.openmeetings.ut
 import static org.apache.openmeetings.web.app.Application.getBean;
 import static org.apache.openmeetings.web.app.WebSession.getLanguage;
 import static org.apache.openmeetings.web.room.RoomBroadcaster.getClient;
-import static org.apache.openmeetings.web.room.RoomPanel.PARAM_PUBLIC_SID;
-import static org.apache.openmeetings.web.room.RoomPanel.PARAM_URL;
-import static org.apache.openmeetings.web.util.CallbackFunctionHelper.getParam;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -46,21 +43,23 @@ import org.apache.openmeetings.db.dao.ro
 import org.apache.openmeetings.db.entity.room.Client;
 import org.apache.openmeetings.db.entity.room.Room;
 import org.apache.openmeetings.util.OmFileHelper;
+import org.apache.openmeetings.web.app.Application;
+import org.apache.openmeetings.web.common.OmButton;
 import org.apache.openmeetings.web.util.AjaxDownload;
-import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
 import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.behavior.AttributeAppender;
 import org.apache.wicket.util.resource.StringResourceStream;
 import org.apache.wicket.util.string.Strings;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
 
-public class StartSharingEventBehavior extends AbstractDefaultAjaxBehavior {
+public class StartSharingButton extends OmButton {
        private static final long serialVersionUID = 1L;
-       private static final Logger log = 
Red5LoggerFactory.getLogger(StartSharingEventBehavior.class, webAppRootKey);
+       private static final Logger log = 
Red5LoggerFactory.getLogger(StartSharingButton.class, webAppRootKey);
        private static final String CDATA_BEGIN = "<![CDATA[";
        private static final String CDATA_END = "]]>";
        private final AjaxDownload download;
-       private final Long roomId;
+       private final org.apache.openmeetings.web.app.Client c;
        private enum Protocol {
                rtmp
                , rtmpe
@@ -68,41 +67,40 @@ public class StartSharingEventBehavior e
                , rtmpt
        }
 
-       public StartSharingEventBehavior(Long _roomId) {
-               this.roomId = _roomId;
-               download = new AjaxDownload(true) {
+       public StartSharingButton(String id, 
org.apache.openmeetings.web.app.Client c) {
+               super(id);
+               this.c = c;
+               setOutputMarkupPlaceholderTag(true);
+               setVisible(false);
+               add(new AttributeAppender("title", 
Application.getString(1480)));
+               add(download = new AjaxDownload(true) {
                        private static final long serialVersionUID = 1L;
 
                        @Override
                        protected String getFileName() {
-                               return "public_" + roomId + ".jnlp";
+                               return String.format("public_%s.jnlp", 
StartSharingButton.this.c.getRoomId());
                        }
-               };
+               });
        }
        
        @Override
-       protected void onBind() {
-               super.onBind();
-               getComponent().add(download);
-       }
-       
-       @Override
-       protected void respond(AjaxRequestTarget target) {
+       protected void onClick(AjaxRequestTarget target) {
                //TODO deny download in case other screen sharing is in progress
                String app = "";
                try (InputStream jnlp = 
getClass().getClassLoader().getResourceAsStream("APPLICATION.jnlp")) {
                        ConfigurationDao cfgDao = 
getBean(ConfigurationDao.class);
                        app = IOUtils.toString(jnlp, StandardCharsets.UTF_8);
                        String baseUrl = cfgDao.getBaseUrl();
-                       String _url = getParam(getComponent(), 
PARAM_URL).toString();
-                       URI url = new URI(_url);
-                       Room room = getBean(RoomDao.class).get(roomId);
-                       String publicSid = getParam(getComponent(), 
PARAM_PUBLIC_SID).toString();
-                       SessionManager sessionManager = 
getBean(SessionManager.class);
+                       String publicSid = c.getUid();
                        Client rc = getClient(publicSid);
                        if (rc == null) {
                                throw new 
RuntimeException(String.format("Unable to find client by publicSID '%s'", 
publicSid));
                        }
+                       String _url = rc.getTcUrl();
+                       URI url = new URI(_url);
+                       long roomId = c.getRoomId();
+                       Room room = getBean(RoomDao.class).get(roomId);
+                       SessionManager sessionManager = 
getBean(SessionManager.class);
                        String path = url.getPath();
                        path = path.substring(path.lastIndexOf('/') + 1);
                        if (Strings.isEmpty(path) || rc.getRoomId() == null || 
!path.equals(rc.getRoomId().toString()) || !rc.getRoomId().equals(roomId)) {

Added: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/message/RoomMessage.java
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/message/RoomMessage.java?rev=1739063&view=auto
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/message/RoomMessage.java
 (added)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/message/RoomMessage.java
 Thu Apr 14 11:46:52 2016
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.web.room.message;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.UUID;
+
+import org.apache.openmeetings.web.app.WebSession;
+import org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;
+
+public class RoomMessage implements IWebSocketPushMessage, Serializable {
+       private static final long serialVersionUID = 1L;
+       public enum Type {
+               roomEnter
+               , roomExit
+               , pollCreated
+               , pollClosed
+               , pollDeleted
+               , voted
+               , rightUpdated
+               , requestRightModerator
+       }
+       private final Date timestamp;
+       private final String uid;
+       private final Long roomId;
+       private final Long userId;
+       private final Type type;
+
+       public RoomMessage(Long roomId, Type type) {
+               this(roomId, WebSession.getUserId(), type);
+       }
+       
+       public RoomMessage(Long roomId, Long userId, Type type) {
+               this.timestamp = new Date();
+               this.roomId = roomId;
+               this.userId = userId;
+               this.type = type;
+               this.uid = UUID.randomUUID().toString();
+       }
+       
+       public Date getTimestamp() {
+               return timestamp;
+       }
+
+       public Long getRoomId() {
+               return roomId;
+       }
+
+       public Long getUserId() {
+               return userId;
+       }
+
+       public Type getType() {
+               return type;
+       }
+
+       public String getUid() {
+               return uid;
+       }
+}

Added: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/room.js
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/room.js?rev=1739063&view=auto
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/room.js
 (added)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/room.js
 Thu Apr 14 11:46:52 2016
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+function setHeight() {
+       var h = $(window).height() - $('#roomMenu').height();
+       $(".room.sidebar.left").height(h);
+       var p = $(".room.sidebar.left .tabs");
+       p.height(h - 5); //FIXME hacks
+       $(".user.list", p).height(h - $("ul", p).height() - 15); //FIXME hacks
+       $(".room.wb.area").height(h);
+       $(".room.wb.area .wb").height(h);
+}
+
+$(document).ready(function() {
+       $(window).on('resize.openmeetings', function() {
+               roomWidth = $(window).width();
+               setHeight();
+       });
+});
+
+var roomWidth = $(window).width();
+function roomLoad() {
+       $(".room.sidebar.left").resizable({
+               handles: "e"
+               , stop: function(event, ui) {
+                       //TODO not really works, need to be investigated
+                       var w = roomWidth - $(this).width() - 5;
+                       $(".room.wb.area").width(w);
+                       $(".room.wb.area .wb").width(w);
+               }
+       });
+       setHeight();
+}
+function startPrivateChat(el) {
+       addChatTab('chatTab-u' + el.parent().parent().data("userid"), 
el.parent().parent().find('.user.name').text());
+       openChat();
+       $('#chatMessage .wysiwyg-editor').click();
+}

Added: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomFilePanel.java
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomFilePanel.java?rev=1739063&view=auto
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomFilePanel.java
 (added)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomFilePanel.java
 Thu Apr 14 11:46:52 2016
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.web.room.sidebar;
+
+import static org.apache.openmeetings.web.app.Application.getBean;
+import static org.apache.openmeetings.web.app.WebSession.getUserId;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.openmeetings.db.dao.file.FileExplorerItemDao;
+import org.apache.openmeetings.db.dao.user.UserDao;
+import org.apache.openmeetings.db.entity.file.FileExplorerItem;
+import org.apache.openmeetings.db.entity.file.FileItem;
+import org.apache.openmeetings.db.entity.file.FileItem.Type;
+import org.apache.openmeetings.db.entity.record.Recording;
+import org.apache.openmeetings.db.entity.user.Group;
+import org.apache.openmeetings.db.entity.user.GroupUser;
+import org.apache.openmeetings.web.app.Application;
+import org.apache.openmeetings.web.common.tree.FileItemTree;
+import org.apache.openmeetings.web.common.tree.FileTreePanel;
+import org.apache.openmeetings.web.common.tree.MyRecordingTreeProvider;
+import org.apache.openmeetings.web.common.tree.PublicRecordingTreeProvider;
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.markup.html.repeater.tree.ITreeProvider;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+
+public class RoomFilePanel extends FileTreePanel {
+       private static final long serialVersionUID = 1L;
+       private final long roomId;
+
+       public RoomFilePanel(String id, final long roomId) {
+               super(id);
+               this.roomId = roomId;
+       }
+       
+       @Override
+       public void updateSizes() {
+               // TODO Auto-generated method stub
+               
+       }
+       
+       @Override
+       public void update(AjaxRequestTarget target, FileItem f) {
+               // TODO Auto-generated method stub
+               
+       }
+       
+       @Override
+       protected Component getUpload(String id) {
+               Component u = super.getUpload(id);
+               u.setVisible(true);
+               return u;
+       }
+       
+       @Override
+       public void defineTrees() {
+               FileExplorerItem f = new FileExplorerItem();
+               f.setOwnerId(getUserId());
+               selectedFile.setObject(f);
+               treesView.add(selected = new 
FileItemTree<FileExplorerItem>(treesView.newChildId(), this, new 
FilesTreeProvider(null)));
+               treesView.add(new 
FileItemTree<FileExplorerItem>(treesView.newChildId(), this, new 
FilesTreeProvider(roomId)));
+               treesView.add(new 
FileItemTree<Recording>(treesView.newChildId(), this, new 
MyRecordingTreeProvider()));
+               treesView.add(new 
FileItemTree<Recording>(treesView.newChildId(), this, new 
PublicRecordingTreeProvider(null, null)));
+               for (GroupUser ou : 
getBean(UserDao.class).get(getUserId()).getGroupUsers()) {
+                       Group o = ou.getGroup();
+                       treesView.add(new 
FileItemTree<Recording>(treesView.newChildId(), this, new 
PublicRecordingTreeProvider(o.getId(), o.getName())));
+               }
+       }
+       
+       @Override
+       public void createFolder(String name) {
+               if (selectedFile.getObject() instanceof Recording) {
+                       createRecordingFolder(name);
+               } else {
+                       FileExplorerItem f = new FileExplorerItem();
+                       f.setName(name);
+                       f.setInsertedBy(getUserId());
+                       f.setInserted(new Date());
+                       f.setType(Type.Folder);;
+                       FileItem p = selectedFile.getObject();
+                       long parentId = p.getId();
+                       f.setParentId(Type.Folder == p.getType() && parentId > 
0 ? parentId : null);
+                       f.setOwnerId(p.getOwnerId());
+                       f.setRoomId(p.getRoomId());
+                       getBean(FileExplorerItemDao.class).update(f);
+               }
+       }
+
+       static class FilesTreeProvider implements 
ITreeProvider<FileExplorerItem> {
+               private static final long serialVersionUID = 1L;
+               Long roomId = null;
+
+               FilesTreeProvider(Long roomId) {
+                       this.roomId = roomId;
+               }
+               
+               @Override
+               public void detach() {
+                       // TODO LDM should be used
+               }
+
+               @Override
+               public boolean hasChildren(FileExplorerItem node) {
+                       return node.getId() <= 0 || Type.Folder == 
node.getType();
+               }
+
+               @Override
+               public Iterator<? extends FileExplorerItem> 
getChildren(FileExplorerItem node) {
+                       FileExplorerItemDao dao = 
getBean(FileExplorerItemDao.class);
+                       List<FileExplorerItem> list = null;
+                       if (node.getId() == 0) {
+                               list = dao.getByOwner(node.getOwnerId());
+                       } else if (node.getId() < 0) {
+                               list = dao.getByRoom(roomId);
+                       } else {
+                               list = dao.getByParent(node.getId());
+                       }
+                       return list.iterator();
+               }
+
+               @Override
+               public IModel<FileExplorerItem> model(FileExplorerItem object) {
+                       // TODO LDM should be used
+                       return Model.of(object);
+               }
+
+               @Override
+               public Iterator<? extends FileExplorerItem> getRoots() {
+                       FileExplorerItem f = new FileExplorerItem();
+                       f.setRoomId(roomId);
+                       f.setType(Type.Folder);
+                       if (roomId == null) {
+                               f.setId(0L);
+                               f.setOwnerId(getUserId());
+                               f.setName(Application.getString(706));
+                       } else {
+                               f.setId(-roomId);
+                               f.setName(Application.getString(707));
+                       }
+                       return Arrays.asList(f).iterator();
+               }
+       }
+}

Added: 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.html
URL: 
http://svn.apache.org/viewvc/openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.html?rev=1739063&view=auto
==============================================================================
--- 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.html
 (added)
+++ 
openmeetings/application/branches/3.2.x/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.html
 Thu Apr 14 11:46:52 2016
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+      http://www.apache.org/licenses/LICENSE-2.0
+         
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  
+-->
+<html xmlns:wicket="http://wicket.apache.org";>
+<wicket:panel>
+       <div class="tabs" wicket:id="tabs"></div>
+       
+       <wicket:fragment wicket:id="user-panel">
+               <div class="user list">
+                       <div wicket:id="user" class="user ui-corner-all 
ui-widget-content">
+                               <div wicket:id="name" class="user name"></div>
+                               <div class="user actions">
+                                       <span wicket:id="privateChat" 
class="private-chat om-icon align-right clickable" wicket:message="title:1493" 
onclick="startPrivateChat($(this));"></span>
+                                       <div class="clear"></div>
+                               </div>
+                       </div>
+               </div>
+       </wicket:fragment>
+       
+       <wicket:fragment wicket:id="file-panel">
+               <div class="file list" wicket:id="tree"></div>
+       </wicket:fragment>
+</wicket:panel>
+</html>


Reply via email to