/*
* #%L
* carewebframework
* %%
* Copyright (C) 2008 - 2016 Regenstrief Institute, Inc.
* %%
* Licensed 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.
*
* This Source Code Form is also subject to the terms of the Health-Related
* Additional Disclaimer of Warranty and Limitation of Liability available at
*
* http://www.carewebframework.org/licensing/disclaimer.
*
* #L%
*/
package org.carewebframework.testharness;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.carewebframework.common.MiscUtil;
import org.carewebframework.shell.plugins.PluginController;
import org.carewebframework.ui.zk.ZKUtil;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.Resource;
import org.zkoss.zk.au.out.AuInvoke;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.ComboitemRenderer;
import org.zkoss.zul.Idspace;
import org.zkoss.zul.Label;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Window;
/**
* Plugin to facilitate testing of zul layouts.
*/
public class SandboxController extends PluginController implements ApplicationContextAware {
private static final long serialVersionUID = 1L;
private static final String[] REPLACE_MODES = { "modal", "highlighted", "popup" };
private static ComboitemRenderer<Resource> zulRenderer = new ComboitemRenderer<Resource>() {
@Override
public void render(Comboitem item, Resource resource, int index) throws Exception {
item.setValue(resource);
item.setLabel(resource.getFilename());
item.setTooltiptext(getPath(resource));
}
private String getPath(Resource resource) throws IOException {
String[] pcs = resource.getURL().toString().split("!", 2);
if (pcs.length == 1) {
return pcs[0];
}
int i = pcs[0].lastIndexOf('/') + 1;
return pcs[0].substring(i) + ":\n\n" + pcs[1];
}
};
// Start of auto-wired section
private Textbox txtContent;
private Combobox cboZul;
private Component contentParent;
// End of auto-wired section
private Component contentBase;
private String content;
private final ListModelList<Resource> model = new ListModelList<>();
/**
* Find the content base component. We can't assign it an id because of potential id collisions.
*/
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
cboZul.setItemRenderer(zulRenderer);
cboZul.setModel(model);
cboZul.setVisible(model.size() > 0);
contentBase = ZKUtil.findChild(contentParent, Idspace.class);
}
/**
* Refreshes the view based on the current contents.
*/
@Override
public void refresh() {
super.refresh();
ZKUtil.detachChildren(contentBase);
if (content != null && !content.isEmpty()) {
try {
Events.echoEvent("onModeCheck", this.root, null);
Executions.createComponentsDirectly(content, null, contentBase, null);
} catch (Exception e) {
ZKUtil.detachChildren(contentBase);
Label label = new Label(ExceptionUtils.getStackTrace(e));
label.setMultiline(true);
contentBase.appendChild(label);
}
}
}
/**
* Check for unsupported window modes. This is done asynchronously to allow modal windows to
* also be checked.
*/
public void onModeCheck() {
modeCheck(contentBase);
}
/**
* Check for any window components with mode settings that need to be changed.
*
* @param comp Current component in search.
*/
private void modeCheck(Component comp) {
if (comp instanceof Window) {
Window win = (Window) comp;
if (win.isVisible() && ArrayUtils.contains(REPLACE_MODES, win.getMode())) {
win.setMode("overlapped");
}
}
for (Component child : comp.getChildren()) {
modeCheck(child);
}
}
/**
* Renders the updated zul content in the view pane.
*/
public void onClick$btnRenderContent() {
content = txtContent.getText();
refresh();
}
/**
* Clears combo box selection when content is cleared.
*/
public void onClick$btnClearContent() {
txtContent.setText(null);
cboZul.setSelectedItem(null);
cboZul.setTooltiptext(null);
}
/**
* Clears the view pane.
*/
public void onClick$btnClearView() {
ZKUtil.detachChildren(contentBase);
}
/**
* Re-renders content in the view pane.
*/
public void onClick$btnRefreshView() {
refresh();
}
/**
* Load contents of newly selected zul document.
*
* @throws IOException Exception on reading zul document.
*/
public void onSelect$cboZul() throws IOException {
Comboitem item = cboZul.getSelectedItem();
cboZul.setTooltiptext(null);
Resource resource = item == null ? null : (Resource) item.getValue();
if (resource != null) {
try (InputStream is = resource.getInputStream()) {
content = IOUtils.toString(is);
cboZul.setTooltiptext(item.getTooltiptext());
txtContent.setText(content);
txtContent.setFocus(true);
execution.addAuResponse(new AuInvoke(txtContent, "resync"));
}
}
}
/**
* Set text box focus upon activation.
*/
@Override
public void onActivate() {
super.onActivate();
txtContent.focus();
}
/**
* Populate combo box model with all zul documents on class path.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
try {
for (Resource resource : applicationContext.getResources("classpath*:**/*.zul")) {
model.add(resource);
}
} catch (Exception e) {
throw MiscUtil.toUnchecked(e);
}
}
}