Java tutorial
/** * Licensed to JumpMind Inc under one or more contributor * license agreements. See the NOTICE file distributed * with this work for additional information regarding * copyright ownership. JumpMind Inc licenses this file * to you under the GNU General Public License, version 3.0 (GPLv3) * (the "License"); you may not use this file except in compliance * with the License. * * You should have received a copy of the GNU General Public License, * version 3.0 (GPLv3) along with this library; if not, see * <http://www.gnu.org/licenses/>. * * 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.jumpmind.metl.ui.views; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import org.jumpmind.metl.core.model.AbstractObject; import org.jumpmind.metl.core.model.Agent; import org.jumpmind.metl.core.model.AgentName; import org.jumpmind.metl.core.model.Folder; import org.jumpmind.metl.core.model.FolderType; import org.jumpmind.metl.core.persist.IConfigurationService; import org.jumpmind.metl.ui.common.ApplicationContext; import org.jumpmind.metl.ui.common.EnableFocusTextField; import org.jumpmind.metl.ui.common.Icons; import org.jumpmind.metl.ui.common.TabbedPanel; import org.jumpmind.metl.ui.views.deploy.EditAgentPanel; import org.jumpmind.util.AppUtils; import org.jumpmind.vaadin.ui.common.CommonUiUtils; import org.jumpmind.vaadin.ui.common.ConfirmDialog; import org.jumpmind.vaadin.ui.common.ConfirmDialog.IConfirmListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vaadin.data.Container; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.data.util.BeanItemContainer; import com.vaadin.event.FieldEvents.BlurEvent; import com.vaadin.event.FieldEvents.BlurListener; import com.vaadin.event.FieldEvents.FocusEvent; import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.event.ItemClickEvent; import com.vaadin.event.ItemClickEvent.ItemClickListener; import com.vaadin.event.ShortcutAction.KeyCode; import com.vaadin.event.ShortcutListener; import com.vaadin.server.FontAwesome; import com.vaadin.shared.MouseEventDetails.MouseButton; import com.vaadin.shared.ui.MarginInfo; import com.vaadin.ui.Component; import com.vaadin.ui.DefaultFieldFactory; import com.vaadin.ui.Field; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.Command; import com.vaadin.ui.MenuBar.MenuItem; import com.vaadin.ui.Notification.Type; import com.vaadin.ui.Table; import com.vaadin.ui.Table.CellStyleGenerator; import com.vaadin.ui.Table.ColumnHeaderMode; import com.vaadin.ui.TextField; import com.vaadin.ui.Tree.CollapseEvent; import com.vaadin.ui.Tree.CollapseListener; import com.vaadin.ui.Tree.ExpandEvent; import com.vaadin.ui.Tree.ExpandListener; import com.vaadin.ui.TreeTable; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.themes.ValoTheme; @SuppressWarnings("serial") public class DeployNavigator extends VerticalLayout { final Logger log = LoggerFactory.getLogger(getClass()); MenuItem newFolder; MenuItem delete; MenuItem newAgent; ApplicationContext context; TreeTable treeTable; AbstractObject lastSelected; AbstractObject itemBeingEdited; TabbedPanel tabbedPanel; MenuItem search; HorizontalLayout searchBarLayout; public DeployNavigator(ApplicationContext context, TabbedPanel tabbedPanel) { this.context = context; this.tabbedPanel = tabbedPanel; setCaption("Navigator"); setSizeFull(); addStyleName("noborder"); addStyleName(ValoTheme.MENU_ROOT); addComponent(buildMenuBar()); searchBarLayout = buildSearchBar(); addComponent(searchBarLayout); treeTable = buildTreeTable(); treeTable.addStyleName("noselect"); addComponent(treeTable); setExpandRatio(treeTable, 1); } public void select(Object obj) { Object parent = obj; do { parent = treeTable.getParent(parent); if (parent != null) { treeTable.setCollapsed(parent, false); } } while (parent != null); treeTable.setValue(obj); } public void refresh() { Object selected = treeTable.getValue(); List<Object> expandedItems = new ArrayList<Object>(); Collection<?> items = treeTable.getItemIds(); for (Object object : items) { if (!treeTable.isCollapsed(object)) { expandedItems.add(object); } } treeTable.removeAllItems(); List<Folder> folders = context.getConfigurationService().findFolders(null, FolderType.AGENT); for (Folder folder : folders) { addChildren(folder); } for (Object object : expandedItems) { treeTable.setCollapsed(object, false); } treeTable.focus(); if (treeTable.containsId(selected)) { treeTable.setValue(selected); } else { if (treeTable.getItemIds().size() > 0) { treeTable.setValue(treeTable.getItemIds().iterator().next()); } } treeTable.focus(); } protected HorizontalLayout buildSearchBar() { HorizontalLayout layout = new HorizontalLayout(); layout.setMargin(new MarginInfo(false, true, true, true)); layout.setWidth(100, Unit.PERCENTAGE); layout.setVisible(false); TextField search = new TextField(); search.setIcon(Icons.SEARCH); search.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); search.setWidth(100, Unit.PERCENTAGE); layout.addComponent(search); return layout; } protected HorizontalLayout buildMenuBar() { HorizontalLayout layout = new HorizontalLayout(); layout.setWidth(100, Unit.PERCENTAGE); MenuBar leftMenuBar = new MenuBar(); leftMenuBar.addStyleName(ValoTheme.MENUBAR_BORDERLESS); leftMenuBar.setWidth(100, Unit.PERCENTAGE); MenuItem newMenu = leftMenuBar.addItem("New", null); newFolder = newMenu.addItem("Folder", new Command() { @Override public void menuSelected(MenuItem selectedItem) { addFolder(); } }); newAgent = newMenu.addItem("Agent", new Command() { @Override public void menuSelected(MenuItem selectedItem) { addAgent(); } }); MenuItem editMenu = leftMenuBar.addItem("Edit", null); editMenu.addItem("Open", new Command() { @Override public void menuSelected(MenuItem selectedItem) { openItem(treeTable.getValue()); } }); editMenu.addItem("Rename", new Command() { @Override public void menuSelected(MenuItem selectedItem) { startEditingItem((AbstractObject) treeTable.getValue()); } }); delete = editMenu.addItem("Remove", new Command() { @Override public void menuSelected(MenuItem selectedItem) { handleDelete(); } }); MenuBar rightMenuBar = new MenuBar(); rightMenuBar.addStyleName(ValoTheme.MENUBAR_BORDERLESS); search = rightMenuBar.addItem("", Icons.SEARCH, new Command() { @Override public void menuSelected(MenuItem selectedItem) { search.setChecked(!search.isChecked()); searchBarLayout.setVisible(search.isChecked()); } }); search.setVisible(false); layout.addComponent(leftMenuBar); layout.addComponent(rightMenuBar); layout.setExpandRatio(leftMenuBar, 1); return layout; } protected TreeTable buildTreeTable() { final TreeTable table = new TreeTable(); table.addStyleName(ValoTheme.TREETABLE_NO_HORIZONTAL_LINES); table.addStyleName(ValoTheme.TREETABLE_NO_STRIPES); table.addStyleName(ValoTheme.TREETABLE_NO_VERTICAL_LINES); table.addStyleName(ValoTheme.TREETABLE_BORDERLESS); table.setColumnHeaderMode(ColumnHeaderMode.HIDDEN); table.setSizeFull(); table.setCacheRate(100); table.setPageLength(100); table.setImmediate(true); table.setSelectable(true); table.setEditable(true); table.setContainerDataSource(new BeanItemContainer<AbstractObject>(AbstractObject.class)); table.setTableFieldFactory(new DefaultFieldFactory() { @Override public Field<?> createField(Container container, Object itemId, Object propertyId, Component uiContext) { return buildEditableNavigatorField(itemId); } }); table.setVisibleColumns(new Object[] { "name" }); table.setColumnExpandRatio("name", 1); table.addValueChangeListener(new ValueChangeListener() { private static final long serialVersionUID = 1L; @Override public void valueChange(ValueChangeEvent event) { lastSelected = getSelectedValue(); selectionChanged(event); } }); table.addItemClickListener(new ItemClickListener() { private static final long serialVersionUID = 1L; @Override public void itemClick(ItemClickEvent event) { if (event.getButton() == MouseButton.LEFT) { if (event.isDoubleClick()) { abortEditingItem(); openItem(event.getItemId()); if (table.areChildrenAllowed(event.getItemId())) { Object item = event.getItemId(); table.setCollapsed(item, !table.isCollapsed(item)); } } } } }); table.addCollapseListener(new CollapseListener() { private static final long serialVersionUID = 1L; @Override public void nodeCollapse(CollapseEvent event) { if (event.getItemId() instanceof Folder) { table.setItemIcon(event.getItemId(), FontAwesome.FOLDER); } } }); table.addExpandListener(new ExpandListener() { private static final long serialVersionUID = 1L; @Override public void nodeExpand(ExpandEvent event) { if (event.getItemId() instanceof Folder) { Folder folder = (Folder) event.getItemId(); table.setItemIcon(folder, FontAwesome.FOLDER_OPEN); } } }); table.setCellStyleGenerator(new CellStyleGenerator() { private static final long serialVersionUID = 1L; @Override public String getStyle(Table source, Object itemId, Object propertyId) { if (itemId instanceof Folder && "name".equals(propertyId)) { return "folder"; } else { return null; } } }); return table; } protected boolean startEditingItem(AbstractObject obj) { if (obj.isSettingNameAllowed()) { itemBeingEdited = obj; treeTable.refreshRowCache(); return true; } else { return false; } } protected void finishEditingItem() { if (itemBeingEdited != null) { IConfigurationService configurationService = context.getConfigurationService(); Object selected = itemBeingEdited; Method method = null; try { method = configurationService.getClass().getMethod("save", itemBeingEdited.getClass()); } catch (NoSuchMethodException e) { } catch (SecurityException e) { } if (method != null) { try { method.invoke(configurationService, itemBeingEdited); } catch (Exception e) { throw new RuntimeException(e); } } else { configurationService.save(itemBeingEdited); } itemBeingEdited = null; treeTable.refreshRowCache(); treeTable.focus(); treeTable.setValue(selected); } } protected void abortEditingItem() { if (itemBeingEdited != null) { itemBeingEdited = null; refresh(); treeTable.focus(); } } protected Field<?> buildEditableNavigatorField(Object itemId) { if (itemBeingEdited != null && itemBeingEdited.equals(itemId)) { final EnableFocusTextField field = new EnableFocusTextField(); field.addStyleName(ValoTheme.TEXTFIELD_SMALL); field.setImmediate(true); field.addFocusListener(new FocusListener() { @Override public void focus(FocusEvent event) { field.setFocusAllowed(false); field.selectAll(); field.setFocusAllowed(true); } }); field.focus(); field.addShortcutListener(new ShortcutListener("", KeyCode.ESCAPE, null) { @Override public void handleAction(Object sender, Object target) { abortEditingItem(); } }); field.addShortcutListener(new ShortcutListener("Enter", KeyCode.ENTER, null) { private static final long serialVersionUID = 1L; @Override public void handleAction(Object sender, Object target) { finishEditingItem(); } }); field.addBlurListener(new BlurListener() { @Override public void blur(BlurEvent event) { finishEditingItem(); } }); return field; } else { return null; } } protected AbstractObject getSelectedValue() { return (AbstractObject) treeTable.getValue(); } protected void openItem(Object item) { if (item instanceof AgentName) { AgentName agentName = (AgentName) item; Agent agent = context.getConfigurationService().findAgent(agentName.getId()); tabbedPanel.addCloseableTab(agent.getId(), agent.getName(), Icons.AGENT, new EditAgentPanel(context, tabbedPanel, agent)); } } protected Folder getSelectedFolder() { Object object = getSelectedValue(); if (object instanceof Folder) { return (Folder) object; } return null; } @SuppressWarnings("unchecked") protected <T> T getSingleSelection(Class<T> clazz) { Object obj = getSelectedValue(); if (obj != null && clazz.isAssignableFrom(obj.getClass())) { return (T) obj; } return null; } protected void selectionChanged(ValueChangeEvent event) { AbstractObject selected = getSelectedValue(); Folder selectedFolder = getSelectedFolder(); boolean showNewFolder = itemBeingEdited == null && (selected == null || selectedFolder != null); newFolder.setEnabled(showNewFolder); newAgent.setEnabled(selectedFolder != null && !selectedFolder.getName().startsWith("<")); delete.setEnabled(isDeleteButtonEnabled(selected)); } protected boolean isDeleteButtonEnabled(Object selected) { Folder selectedFolder = getSelectedFolder(); return (selectedFolder != null && !selectedFolder.getName().startsWith("<")) || selected instanceof AgentName; } protected void handleDelete() { if (getSelectedFolder() != null) { ConfirmDialog.show("Delete Folder?", "Are you sure you want to delete the selected folders?", new IConfirmListener() { private static final long serialVersionUID = 1L; @Override public boolean onOk() { Object obj = getSelectedValue(); if (obj instanceof Folder) { Folder folder = (Folder) obj; try { context.getConfigurationService().delete(folder); } catch (Exception ex) { log.error("", ex); CommonUiUtils.notify("Could not delete the \"" + folder.getName() + "\" folder", Type.WARNING_MESSAGE); } } refresh(); return true; } }); } AbstractObject obj = getSelectedValue(); if (!(obj instanceof Folder)) { deleteTreeItems(obj); } } protected void addFolder() { Folder parentFolder = getSelectedFolder(); Folder folder = new Folder(); folder.setName("New Folder"); folder.setType(FolderType.AGENT.name()); folder.setParent(parentFolder); addChildren(folder); while (parentFolder != null) { treeTable.setCollapsed(parentFolder, false); parentFolder = parentFolder.getParent(); } startEditingItem(folder); } protected void addAgent() { Folder folder = getSelectedFolder(); if (folder != null) { Agent agent = new Agent(); agent.setName("New Agent"); agent.setFolder(folder); agent.setHost(AppUtils.getHostName()); context.getConfigurationService().save(agent); context.getAgentManager().refresh(agent); AgentName name = new AgentName(agent); addAgent(folder, name); expand(folder, name); startEditingItem(name); } } protected void addAgent(Folder folder, AgentName agent) { treeTable.setChildrenAllowed(folder, true); treeTable.addItem(agent); treeTable.setItemIcon(agent, Icons.AGENT); treeTable.setParent(agent, folder); treeTable.setChildrenAllowed(agent, false); } protected void addChildren(Folder folder) { if (folder.getParent() != null) { treeTable.setChildrenAllowed(folder.getParent(), true); } treeTable.addItem(folder); treeTable.setItemIcon(folder, FontAwesome.FOLDER); treeTable.setCollapsed(folder, true); treeTable.setChildrenAllowed(folder, false); if (folder.getParent() != null) { treeTable.setParent(folder, folder.getParent()); } List<Folder> children = folder.getChildren(); for (Folder child : children) { addChildren(child); } List<AgentName> agents = context.getConfigurationService().findAgentsInFolder(folder); for (AgentName agent : agents) { addAgent(folder, agent); } } protected void deleteTreeItems(AbstractObject obj) { if (obj instanceof AgentName) { AgentName agentName = (AgentName) obj; Agent agent = context.getConfigurationService().findAgent(agentName.getId()); context.getConfigurationService().delete(agent); context.getAgentManager().refresh(agent); refresh(); } } protected void removeAllNonFolderChildren(Folder folder) { Collection<?> children = treeTable.getChildren(folder); if (children != null) { children = new HashSet<Object>(children); for (Object child : children) { if (!(child instanceof Folder)) { treeTable.removeItem(child); } } } } protected void expand(Folder folder, Object itemToSelect) { List<Folder> toExpand = new ArrayList<Folder>(); toExpand.add(0, folder); treeTable.unselect(folder); while (folder != null) { folder = folder.getParent(); if (folder != null) { toExpand.add(0, folder); } } for (Folder expandMe : toExpand) { treeTable.setCollapsed(expandMe, false); } treeTable.focus(); treeTable.select(itemToSelect); } }