/******************************************************************************* * Copyright (c) 2010-2014 SAP AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * SAP AG - initial API and implementation *******************************************************************************/ package org.eclipse.skalli.view.component; import java.util.Collection; import org.apache.commons.lang.StringUtils; import org.eclipse.skalli.commons.Link; import org.eclipse.skalli.model.ext.linkgroups.LinkGroup; import org.eclipse.skalli.model.ext.linkgroups.OrderableGroup; import org.eclipse.skalli.view.component.LinkWindow.ILinkAddedHandler; import org.eclipse.skalli.view.component.LinkWindow.ILinkModifiedHandler; import com.vaadin.terminal.Sizeable; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Component; import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; public class MultiLinkField extends CustomField implements ILinkAddedHandler, ILinkModifiedHandler { private static final long serialVersionUID = 8114438955923388539L; private static final String STYLE_LAYOUT = "multilink-layout"; //$NON-NLS-1$ private static final String STYLE_LABEL_GROUP = "multilink-grouplabel"; //$NON-NLS-1$ private static final String STYLE_LABEL_LINK = "multilink-linklabel"; //$NON-NLS-1$ private static final String STYLE_BUTTON_GROUPACTION = "multilink-groupaction"; //$NON-NLS-1$ private static final String STYLE_BUTTON_LINKACTION = "multilink-linkaction"; //$NON-NLS-1$ private static final String STYLE_BUTTON_ADD = "multilink-addlink"; //$NON-NLS-1$ private GridLayout layout; private String buttonCaption; private boolean modified; private boolean readOnly; private final OrderableGroup<LinkGroup> linkGroups; public MultiLinkField(String caption, String buttonCaption, Collection<LinkGroup> linkGroups) { setCaption(caption); this.buttonCaption = StringUtils.isNotBlank(buttonCaption)? buttonCaption : "Add Link"; this.linkGroups = new OrderableGroup<LinkGroup>(linkGroups); layout = new GridLayout(); // do not change the width! otherwise right border of table is hidden in IE! layout.setWidth(100, Sizeable.UNITS_PERCENTAGE); layout.setStyleName(STYLE_LAYOUT); render(); setCompositionRoot(layout); } private void renderIfModified() { if (modified) { render(); } } @SuppressWarnings({ "serial", "deprecation" }) private void render() { layout.removeAllComponents(); if (!readOnly) { layout.setColumns(2); } int groupsIdx = 0; int groupsSize = linkGroups.getItems().size(); for (final LinkGroup linkGroup : linkGroups.getItems()) { Label linkGroupLabel = new Label(linkGroup.getCaption()); linkGroupLabel.addStyleName(STYLE_LABEL_GROUP); layout.addComponent(linkGroupLabel); layout.setComponentAlignment(linkGroupLabel, Alignment.TOP_RIGHT); if (!readOnly) { Button btnUpGroup = null; Button btnDownGroup = null; Button btnRemoveGroup = null; // up if (groupsIdx > 0) { btnUpGroup = new Button("up"); btnUpGroup.setStyleName(Button.STYLE_LINK); btnUpGroup.addStyleName(STYLE_BUTTON_GROUPACTION); btnUpGroup.setDescription(String.format("Move up group '%s'", linkGroup.getCaption())); btnUpGroup.addListener(new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { modified = linkGroups.moveUp(linkGroup); renderIfModified(); } }); } // down if (groupsIdx < groupsSize - 1) { btnDownGroup = new Button("down"); btnDownGroup.setStyleName(Button.STYLE_LINK); btnDownGroup.addStyleName(STYLE_BUTTON_GROUPACTION); btnDownGroup.setDescription(String.format("Move down group '%s'", linkGroup.getCaption())); btnDownGroup.addListener(new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { modified = linkGroups.moveDown(linkGroup); renderIfModified(); } }); } // remove btnRemoveGroup = new Button("remove"); btnRemoveGroup.setStyleName(Button.STYLE_LINK); btnRemoveGroup.addStyleName(STYLE_BUTTON_GROUPACTION); btnRemoveGroup.setDescription(String.format("Remove group '%s'", linkGroup.getCaption())); btnRemoveGroup.addListener(new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { modified = linkGroups.remove(linkGroup); renderIfModified(); } }); HorizontalLayout toolbar = getToolbar(btnUpGroup, btnDownGroup, btnRemoveGroup); layout.addComponent(toolbar); layout.setComponentAlignment(toolbar, Alignment.TOP_RIGHT); } layout.newLine(); Collection<Link> links = linkGroup.getItems(); int linksIdx = 0; int linksSize = links.size(); for (final Link link : links) { if (readOnly) { // view Label linkLabel = new Label(link.getLabel()); linkLabel.addStyleName(STYLE_LABEL_LINK); linkLabel.setDescription(StringUtils.abbreviate(link.getUrl(), 50)); layout.addComponent(linkLabel); layout.setComponentAlignment(linkLabel, Alignment.TOP_LEFT); } else { // edit Button btnEditLink = new Button(link.getLabel()); btnEditLink.setStyleName(Button.STYLE_LINK); btnEditLink.addStyleName(STYLE_LABEL_LINK); btnEditLink.setDescription(String.format("Edit link '%s' %s", link.getLabel(), StringUtils.isBlank(link.getUrl()) ? "" : "[" + link.getUrl() + "]")); btnEditLink.addListener(new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { LinkWindow editLinkWindow = new LinkWindow(MultiLinkField.this, linkGroups.getItems(), linkGroup, link, MultiLinkField.this); editLinkWindow.show(); } }); layout.addComponent(btnEditLink); layout.setComponentAlignment(btnEditLink, Alignment.TOP_LEFT); } if (!readOnly) { Button btnUpLink = null; Button btnDownLink = null; Button btnRemoveLink = null; // up if (linksIdx > 0) { btnUpLink = new Button("up"); btnUpLink.setStyleName(Button.STYLE_LINK); btnUpLink.addStyleName(STYLE_BUTTON_LINKACTION); btnUpLink.setDescription(String.format("Move up link '%s'", link.getLabel())); btnUpLink.addListener(new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { modified = linkGroup.moveUp(link); renderIfModified(); } }); } // down if (linksIdx < linksSize - 1) { btnDownLink = new Button("down"); btnDownLink.setStyleName(Button.STYLE_LINK); btnDownLink.addStyleName(STYLE_BUTTON_LINKACTION); btnDownLink.setDescription(String.format("Move down link '%s'", link.getLabel())); btnDownLink.addListener(new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { modified = linkGroup.moveDown(link); renderIfModified(); } }); } // remove btnRemoveLink = new Button("remove"); btnRemoveLink.setStyleName(Button.STYLE_LINK); btnRemoveLink.addStyleName(STYLE_BUTTON_LINKACTION); btnRemoveLink.setDescription(String.format("Remove link '%s'", link.getLabel())); btnRemoveLink.addListener(new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { modified = linkGroup.remove(link); if (linkGroup.getItems().isEmpty()) { linkGroups.remove(linkGroup); } renderIfModified(); } }); HorizontalLayout toolbar = getToolbar(btnUpLink, btnDownLink, btnRemoveLink); layout.addComponent(toolbar); layout.setComponentAlignment(toolbar, Alignment.TOP_RIGHT); } layout.newLine(); linksIdx++; } groupsIdx++; } if (!readOnly) { Button btnAddLink = new Button(buttonCaption, new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { LinkWindow addLinkWindow = new LinkWindow(MultiLinkField.this, linkGroups.getItems(), MultiLinkField.this); addLinkWindow.show(); } }); btnAddLink.setStyleName(Button.STYLE_LINK); btnAddLink.addStyleName(STYLE_BUTTON_ADD); btnAddLink.setDescription("Add Link"); layout.addComponent(btnAddLink); } } private HorizontalLayout getToolbar(Component... components) { HorizontalLayout lineLayout = new HorizontalLayout(); for (Component component : components) { if (component != null) { lineLayout.addComponent(component); } } return lineLayout; } @Override public void onLinkAdded(String groupName, Link link) { LinkGroup linkGroup = getOrCreateLinkGroup(groupName); if (!linkGroup.hasItem(link)) { modified = linkGroup.add(link); } renderIfModified(); } @Override public void onLinkModified(LinkGroup oldGroup, String newGroupName, Link link, boolean linkModified) { modified = linkModified; // move link if the group changed if (!oldGroup.getCaption().equals(newGroupName)) { LinkGroup newGroup = getOrCreateLinkGroup(newGroupName); if (!newGroup.hasItem(link)) { modified = newGroup.add(link) || modified; } modified = oldGroup.remove(link) || modified; if (oldGroup.getItems().isEmpty()) { modified = linkGroups.remove(oldGroup) || modified; } } renderIfModified(); } @Override public boolean isModified() { return modified; } @Override public void setReadOnly(boolean readOnly) { this.readOnly = readOnly; layout.removeAllComponents(); render(); } @Override public boolean isReadOnly() { return readOnly; } @Override public Object getValue() { return linkGroups.getItems(); } @Override public Class<?> getType() { return Collection.class; } private LinkGroup getOrCreateLinkGroup(String groupName) { for (LinkGroup linkGroup : linkGroups.getItems()) { if (linkGroup.getCaption().equals(groupName)) { return linkGroup; } } LinkGroup newLinkGroup = new LinkGroup(); newLinkGroup.setCaption(groupName); linkGroups.add(newLinkGroup); return newLinkGroup; } }