/** * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> * University of Zurich, Switzerland. * <hr> * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed * under the Apache 2.0 license as the original file. * <p> * Initial code contributed and copyrighted by<br> * JGS goodsolutions GmbH, http://www.goodsolutions.ch * <p> */ package org.olat.core.gui.dev.controller; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.olat.core.gui.UserRequest; import org.olat.core.gui.Windows; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.ComponentCollection; import org.olat.core.gui.components.Container; import org.olat.core.gui.components.Window; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; import org.olat.core.gui.components.panel.Panel; import org.olat.core.gui.components.util.ComponentUtil; import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.DefaultController; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.control.floatingresizabledialog.FloatingResizableDialogController; import org.olat.core.gui.control.generic.spacesaver.ExpColController; import org.olat.core.gui.control.winmgr.WindowBackOfficeImpl; import org.olat.core.gui.control.winmgr.WindowManagerImpl; import org.olat.core.gui.render.Renderer; import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.intercept.DebugHelper; import org.olat.core.gui.util.bandwidth.SlowBandWidthSimulator; /** * * Description:<br> * * <P> * Initial Date: 20.05.2006 <br> * * @author Felix Jost */ public class DevelopmentController extends BasicController { private VelocityContainer myContent; private Panel mainpanel; private final WindowBackOfficeImpl wboImpl; private ExpColController spacesaverController; private Component mainComp; private Link web10Link; private Link web20Link; private Link showComponentTree; private List<Link> modes = new ArrayList<Link>(); private Link chosenMode; private WindowManagerImpl winMgrImpl; private Link debugLink; private boolean treeShown = false; private int pageCnt =0; // only for visual indication // fast polling while developing: no more need to push browser reload! private Link toggleAutorefresh; private boolean autorefresh = false; private Controller floatCtr; private Controller bandwithController; private Link devToolLink; /** * @param ureq * @param wControl * @param navElem */ public DevelopmentController(UserRequest ureq, WindowControl wControl, WindowBackOfficeImpl wboImpl) { super(ureq, wControl); this.wboImpl = wboImpl; this.winMgrImpl = wboImpl.getWinmgrImpl(); // set up the main layout myContent = createVelocityContainer("index"); // create four links to switch between modes. // a special case here: these link must work in regular mode (normal uri with full screen refresh (as // opposed to partial page refresh )in order to switch modes correctly. // (grouping only needed for coloring) web10Link = LinkFactory.createLink("web10", myContent, this); web10Link.setAjaxEnabled(false); web20Link =LinkFactory.createLink("web20", myContent, this); web20Link.setAjaxEnabled(false); debugLink = LinkFactory.createLink("debug", myContent, this); debugLink.setAjaxEnabled(false); modes.add(web10Link); modes.add(web20Link); modes.add(debugLink); if (winMgrImpl.isAjaxEnabled()) { chosenMode = web20Link; } else { chosenMode = web10Link; } updateUI(); // commands showComponentTree = LinkFactory.createButton("showComponentTree", myContent, this); showComponentTree.setAjaxEnabled(false); myContent.contextPut("compdump", ""); myContent.contextPut("sys", this); toggleAutorefresh = LinkFactory.createButtonSmall("toggleAutorefresh", myContent, this); // do it with web 1.0 full page reload timer myContent.contextPut("autorefresh", "false"); // slow bandwidth simulation SlowBandWidthSimulator sbs = Windows.getWindows(ureq).getSlowBandWidthSimulator(); bandwithController = sbs.createAdminGUI().createController(ureq, getWindowControl()); myContent.put("bandwidth",bandwithController.getInitialComponent()); mainpanel = new Panel("developermainpanel"); devToolLink = LinkFactory.createCustomLink("devTool", "devTool", "", Link.NONTRANSLATED, myContent, this); devToolLink.setIconLeftCSS("o_icon o_icon_dev o_icon-fw"); devToolLink.setCustomEnabledLinkCSS("o_dev hidden-print"); devToolLink.setTitle(translate("devTool")); Component protectedMainPanel = DebugHelper.createDebugProtectedWrapper(mainpanel); spacesaverController = new ExpColController(ureq, getWindowControl(), false, protectedMainPanel, devToolLink); mainComp = DebugHelper.createDebugProtectedWrapper(spacesaverController.getInitialComponent()); putInitialPanel(mainComp); } /** * [used by velocity] * @return */ public String time() { return ""+System.currentTimeMillis(); } /** * [used by velocity] * @return a hex color */ public String modthree() { int n = ++pageCnt % 3; switch (n) { case 0: return "FF0000"; case 1: return "00FF00"; case 2: return "0000FF"; default: return "n/a"; // cannot happen } } /** * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, * org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) */ public void event(UserRequest ureq, Component source, Event event) { if (source == devToolLink) { removeAsListenerAndDispose(floatCtr); floatCtr = new FloatingResizableDialogController(ureq, getWindowControl(), myContent, "Brasato Development Tool", 1000, 200, 10, 60, true, true); listenTo(floatCtr); mainpanel.setContent(floatCtr.getInitialComponent()); } else if (source == web10Link) { // choose regular mode winMgrImpl.setShowDebugInfo(false); winMgrImpl.setAjaxEnabled(false); winMgrImpl.setIdDivsForced(false); chosenMode = web10Link; updateUI(); } else if (source == web20Link) { // enable ajax / generic-dom-replacement GDR mode winMgrImpl.setShowDebugInfo(false); winMgrImpl.setAjaxEnabled(true); winMgrImpl.setIdDivsForced(false); chosenMode = web20Link; updateUI(); } else if (source == debugLink) { // debug mode requires web 1.0 mode at the moment winMgrImpl.setShowDebugInfo(true); winMgrImpl.setAjaxEnabled(false); winMgrImpl.setIdDivsForced(false); chosenMode = debugLink; updateUI(); } else if (source == showComponentTree) { if (treeShown) { // hide component tree myContent.contextPut("compdump", ""); winMgrImpl.setIdDivsForced(false); } else { winMgrImpl.setIdDivsForced(true); updateComponentTree(); } treeShown = !treeShown; } else if (source == toggleAutorefresh) { autorefresh = !autorefresh; if (autorefresh) { myContent.contextPut("autorefresh", "true"); } else { myContent.contextPut("autorefresh", "false"); } } else if (event == ComponentUtil.VALIDATE_EVENT) { // todo update mode if (treeShown) { updateComponentTree(); } } } @Override protected void event(UserRequest ureq, Controller source, Event event) { if (source == floatCtr) { if (event.equals(Event.DONE_EVENT)) { spacesaverController.toggleUi(); } } } private void updateComponentTree() { Window win = wboImpl.getWindow(); StringOutput sb = new StringOutput(); renderDebugInfo(win.getContentPane(), sb); myContent.contextPut("compdump", sb.toString()); } private void updateUI() { // update mode. for (Link li : modes) { myContent.contextPut(li.getComponentName() + "Active", (li == chosenMode ? Boolean.TRUE : Boolean.FALSE)); } myContent.contextPut("compdump", ""); } /** * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) */ protected void doDispose() { // floatCtr auto disposed by basic controller if (spacesaverController != null) spacesaverController.dispose(); if (bandwithController != null) bandwithController.dispose(); } /** * used by velocityrenderdecorator * @param target */ private void renderDebugInfo(Component root, StringOutput target) { target.append("<div>"); int cnt = cntTree(root); int size = DefaultController.getControllerCount(); target.append("<strong>Component Tree:</strong> count: " + cnt + "  |  Controllers (global: active and not disposed): <strong>"+size+"</strong>"); target.append("</div><div>"); Map<Controller, List<Component>> controllerInfos = new HashMap<Controller, List<Component>>(); dumpTree(target, root, 0, controllerInfos); target.append("</div>"); // now dump the controller info for (Controller controller : controllerInfos.keySet()) { try { Component initComp = controller.getInitialComponent(); target.append("<div style=\"padding-bottom:2px; \"><strong>Controller "+controller.getClass().getName()+" :"+controller.hashCode()); appendDivCodeForComponent("<i>Initial Component:</i> ",target, initComp, 20); List<Component> listenTo = controllerInfos.get(controller); for (Component component : listenTo) { appendDivCodeForComponent("", target, component, 20); } target.append("</strong></div><br />"); } catch (Exception e) { // some components like window dont like being called for the initialcomponent // -> ignore } } } private void appendDivCodeForComponent(String pre, StringOutput sb, Component current, int marginLeft) { String pcid = Renderer.getComponentPrefix(current); sb.append("<div"); if (current.isVisible() && current.isDomReplaceable()) { sb.append(" onMouseOver=\"jQuery(this).css('background-color','#f3feff');o_dbg_mark('").append(pcid) .append("')\" onMouseOut=\"jQuery(this).css('background-color','');o_dbg_unmark('").append(pcid).append("')\""); } sb.append(" style=\"color:blue; padding-bottom:2px; font-size:10px\"><div style=\"margin-left:"+marginLeft+"px\">"); String cname = current.getClass().getName(); cname = cname.substring(cname.lastIndexOf('.') + 1); sb.append(pre+"<b>" + cname + "</b> (" + current.getComponentName() + " id "+current.getDispatchID()+") "); sb.append((current.isVisible()? "":"INVISIBLE ")+(current.isEnabled()? "":" NOT ENABLED ")+current.getExtendedDebugInfo()+", "+current.getListenerInfo()+"<br />"); sb.append("</div></div>"); } private void dumpTree(StringOutput sb, Component current, int indent, Map<Controller, List<Component>> controllerInfos) { // add infos, Controller lController = org.olat.core.gui.dev.Util.getListeningControllerFor(current); if (lController != null) { List<Component> lcomps = controllerInfos.get(lController); if (lcomps == null) { // first entry lcomps = new ArrayList<Component>(); controllerInfos.put(lController, lcomps); } lcomps.add(current); } int pxInd = indent * 25; String pcid = Renderer.getComponentPrefix(current); sb.append("<div id='dmt_").append(pcid).append("' "); if (current.isVisible() && current.isDomReplaceable()) { sb.append(" onMouseOver=\"jQuery(this).css('background-color','#f3feff');o_dbg_mark('").append(pcid) .append("')\" onMouseOut=\"jQuery(this).css('background-color','');o_dbg_unmark('").append(pcid).append("')\""); } sb.append(" style=\"color:blue; padding-bottom:2px; font-size:10px\"><div style=\"margin-left:"+pxInd+"px\">"); String cname = current.getClass().getName(); cname = cname.substring(cname.lastIndexOf('.') + 1); sb.append("<b>" + cname + "</b> (" + current.getComponentName() + " id "+current.getDispatchID()+") "); if (current == mainComp) { // suppress detail and subtree for our controller here sb.append(" --suppressing output, since developmentcontroller --</div></div>"); } else { sb.append((current.isVisible()? "":"INVISIBLE ")+(current.isEnabled()? "":" NOT ENABLED ")+current.getExtendedDebugInfo()+", "+current.getListenerInfo()+"<br />"); sb.append("</div></div>"); if (current instanceof Container) { Container co = (Container) current; for (Component child:co.getComponents()) { dumpTree(sb, child, indent + 1, controllerInfos); } } } } private int cntTree(Component current) { int cnt = 1; if (current instanceof ComponentCollection) { ComponentCollection co = (ComponentCollection) current; for (Component child:co.getComponents()) { cnt += cntTree(child); } } return cnt; } }