/* * #%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.shell.designer; import static org.carewebframework.shell.designer.DesignConstants.CAP_LAYOUT_CLONE; import static org.carewebframework.shell.designer.DesignConstants.CAP_LAYOUT_IMPORT; import static org.carewebframework.shell.designer.DesignConstants.CAP_LAYOUT_LOAD; import static org.carewebframework.shell.designer.DesignConstants.CAP_LAYOUT_MANAGE; import static org.carewebframework.shell.designer.DesignConstants.CAP_LAYOUT_RENAME; import static org.carewebframework.shell.designer.DesignConstants.CAP_LAYOUT_SAVE; import static org.carewebframework.shell.designer.DesignConstants.ERR_LAYOUT_IMPORT; import static org.carewebframework.shell.designer.DesignConstants.MSG_LAYOUT_CLONE; import static org.carewebframework.shell.designer.DesignConstants.MSG_LAYOUT_DELETE; import static org.carewebframework.shell.designer.DesignConstants.MSG_LAYOUT_IMPORT; import static org.carewebframework.shell.designer.DesignConstants.MSG_LAYOUT_LOAD; import static org.carewebframework.shell.designer.DesignConstants.MSG_LAYOUT_MANAGE; import static org.carewebframework.shell.designer.DesignConstants.MSG_LAYOUT_RENAME; import static org.carewebframework.shell.designer.DesignConstants.MSG_LAYOUT_SAVE; import static org.carewebframework.shell.designer.DesignConstants.RESOURCE_PREFIX; import org.carewebframework.api.FrameworkUtil; import org.carewebframework.common.StrUtil; import org.carewebframework.shell.layout.LayoutIdentifier; import org.carewebframework.shell.layout.LayoutUtil; import org.carewebframework.shell.layout.UILayout; import org.carewebframework.ui.zk.ListUtil; import org.carewebframework.ui.zk.PopupDialog; import org.carewebframework.ui.zk.PromptDialog; import org.carewebframework.ui.zk.ZKUtil; import org.zkoss.util.media.Media; import org.zkoss.zk.ui.HtmlBasedComponent; import org.zkoss.zk.ui.event.Events; import org.zkoss.zul.Button; import org.zkoss.zul.Filedownload; import org.zkoss.zul.Fileupload; import org.zkoss.zul.Label; import org.zkoss.zul.ListModelList; import org.zkoss.zul.Listbox; import org.zkoss.zul.Listitem; import org.zkoss.zul.ListitemRenderer; import org.zkoss.zul.Radiogroup; import org.zkoss.zul.Window; /** * Supports selection and management of existing layouts. */ public class LayoutManager extends Window { private static final long serialVersionUID = 1L; private static final String ATTR_DEFAULT_SCOPE = LayoutUtil.class.getName() + ".default_scope"; private Button btnOK; private Button btnDelete; private Button btnRename; private Button btnClone; private Button btnExport; private Listbox lstLayouts; private Label lblPrompt; private Radiogroup radioGroup; private HtmlBasedComponent pnlManage; private HtmlBasedComponent pnlSelect; private HtmlBasedComponent pnlScope; private boolean shared; private LayoutIdentifier selectedLayout; private final ListitemRenderer<String> renderer = new ListitemRenderer<String>() { @Override public void render(Listitem item, String data, int index) throws Exception { item.setLabel(data); item.setValue(new LayoutIdentifier(data, shared)); if (pnlSelect.isVisible()) { item.addForward(Events.ON_DOUBLE_CLICK, btnOK, Events.ON_CLICK); } } }; /** * Returns true if the default layout scope is shared. * * @return True if the default layout scope is shared. */ public static boolean defaultIsShared() { return FrameworkUtil.getAttribute(ATTR_DEFAULT_SCOPE) != null; } /** * Sets the default layout scope. * * @param isShared If true, the default scope is shared. If false, it is private. */ public static void defaultIsShared(boolean isShared) { FrameworkUtil.setAttribute(ATTR_DEFAULT_SCOPE, isShared ? true : null); } /** * Invokes the layout manager dialog. * * @param manage If true, open in management mode; otherwise, in selection mode. * @param deflt Default layout name. * @return The layout selected on dialog closure. */ public static LayoutIdentifier execute(boolean manage, String deflt) { LayoutManager dlg = null; try { dlg = (LayoutManager) PopupDialog.popup(ZKUtil.loadCachedPageDefinition(RESOURCE_PREFIX + "LayoutManager.zul"), null, true, true, false); return dlg.show(manage, deflt); } catch (Exception e) { return null; } } /** * Prompts to save layout. * * @param layout Layout to save. * @param layoutId Layout identifier * @param hideScope If true, hide shared/private scope selection. * @return The saved layout name. */ public static LayoutIdentifier saveLayout(UILayout layout, LayoutIdentifier layoutId, boolean hideScope) { layoutId = LayoutPrompt.promptLayout(layoutId, hideScope, true, CAP_LAYOUT_SAVE, MSG_LAYOUT_SAVE); if (layoutId != null) { layout.saveToProperty(layoutId); } return layoutId; } /** * Import a layout. * * @param shared If true, import as a shared layout. * @return The layout identifier if the import was successful, null otherwise. */ public static LayoutIdentifier importLayout(boolean shared) { while (true) { try { Media media = Fileupload.get(StrUtil.formatMessage(MSG_LAYOUT_IMPORT), StrUtil.formatMessage(CAP_LAYOUT_IMPORT), false); if (media == null) { break; } if (!"text/xml".equalsIgnoreCase(media.getContentType())) { PromptDialog.showError(ERR_LAYOUT_IMPORT); continue; } UILayout layout = new UILayout(); layout.loadFromText(media.getStringData()); LayoutIdentifier layoutId = saveLayout(layout, new LayoutIdentifier(layout.getName(), shared), false); return layoutId; } catch (Exception e) { PromptDialog.showError(e); } } return null; } public static void exportLayout(LayoutIdentifier layout) { String content = LayoutUtil.getLayoutContent(layout); Filedownload.save(content, "text/xml", layout.name + ".xml"); } /** * Initialize and display the dialog. * * @param manage If true, open in management mode; otherwise, in selection mode. * @param deflt Default layout name. * @return The selected layout name (if in selection mode). */ private LayoutIdentifier show(boolean manage, String deflt) { this.shared = defaultIsShared(); ZKUtil.wireController(this); setTitle(StrUtil.formatMessage(manage ? CAP_LAYOUT_MANAGE : CAP_LAYOUT_LOAD)); lblPrompt.setValue(StrUtil.formatMessage(manage ? MSG_LAYOUT_MANAGE : MSG_LAYOUT_LOAD)); lstLayouts.setItemRenderer(renderer); pnlSelect.setVisible(!manage); pnlManage.setVisible(manage); radioGroup.setSelectedIndex(shared ? 0 : 1); pnlScope.setSclass(manage ? "pull-right" : "pull-left"); refresh(deflt); doModal(); return manage || selectedLayout == null ? null : selectedLayout; } /** * Refresh the list. * * @param deflt The layout to select initially. */ private void refresh(String deflt) { lstLayouts.setModel(new ListModelList<>(LayoutUtil.getLayouts(shared))); lstLayouts.setSelectedIndex(deflt == null ? -1 : ListUtil.findListboxItem(lstLayouts, deflt)); updateControls(); } /** * Update control states. */ private void updateControls() { boolean disable = getSelectedLayout() == null; btnDelete.setDisabled(disable); btnOK.setDisabled(disable); btnRename.setDisabled(disable); btnClone.setDisabled(disable); btnExport.setDisabled(disable); } /** * Returns the identifier of the currently selected layout, or null if none selected. * * @return The currently selected layout. */ private LayoutIdentifier getSelectedLayout() { Listitem item = lstLayouts.getSelectedItem(); return item == null ? null : (LayoutIdentifier) item.getValue(); } /** * Clone or rename a layout. * * @param clone If true, perform a clone operation; if false, a rename operation. */ private void cloneOrRename(boolean clone) { String title = clone ? CAP_LAYOUT_CLONE : CAP_LAYOUT_RENAME; String prompt = clone ? MSG_LAYOUT_CLONE : MSG_LAYOUT_RENAME; LayoutIdentifier layoutId1 = getSelectedLayout(); LayoutIdentifier layoutId2 = LayoutPrompt.promptLayout(layoutId1, !clone, false, title, prompt); if (layoutId2 != null) { if (clone) { LayoutUtil.cloneLayout(layoutId1, layoutId2); } else { LayoutUtil.renameLayout(layoutId1, layoutId2.name); } refresh(null); } } /** * Sets the selected layout and closes the dialog. */ public void onClick$btnOK() { selectedLayout = getSelectedLayout(); if (selectedLayout != null) { onClose(); } } /** * Deletes the selected layout. */ public void onClick$btnDelete() { if (PromptDialog.confirm(MSG_LAYOUT_DELETE)) { LayoutUtil.deleteLayout(getSelectedLayout()); refresh(null); } } /** * Renames the selected layout. */ public void onClick$btnRename() { cloneOrRename(false); } /** * Clones the selected layout. */ public void onClick$btnClone() { cloneOrRename(true); } /** * Import a layout. */ public void onClick$btnImport() { LayoutIdentifier layoutId = importLayout(shared); if (layoutId != null) { refresh(layoutId.name); } } /** * Export a layout */ public void onClick$btnExport() { exportLayout(getSelectedLayout()); } /** * Update control states when selection changes. */ public void onSelect$lstLayouts() { updateControls(); } /** * Refresh when shared/private toggled. */ public void onCheck$radioGroup() { shared = radioGroup.getSelectedIndex() == 0; defaultIsShared(shared); refresh(null); } }