Java tutorial
/* * Copyright (c) 2012 Brown Bag Consulting. * This file is part of the ExpressUI project. * Author: Juan Osuna * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License Version 3 * as published by the Free Software Foundation with the addition of the * following permission added to Section 15 as permitted in Section 7(a): * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY * Brown Bag Consulting, Brown Bag Consulting DISCLAIMS THE WARRANTY OF * NON INFRINGEMENT OF THIRD PARTY RIGHTS. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License. * * You can be released from the requirements of the license by purchasing * a commercial license. Buying such a license is mandatory as soon as you * develop commercial activities involving the ExpressUI software without * disclosing the source code of your own applications. These activities * include: offering paid services to customers as an ASP, providing * services from a web application, shipping ExpressUI with a closed * source product. * * For more information, please contact Brown Bag Consulting at this * address: juan@brownbagconsulting.com. */ package com.expressui.core.view.results; import com.expressui.core.util.assertion.Assert; import com.expressui.core.view.form.EntityForm; import com.expressui.core.view.form.EntityFormWindow; import com.expressui.core.view.form.ResultsConnectedEntityForm; import com.expressui.core.view.menu.ActionContextMenu; import com.vaadin.data.Property; import com.vaadin.data.util.BeanItem; import com.vaadin.event.ItemClickEvent; import com.vaadin.terminal.Sizeable; import com.vaadin.terminal.ThemeResource; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.HorizontalLayout; import org.vaadin.dialogs.ConfirmDialog; import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.persistence.EntityNotFoundException; import java.util.Collection; /** * Results with CRUD buttons to create, view, edit and delete selected items in the results. * * @param <T> type of entity in the results */ public abstract class CrudResults<T> extends Results<T> implements WalkableResults { @Resource protected ActionContextMenu actionContextMenu; private EntityForm<T> entityForm; private Button newButton; private Button editButton; private Button viewButton; private Button deleteButton; private boolean isViewMode; private Object currentItemId; protected CrudResults() { super(); } /** * Creates the entity form used for viewing or editing items in the results. Only called once lazily * when user views or edits a selected result. * <p/> * Unlike many other view components, EntityForm is created lazily for better performance and to avoid infinite * circular dependency injection. * * @return entity form */ protected abstract EntityForm<T> createEntityForm(); /** * Gets the entity form used for viewing or editing items in the results. Lazily initializes * entityForm by calling createEntityForm(). This method may not be overridden. * Override {@link #createEntityForm()} instead. * * @return entity form */ public final EntityForm<T> getEntityForm() { if (entityForm == null) { entityForm = createEntityForm(); entityForm.addCancelListener(this, "search"); entityForm.addCloseListener(this, "search"); entityForm.postWire(); } return entityForm; } @PostConstruct @Override public void postConstruct() { super.postConstruct(); getResultsTable().setMultiSelect(true); HorizontalLayout crudButtons = new HorizontalLayout(); setDebugId(crudButtons, "crudButtons"); crudButtons.setMargin(false); crudButtons.setSpacing(true); newButton = new Button(uiMessageSource.getMessage("crudResults.new"), this, "create"); newButton.setDescription(uiMessageSource.getToolTip("crudResults.new.toolTip")); newButton.setIcon(new ThemeResource("../expressui/icons/16/add.png")); newButton.addStyleName("small default"); crudButtons.addComponent(newButton); viewButton = new Button(uiMessageSource.getMessage("crudResults.view"), this, "view"); viewButton.setDescription(uiMessageSource.getToolTip("crudResults.view.toolTip")); viewButton.setIcon(new ThemeResource("../expressui/icons/16/view.png")); viewButton.addStyleName("small default"); crudButtons.addComponent(viewButton); editButton = new Button(uiMessageSource.getMessage("crudResults.edit"), this, "edit"); editButton.setDescription(uiMessageSource.getToolTip("crudResults.edit.toolTip")); editButton.setIcon(new ThemeResource("../expressui/icons/16/edit.png")); editButton.addStyleName("small default"); crudButtons.addComponent(editButton); deleteButton = new Button(uiMessageSource.getMessage("crudResults.delete"), this, "delete"); deleteButton.setDescription(uiMessageSource.getToolTip("crudResults.delete.toolTip")); deleteButton.setIcon(new ThemeResource("../expressui/icons/16/delete.png")); deleteButton.addStyleName("small default"); crudButtons.addComponent(deleteButton); actionContextMenu.addAction("crudResults.view", this, "view"); actionContextMenu.addAction("crudResults.edit", this, "edit"); actionContextMenu.addAction("crudResults.delete", this, "delete"); addSelectionChangedListener(this, "selectionChanged"); getCrudButtons().addComponent(crudButtons, 0); getCrudButtons().setComponentAlignment(crudButtons, Alignment.MIDDLE_LEFT); getResultsTable().addListener(new DoubleClickListener()); addCodePopupButtonIfEnabledForCrudResults(); } /** * Add code popup button next to this component. */ protected void addCodePopupButtonIfEnabledForCrudResults() { addCodePopupButtonIfEnabled(CrudResults.class); } @Override public void postWire() { super.postWire(); } @Override public void onDisplay() { syncCrudActions(); } /** * Creates a new entity and opens edit form to edit new entity. */ public void create() { getEntityForm().setViewMode(false); getEntityForm().syncCrudActions(); getEntityForm().create(); EntityFormWindow entityFormWindow = EntityFormWindow.open(getEntityForm()); entityFormWindow.addCloseListener(this, "search"); } /** * Views an entity and opens form in read-only mode. */ public void view() { getEntityForm().setViewMode(true); editOrView(); } /** * Edits the selected entity and opens edit form to edit selected entity. */ public void edit() { getEntityForm().setViewMode(false); editOrView(); } private void editOrView() { Collection itemIds = (Collection) getResultsTable().getValue(); Assert.PROGRAMMING.size(itemIds, 1); editOrView(itemIds.iterator().next()); } private void editOrView(Object itemId) { loadItem(itemId); ResultsConnectedEntityForm resultsConnectedEntityForm = new ResultsConnectedEntityForm(getEntityForm(), this); EntityFormWindow entityFormWindow = EntityFormWindow.open(resultsConnectedEntityForm); entityFormWindow.addCloseListener(this, "search"); if (getEntityForm().isPopupWindowHeightFull() == null) { if (!getEntityForm().getViewableToManyRelationships().isEmpty()) { entityFormWindow.setHeight(100, Sizeable.UNITS_PERCENTAGE); } } else { if (getEntityForm().isPopupWindowHeightFull()) { entityFormWindow.setHeight(100, Sizeable.UNITS_PERCENTAGE); } } } private void loadItem(Object itemId) { loadItem(itemId, true); } private void loadItem(Object itemId, boolean selectFirstTab) throws EntityNotFoundException { try { getEntityForm().getFormFieldSet().restoreIsReadOnly(); currentItemId = itemId; getResultsTable().clearSelection(); getResultsTable().select(currentItemId); BeanItem beanItem = getResultsTable().getContainerDataSource().getItem(itemId); getEntityForm().load((T) beanItem.getBean(), selectFirstTab); } finally { // in case entity is not found and exception occurs, still need to apply view mode getEntityForm().syncCrudActions(); } } @Override public void editOrViewPreviousItem() { Object previousItemId = getResultsTable().getContainerDataSource().prevItemId(currentItemId); if (previousItemId == null) { if (getEntityQuery().hasPreviousPage()) { getResultsTable().previousPage(); } else { getResultsTable().lastPage(); } previousItemId = getResultsTable().getContainerDataSource().lastItemId(); } if (previousItemId != null) { try { loadItem(previousItemId, false); } catch (EntityNotFoundException e) { // may occur if entity has been deleted by another user editOrViewPreviousItem(); } } } @Override public void editOrViewNextItem() { Object nextItemId = getResultsTable().getContainerDataSource().nextItemId(currentItemId); if (nextItemId == null) { if (getEntityQuery().hasNextPage()) { getResultsTable().nextPage(); } else { getResultsTable().firstPage(); } nextItemId = getResultsTable().getContainerDataSource().firstItemId(); } if (nextItemId != null) { try { loadItem(nextItemId, false); } catch (EntityNotFoundException e) { // may occur if entity has been deleted by another user editOrViewNextItem(); } } } private void deleteConfirmed() { Collection itemIds = (Collection) getResultsTable().getValue(); for (Object itemId : itemIds) { BeanItem<T> beanItem = getResultsTable().getContainerDataSource().getItem(itemId); T entity = beanItem.getBean(); preDelete(entity); if (getEntityDao() == null) { genericDao.remove(entity); } else { getEntityDao().remove(entity); } } showDeleteSuccessfulMessage(); // solves tricky ConcurrentModification bug where ContextMenu handler calls delete // but then search removes handler searchImpl(false); clearSelection(); syncCrudActions(); } /** * Shows notification message that a delete was successful. */ public void showDeleteSuccessfulMessage() { getMainApplication().showMessage(uiMessageSource.getMessage("crudResults.deleted")); } /** * Deletes selected entities but first pops up confirmation dialog. */ public void delete() { getMainApplication().showConfirmationDialog(new ConfirmDialog.Listener() { public void onClose(ConfirmDialog dialog) { if (dialog.isConfirmed()) { deleteConfirmed(); } } }); } /** * Lifecycle listener method called before delete. * * @param entity entity that will be deleted */ public void preDelete(T entity) { } /** * Listener method called when selection of result items changes. * * @param event ignored */ public void selectionChanged(Property.ValueChangeEvent event) { syncCrudActions(); } /** * Asks if this component is in view mode. In view-only mode, no CRUD actions may be performed. * * @return true if in view mode */ public boolean isViewMode() { return isViewMode; } /** * Sets whether or not this component is in view mode. In view-only mode, no CRUD actions may be performed. * * @param viewMode true if in view mode */ public void setViewMode(boolean viewMode) { isViewMode = viewMode; } /** * Synchronizes the states of CRUD action buttons and context menu items so that they are consistent * with security permissions, the number of rows selected (if any) and whether or not this component * is in view mode. */ public void syncCrudActions() { newButton.setVisible(!isViewMode()); editButton.setVisible(!isViewMode()); deleteButton.setVisible(!isViewMode()); newButton.setEnabled(isCreateAllowed()); Collection itemIds = (Collection) getSelectedValue(); getResultsTable().turnOnContentRefreshing(); int selectionItemsCount = itemIds.size(); if (selectionItemsCount == 1) { actionContextMenu.setActionEnabled("crudResults.view", isViewAllowed()); actionContextMenu.setActionEnabled("crudResults.edit", isEditAllowed() && !isViewMode()); actionContextMenu.setActionEnabled("crudResults.delete", isDeleteAllowed() && !isViewMode()); getResultsTable().removeActionHandler(actionContextMenu); getResultsTable().addActionHandler(actionContextMenu); editButton.setEnabled(isEditAllowed()); viewButton.setEnabled(isViewAllowed()); deleteButton.setEnabled(isDeleteAllowed()); } else if (selectionItemsCount > 1) { actionContextMenu.setActionEnabled("crudResults.view", false); actionContextMenu.setActionEnabled("crudResults.edit", false); actionContextMenu.setActionEnabled("crudResults.delete", isDeleteAllowed() && !isViewMode()); getResultsTable().removeActionHandler(actionContextMenu); getResultsTable().addActionHandler(actionContextMenu); editButton.setEnabled(false); viewButton.setEnabled(false); deleteButton.setEnabled(isDeleteAllowed()); } else { getResultsTable().removeActionHandler(actionContextMenu); editButton.setEnabled(false); viewButton.setEnabled(false); deleteButton.setEnabled(false); } } class DoubleClickListener implements ItemClickEvent.ItemClickListener { public void itemClick(ItemClickEvent event) { if (event.isDoubleClick()) { if (isViewAllowed()) { getEntityForm().setViewMode(!isEditAllowed() || isViewMode()); } editOrView(event.getItemId()); } } } }