| /* |
| * 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.user.record; |
| |
| import static org.apache.openmeetings.util.OmFileHelper.MP4_EXTENSION; |
| import static org.apache.openmeetings.util.OmFileHelper.getHumanSize; |
| import static org.apache.openmeetings.util.OmFileHelper.isRecordingExists; |
| 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 org.apache.openmeetings.db.dao.record.FlvRecordingDao; |
| import org.apache.openmeetings.db.dao.user.UserDao; |
| import org.apache.openmeetings.db.dto.record.RecordingContainerData; |
| import org.apache.openmeetings.db.entity.record.FlvRecording; |
| import org.apache.openmeetings.db.entity.record.FlvRecording.Status; |
| import org.apache.openmeetings.db.entity.user.Organisation; |
| import org.apache.openmeetings.db.entity.user.Organisation_Users; |
| import org.apache.openmeetings.web.app.Application; |
| import org.apache.openmeetings.web.common.AddFolderDialog; |
| import org.apache.openmeetings.web.common.ConfirmableAjaxBorder; |
| import org.apache.openmeetings.web.common.UserPanel; |
| import org.apache.wicket.Component; |
| import org.apache.wicket.ajax.AjaxEventBehavior; |
| import org.apache.wicket.ajax.AjaxRequestTarget; |
| import org.apache.wicket.ajax.AjaxSelfUpdatingTimerBehavior; |
| import org.apache.wicket.extensions.markup.html.repeater.tree.DefaultNestedTree; |
| import org.apache.wicket.extensions.markup.html.repeater.tree.ITreeProvider; |
| import org.apache.wicket.extensions.markup.html.repeater.tree.content.Folder; |
| import org.apache.wicket.markup.html.WebMarkupContainer; |
| import org.apache.wicket.markup.html.basic.Label; |
| import org.apache.wicket.markup.html.form.Form; |
| import org.apache.wicket.markup.repeater.RepeatingView; |
| import org.apache.wicket.markup.repeater.ReuseIfModelsEqualStrategy; |
| import org.apache.wicket.model.CompoundPropertyModel; |
| import org.apache.wicket.model.IModel; |
| import org.apache.wicket.model.Model; |
| import org.apache.wicket.util.time.Duration; |
| |
| import com.googlecode.wicket.jquery.core.JQueryBehavior; |
| import com.googlecode.wicket.jquery.core.Options; |
| import com.googlecode.wicket.jquery.ui.interaction.droppable.Droppable; |
| |
| public class RecordingsPanel extends UserPanel { |
| private static final long serialVersionUID = 1321258690447136958L; |
| final WebMarkupContainer trees = new WebMarkupContainer("tree-container"); |
| private final WebMarkupContainer sizes = new WebMarkupContainer("sizes"); |
| private final VideoPlayer video = new VideoPlayer("video"); |
| private final VideoInfo info = new VideoInfo("info"); |
| private final IModel<FlvRecording> rm = new CompoundPropertyModel<FlvRecording>(new FlvRecording()); |
| private final IModel<String> homeSize = Model.of((String)null); |
| private final IModel<String> publicSize = Model.of((String)null); |
| final RecordingErrorsDialog errorsDialog = new RecordingErrorsDialog("errors", Model.of((FlvRecording)null)); |
| private RecordingTree selected; |
| |
| public RecordingsPanel(String id) { |
| super(id); |
| rm.getObject().setFlvRecordingId(Long.MIN_VALUE); |
| final AddFolderDialog addFolder = new AddFolderDialog("addFolder", Application.getString(712)) { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| protected void onSubmit(AjaxRequestTarget target) { |
| FlvRecording f = new FlvRecording(); |
| f.setFileName(getModelObject()); |
| f.setInsertedBy(getUserId()); |
| f.setInserted(new Date()); |
| f.setFolder(true); |
| f.setIsImage(false); |
| f.setIsPresentation(false); |
| f.setIsRecording(true); |
| FlvRecording p = rm.getObject(); |
| long parentId = p.getFlvRecordingId(); |
| if (p.isFolder()) { |
| f.setParentFileExplorerItemId(parentId); |
| } |
| f.setOwnerId(p.getOwnerId()); |
| f.setOrganization_id(p.getOrganization_id()); |
| getBean(FlvRecordingDao.class).update(f); |
| target.add(trees); //FIXME add correct refresh |
| } |
| }; |
| add(addFolder); |
| Droppable<FlvRecording> trashToolbar = new Droppable<FlvRecording>("trash-toolbar") { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| public void onConfigure(JQueryBehavior behavior) { |
| super.onConfigure(behavior); |
| behavior.setOption("hoverClass", Options.asString("ui-state-hover trash-toolbar-hover")); |
| behavior.setOption("accept", Options.asString(".recorditem, .fileitem")); |
| } |
| |
| @Override |
| public void onDrop(AjaxRequestTarget target, Component component) { |
| Object o = component.getDefaultModelObject(); |
| if (o instanceof FlvRecording) { |
| delete((FlvRecording)o, target); |
| } |
| } |
| }; |
| add(trashToolbar); |
| trashToolbar.add(new WebMarkupContainer("create").add(new AjaxEventBehavior("click") { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| protected void onEvent(AjaxRequestTarget target) { |
| addFolder.open(target); |
| } |
| })); |
| trashToolbar.add(new WebMarkupContainer("refresh").add(new AjaxEventBehavior("click") { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| protected void onEvent(AjaxRequestTarget target) { |
| target.add(trees); //FIXME add correct refresh |
| } |
| })); |
| trashToolbar.add(new ConfirmableAjaxBorder("trash", getString("80"), getString("713")) { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| protected void onSubmit(AjaxRequestTarget target, Form<?> form) { |
| delete(rm.getObject(), target); |
| } |
| }); |
| RepeatingView treesView = new RepeatingView("tree"); |
| treesView.add(selected = new RecordingTree(treesView.newChildId(), new MyRecordingTreeProvider())); |
| treesView.add(new RecordingTree(treesView.newChildId(), new PublicRecordingTreeProvider(null, null))); |
| for (Organisation_Users ou : getBean(UserDao.class).get(getUserId()).getOrganisation_users()) { |
| Organisation o = ou.getOrganisation(); |
| treesView.add(new RecordingTree(treesView.newChildId(), new PublicRecordingTreeProvider(o.getOrganisation_id(), o.getName()))); |
| } |
| add(trees.add(treesView).setOutputMarkupId(true)); |
| updateSizes(); |
| add(sizes.add(new Label("homeSize", homeSize), new Label("publicSize", publicSize)).setOutputMarkupId(true)); |
| sizes.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(30)) { |
| private static final long serialVersionUID = 1L; |
| |
| protected void onPostProcessTarget(AjaxRequestTarget target) { |
| updateSizes(); |
| } |
| }); |
| add(video, info, errorsDialog); |
| } |
| |
| void delete(FlvRecording f, AjaxRequestTarget target) { |
| long id = f.getFlvRecordingId(); |
| if (id > 0) { |
| getBean(FlvRecordingDao.class).delete(f); |
| } |
| target.add(trees); //FIXME add correct refresh |
| } |
| |
| private void updateSizes() { |
| RecordingContainerData sizeData = getBean(FlvRecordingDao.class).getRecordingContainerData(getUserId()); |
| if (sizeData != null) { |
| homeSize.setObject(getHumanSize(sizeData.getUserHomeSize())); |
| publicSize.setObject(getHumanSize(sizeData.getPublicFileSize())); |
| } |
| } |
| |
| //FIXME need to be generalized to use as Room files explorer |
| class RecordingTree extends DefaultNestedTree<FlvRecording> { |
| private static final long serialVersionUID = 2527395034256868022L; |
| |
| public RecordingTree(String id, ITreeProvider<FlvRecording> tp) { |
| super(id, tp); |
| setItemReuseStrategy(new ReuseIfModelsEqualStrategy()); |
| } |
| |
| @Override |
| protected Component newContentComponent(String id, IModel<FlvRecording> node) { |
| return new Folder<FlvRecording>(id, this, node) { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| protected Component newLabelComponent(String id, final IModel<FlvRecording> lm) { |
| FlvRecording r = lm.getObject(); |
| return r.isFolder() || r.getFlvRecordingId() < 1 ? new RecordingPanel(id, lm, RecordingsPanel.this) : new RecordingItemPanel(id, lm, RecordingsPanel.this); |
| } |
| |
| @Override |
| protected boolean isSelected() { |
| return getModelObject().getFlvRecordingId() == rm.getObject().getFlvRecordingId(); |
| } |
| |
| @Override |
| protected boolean isClickable() { |
| return true; |
| } |
| |
| @Override |
| protected void onClick(AjaxRequestTarget target) { |
| FlvRecording r = getModelObject(); |
| FlvRecording _prev = rm.getObject(); |
| rm.setObject(r); |
| if (_prev != null) { |
| if (_prev.isFolder()) { |
| selected.updateBranch(_prev, target); |
| } else { |
| selected.updateNode(_prev, target); |
| } |
| } |
| selected = RecordingTree.this; |
| if (r.isFolder()) { |
| if (getState(r) == State.COLLAPSED) { |
| super.onClick(target); |
| } |
| updateBranch(r, target); |
| } else { |
| video.update(target, r); |
| info.update(target, r); |
| updateNode(r, target); |
| } |
| } |
| |
| private String getRecordingStyle(FlvRecording r, String def) { |
| String style; |
| if (r.getFlvRecordingId() == 0) { |
| style = "my-recordings om-icon"; |
| } else if (r.getFlvRecordingId() < 0) { |
| style = "public-recordings om-icon"; |
| } else if (r.isFolder()) { |
| style = def; |
| } else if (isRecordingExists(r.getFileHash() + MP4_EXTENSION)) { |
| style = "recording om-icon"; |
| } else if (Status.RECORDING == r.getStatus() || Status.CONVERTING == r.getStatus()) { |
| style = "processing-recording om-icon"; |
| } else { |
| style = "broken-recording om-icon"; |
| } |
| return style; |
| } |
| |
| @Override |
| protected String getOtherStyleClass(FlvRecording r) { |
| return getRecordingStyle(r, super.getOtherStyleClass(r)); |
| } |
| |
| @Override |
| protected String getOpenStyleClass() { |
| return getRecordingStyle(getModelObject(), super.getOpenStyleClass()); |
| } |
| |
| @Override |
| protected String getClosedStyleClass() { |
| return getRecordingStyle(getModelObject(), super.getClosedStyleClass()); |
| } |
| |
| @Override |
| protected String getSelectedStyleClass() { |
| return "ui-state-active"; |
| } |
| |
| @Override |
| protected IModel<String> newLabelModel(IModel<FlvRecording> model) { |
| return Model.of(model.getObject().getFileName()); |
| } |
| }; |
| } |
| } |
| |
| @Override |
| protected void onDetach() { |
| rm.detach(); |
| homeSize.detach(); |
| publicSize.detach(); |
| super.onDetach(); |
| } |
| |
| class MyRecordingTreeProvider extends RecordingTreeProvider { |
| private static final long serialVersionUID = 1L; |
| |
| public Iterator<? extends FlvRecording> getRoots() { |
| FlvRecording r = new FlvRecording(); |
| r.setFlvRecordingId(0); |
| r.setFileName(Application.getString(860)); |
| r.setFolder(true); |
| r.setOwnerId(getUserId()); |
| return Arrays.asList(r).iterator(); |
| } |
| |
| public Iterator<? extends FlvRecording> getChildren(FlvRecording node) { |
| if (node.getFlvRecordingId() == 0) { |
| return getBean(FlvRecordingDao.class).getFlvRecordingRootByOwner(getUserId()).iterator(); |
| } else { |
| return super.getChildren(node); |
| } |
| } |
| } |
| |
| class PublicRecordingTreeProvider extends RecordingTreeProvider { |
| private static final long serialVersionUID = 5502610991599632079L; |
| private final Long orgId; |
| private final String name; |
| |
| public PublicRecordingTreeProvider(Long orgId, String name) { |
| this.orgId = orgId; |
| this.name = name; |
| } |
| |
| public Iterator<? extends FlvRecording> getRoots() { |
| FlvRecording r = new FlvRecording(); |
| r.setFlvRecordingId(orgId == null ? -1 : -orgId); |
| r.setOrganization_id(orgId); |
| r.setOwnerId(null); |
| r.setFolder(true); |
| String pub = Application.getString(861); |
| r.setFileName(orgId == null ? pub : String.format("%s (%s)", pub, name)); |
| return Arrays.asList(r).iterator(); |
| } |
| |
| public Iterator<? extends FlvRecording> getChildren(FlvRecording node) { |
| if (node.getFlvRecordingId() < 0) { |
| return getBean(FlvRecordingDao.class).getFlvRecordingRootByPublic(orgId).iterator(); |
| } else { |
| return super.getChildren(node); |
| } |
| } |
| } |
| |
| abstract class RecordingTreeProvider implements ITreeProvider<FlvRecording> { |
| private static final long serialVersionUID = 1L; |
| |
| public void detach() { |
| // TODO LDM should be used |
| } |
| |
| public boolean hasChildren(FlvRecording node) { |
| return node.getFlvRecordingId() <= 0 || node.isFolder(); |
| } |
| |
| public Iterator<? extends FlvRecording> getChildren(FlvRecording node) { |
| return getBean(FlvRecordingDao.class).getFlvRecordingByParent(node.getFlvRecordingId()).iterator(); |
| } |
| |
| public IModel<FlvRecording> model(FlvRecording object) { |
| // TODO LDM should be used |
| return Model.of(object); |
| } |
| } |
| } |