
com.sibvisions.rad.ui.vaadin.impl.control.VaadinTreeGrid Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jvxvaadin-server Show documentation
Show all versions of jvxvaadin-server Show documentation
Vaadin UI implementation for JVx
The newest version!
/*
* Copyright 2012 SIB Visions GmbH
*
* 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.
*
*
* History
*
* 25.04.2013 - [SW] - creation
*/
package com.sibvisions.rad.ui.vaadin.impl.control;
import java.util.ArrayList;
import java.util.List;
import jvx.rad.model.ColumnDefinition;
import jvx.rad.model.IDataBook;
import jvx.rad.model.IDataPage;
import jvx.rad.model.IDataRow;
import jvx.rad.model.ModelException;
import jvx.rad.model.TreePath;
import jvx.rad.model.datatype.StringDataType;
import jvx.rad.model.ui.ICellEditor;
import jvx.rad.model.ui.ICellEditorHandler;
import jvx.rad.model.ui.ICellEditorListener;
import jvx.rad.model.ui.IControl;
import jvx.rad.ui.IImage;
import jvx.rad.ui.control.ICellFormat;
import jvx.rad.ui.control.ICellFormatter;
import jvx.rad.ui.control.INodeFormatter;
import jvx.rad.ui.control.ITree;
import jvx.rad.ui.event.UIMouseEvent;
import jvx.rad.util.ExceptionHandler;
import jvx.rad.util.TranslationMap;
import com.sibvisions.rad.model.mem.DataRow;
import com.sibvisions.rad.ui.vaadin.ext.VaadinUtil;
import com.sibvisions.rad.ui.vaadin.ext.data.DummySetter;
import com.sibvisions.rad.ui.vaadin.ext.data.PassThroughValueProvider;
import com.sibvisions.rad.ui.vaadin.ext.grid.field.CellEditorField;
import com.sibvisions.rad.ui.vaadin.ext.treegrid.databinding.TreePathDataProvider;
import com.sibvisions.rad.ui.vaadin.ext.treegrid.databinding.ValueFromTreePathValueProvider;
import com.sibvisions.rad.ui.vaadin.ext.ui.ExtendedTreeGrid;
import com.sibvisions.rad.ui.vaadin.impl.VaadinComponent;
import com.sibvisions.rad.ui.vaadin.impl.celleditor.IVaadinCellEditorHandler;
import com.sibvisions.rad.ui.vaadin.impl.celleditor.ShortcutHandler;
import com.sibvisions.rad.ui.vaadin.impl.celleditor.VaadinTextCellEditor;
import com.vaadin.event.Action;
import com.vaadin.event.ContextClickEvent;
import com.vaadin.event.ContextClickEvent.ContextClickListener;
import com.vaadin.event.selection.SelectionEvent;
import com.vaadin.event.selection.SelectionListener;
import com.vaadin.server.Sizeable.Unit;
import com.vaadin.ui.Component;
import com.vaadin.ui.Grid.Column;
import com.vaadin.ui.Grid.SelectionMode;
import com.vaadin.ui.components.grid.EditorCancelEvent;
import com.vaadin.ui.components.grid.EditorCancelListener;
import com.vaadin.ui.components.grid.EditorOpenEvent;
import com.vaadin.ui.components.grid.EditorOpenListener;
import com.vaadin.ui.components.grid.EditorSaveEvent;
import com.vaadin.ui.components.grid.EditorSaveListener;
import com.vaadin.ui.renderers.HtmlRenderer;
/**
* The VaadinTree
is the ITree
implementation for
* vaadin.
*
* @author Stefan Wurm
*/
public class VaadinTreeGrid extends VaadinComponent
implements ITree,
ContextClickListener,
SelectionListener,
Runnable,
ICellFormatter,
ICellFormatterEditorListener,
INodeFormatter,
EditorCancelListener,
EditorSaveListener,
EditorOpenListener
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class members
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/** The IDataBook to be shown. */
private IDataBook[] dataBooks = null;
/** The selfjoined databooks. */
private IDataBook selfJoinedDataBook = null;
/** The selected data book. **/
private IDataBook currentDataBook = null;
/** The selected tree path. **/
private TreePath selectedTreePath = null;
/** The maximum length of not selfjoined databooks. */
private int maxLength = 0;
/** The cellFormatListener. */
private ICellFormatter cellFormatter = null;
/** The Node Formatter. **/
private INodeFormatter nodeFormatter = null;
/** The translation mapping. */
private TranslationMap translation = null;
/** Tells, if notifyRepaint is called the first time. */
private boolean bFirstNotifyRepaintCall = true;
/** Ignoring Events. */
private volatile boolean bIgnoreEvent = false;
/** If the table is editable. **/
private boolean editable = false;
/** whether the translation is enabled. */
private boolean bTranslationEnabled = true;
/** the visible column. */
private Column column = null;
/** the cell editor. */
private SelfContainedCellEditor selfContainedCellEditor = new SelfContainedCellEditor();
/** whether to commit the previous editor. */
private boolean commitPreviousEditor = false;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Initialization
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* New instance of VaadinTree
.
*/
public VaadinTreeGrid()
{
super(new ExtendedTreeGrid());
resource.setHeaderVisible(false);
resource.setSelectionMode(SelectionMode.SINGLE);
resource.setStyleName("jvxtreegrid");
resource.getEditor().setBuffered(false);
resource.getEditor().addCancelListener(this);
resource.getEditor().addOpenListener(this);
resource.getEditor().addSaveListener(this);
resource.addContextClickListener(this);
resource.addSelectionListener(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Interface implementation
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* {@inheritDoc}
*/
public void contextClick(ContextClickEvent pEvent)
{
if (eventMouseReleased != null)
{
getFactory().synchronizedDispatchEvent(eventMouseReleased,
new UIMouseEvent(this,
UIMouseEvent.MOUSE_RELEASED,
System.currentTimeMillis(),
UIMouseEvent.BUTTON2_MASK,
pEvent.getClientX(),
pEvent.getClientY(),
pEvent.getMouseEventDetails().isDoubleClick() ? 2 : 1,
true));
}
}
/**
* {@inheritDoc}
*/
public void run()
{
bFirstNotifyRepaintCall = true;
if (!bIgnoreEvent && dataBooks != null)
{
try
{
bIgnoreEvent = true;
resource.getDataProvider().refreshAll();
updateSelectionFromDataBooks();
}
catch (ModelException e)
{
ExceptionHandler.raise(e);
}
finally
{
bIgnoreEvent = false;
}
}
}
/**
* {@inheritDoc}
*/
public IDataBook[] getDataBooks()
{
return dataBooks;
}
/**
* {@inheritDoc}
*/
public void setDataBooks(IDataBook... pDataBooks)
{
if (dataBooks != null)
{
for (int i = 0; i < dataBooks.length; i++)
{
dataBooks[i].removeControl(this);
}
}
if (pDataBooks == null || pDataBooks.length == 0)
{
dataBooks = null;
}
else
{
dataBooks = pDataBooks;
}
if (dataBooks != null)
{
for (int i = 0; i < dataBooks.length; i++)
{
dataBooks[i].addControl(this);
}
IDataBook dataBook = dataBooks[dataBooks.length - 1];
if (dataBook.isSelfJoined())
{
selfJoinedDataBook = dataBook;
maxLength = dataBooks.length - 1;
}
else
{
maxLength = dataBooks.length;
}
}
resource.setDataProvider(new TreePathDataProvider(dataBooks));
column = resource.addColumn(PassThroughValueProvider.getInstance());
column.setId("column");
column.setEditorComponent(
new CellEditorField(selfContainedCellEditor.createCellEditor(), this, null, null),
DummySetter.getInstance());
column.setRenderer(
new ValueFromTreePathValueProvider(this),
new HtmlRenderer());
notifyRepaint();
}
/**
* {@inheritDoc}
*/
public IDataBook getActiveDataBook()
{
return currentDataBook;
}
/**
* {@inheritDoc}
*/
public void notifyRepaint()
{
if (bFirstNotifyRepaintCall && !bIgnoreEvent) // Check additionally if editing is started, to prevent immediate closing editor
{
bFirstNotifyRepaintCall = false;
getFactory().invokeLater(this);
}
}
/**
* {@inheritDoc}
*/
public void editingStarted()
{
}
/**
* {@inheritDoc}
*/
public void editingComplete(String pCompleteType)
{
if (pCompleteType == ICellEditorListener.ESCAPE_KEY)
{
cancelEditing();
}
else
{
try
{
saveEditing();
}
catch (ModelException ex)
{
cancelEditing();
ExceptionHandler.raise(ex);
}
}
}
/**
* {@inheritDoc}
*/
public boolean isSavingImmediate()
{
return false;
}
/**
* {@inheritDoc}
*/
public IControl getControl()
{
return this;
}
/**
* {@inheritDoc}
*/
public void startEditing()
{
if (isEditable())
{
resource.select(null);
}
}
/**
* {@inheritDoc}
*/
public void saveEditing() throws ModelException
{
if (!bIgnoreEvent)
{
cancelEditing();
}
}
/**
* {@inheritDoc}
*/
public void cancelEditing()
{
if (!bIgnoreEvent)
{
resource.getEditor().cancel();
}
}
/**
* {@inheritDoc}
*/
public void setTranslation(TranslationMap pTranslation)
{
if (translation != pTranslation)
{
translation = pTranslation;
try
{
saveEditing();
}
catch (ModelException e)
{
cancelEditing();
}
notifyRepaint();
}
}
/**
* {@inheritDoc}
*/
public TranslationMap getTranslation()
{
return translation;
}
/**
* {@inheritDoc}
*/
public void setTranslationEnabled(boolean pEnabled)
{
bTranslationEnabled = pEnabled;
}
/**
* {@inheritDoc}
*/
public boolean isTranslationEnabled()
{
return bTranslationEnabled;
}
/**
* {@inheritDoc}
*/
public String translate(String pText)
{
if (bTranslationEnabled && translation != null)
{
return translation.translate(pText);
}
else
{
return pText;
}
}
/**
* {@inheritDoc}
*/
public ICellFormatter getCellFormatter()
{
return cellFormatter;
}
/**
* {@inheritDoc}
*/
public void setCellFormatter(ICellFormatter pCellFormatter)
{
cellFormatter = pCellFormatter;
}
/**
* {@inheritDoc}
*/
public ICellFormat getCellFormat(IDataBook pDataBook, IDataPage pDataPage, IDataRow pDataRow, String pColumnName, int pRow, int pColumn) throws Throwable
{
if (cellFormatter == null)
{
return null;
}
return cellFormatter.getCellFormat(pDataBook, pDataPage, pDataRow, pColumnName, pRow, pColumn);
}
/**
* {@inheritDoc}
*/
public IImage getNodeImage(IDataBook pDataBook, IDataPage pDataPage, IDataRow pDataRow, String pColumnName, int pRow, boolean pExpanded, boolean pLeaf)
{
if (nodeFormatter == null)
{
return null;
}
return nodeFormatter.getNodeImage(pDataBook, pDataPage, pDataRow, pColumnName, pRow, pExpanded, pLeaf);
}
/**
* {@inheritDoc}
*/
public boolean isDetectEndNode()
{
return false;
}
/**
* {@inheritDoc}
*/
public void setDetectEndNode(boolean pDetectEndNode)
{
// TODO Disabled because not supported by the Vaadin model.
// Or at least I could not make it work, the TreeGrid doesn't
// behave very nicely when the model returns hasChildren() true
// but there no actual children.
}
/**
* {@inheritDoc}
*/
public boolean isEditable()
{
return editable;
}
/**
* {@inheritDoc}
*/
public void setEditable(boolean pEditable)
{
editable = pEditable;
resource.getEditor().setEnabled(true);
}
/**
* {@inheritDoc}
*/
public INodeFormatter getNodeFormatter()
{
return nodeFormatter;
}
/**
* {@inheritDoc}
*/
public void setNodeFormatter(INodeFormatter pNodeFormatter)
{
nodeFormatter = pNodeFormatter;
}
/**
* {@inheritDoc}
*/
public void selectionChange(SelectionEvent pEvent)
{
if (bIgnoreEvent)
{
return;
}
try
{
bIgnoreEvent = true;
if (pEvent.getFirstSelectedItem().isPresent())
{
selectedTreePath = pEvent.getFirstSelectedItem().get();
selectPathInDataBooks();
selfContainedCellEditor.updateBinding(currentDataBook, getColumnName(currentDataBook));
}
}
catch (Throwable thr)
{
bIgnoreEvent = false;
notifyRepaint();
ExceptionHandler.raise(thr);
}
finally
{
bIgnoreEvent = false;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Overwritten methods
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* {@inheritDoc}
*/
@Override
public void setWidthFull()
{
if (VaadinUtil.isParentWidthDefined(resource))
{
VaadinUtil.setComponentWidth(resource, 100, Unit.PERCENTAGE);
}
else
{
setWidthUndefined();
}
}
/**
* {@inheritDoc}
*/
@Override
public void setHeightFull()
{
if (VaadinUtil.isParentHeightDefined(resource))
{
VaadinUtil.setComponentHeight(resource, 100, Unit.PERCENTAGE);
}
else
{
setHeightUndefined();
}
}
/**
* {@inheritDoc}
*/
@Override
public void setWidthUndefined()
{
VaadinUtil.setComponentWidth(resource, VaadinUtil.SIZE_UNDEFINED, Unit.PIXELS);
}
/**
* {@inheritDoc}
*/
@Override
public void setHeightUndefined()
{
VaadinUtil.setComponentHeight(resource, VaadinUtil.SIZE_UNDEFINED, Unit.PIXELS);
}
/**
* {@inheritDoc}
*/
@Override
public void onEditorOpen(EditorOpenEvent pEvent)
{
if (commitPreviousEditor)
{
bIgnoreEvent = true;
selfContainedCellEditor.commit();
bIgnoreEvent = false;
}
if (pEvent.getBean() != null)
{
// We have to correct the selection.
resource.select(pEvent.getBean());
}
selfContainedCellEditor.discard();
commitPreviousEditor = true;
}
/**
* {@inheritDoc}
*/
@Override
public void onEditorSave(EditorSaveEvent pEvent)
{
selfContainedCellEditor.commit();
commitPreviousEditor = false;
}
/**
* {@inheritDoc}
*/
@Override
public void onEditorCancel(EditorCancelEvent pEvent)
{
if (bIgnoreEvent)
{
return;
}
selfContainedCellEditor.discard();
commitPreviousEditor = false;
}
/**
* {@inheritDoc}
*/
public boolean isMouseEventOnSelectedCell()
{
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// User-defined methods
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Handles the key actions.
*
* @param pAction the key action.
*/
public void handleAction(Action pAction)
{
if (isEditable())
{
if (pAction == ShortcutHandler.ACTION_TAB)
{
editingComplete(ICellEditorListener.TAB_KEY);
}
else if (pAction == ShortcutHandler.ACTION_SHIFT_TAB)
{
editingComplete(ICellEditorListener.SHIFT_TAB_KEY);
}
else if (pAction == ShortcutHandler.ACTION_ENTER
|| pAction == ShortcutHandler.ACTION_ALT_ENTER
|| pAction == ShortcutHandler.ACTION_CTRL_ENTER
|| pAction == ShortcutHandler.ACTION_META_ENTER)
{
editingComplete(ICellEditorListener.ENTER_KEY);
}
else if (pAction == ShortcutHandler.ACTION_SHIFT_ENTER)
{
editingComplete(ICellEditorListener.SHIFT_ENTER_KEY);
}
else if (pAction == ShortcutHandler.ACTION_ESCAPE)
{
editingComplete(ICellEditorListener.ESCAPE_KEY);
}
else if (pAction == ShortcutHandler.ACTION_EDIT)
{
startEditing();
}
}
}
/**
* Gets the required column name form the given {@link IDataBook}.
*
* @param pDataBook the {@link IDataBook} from which to get the column name.
* @return the column name from the {@link IDataBook}.
* @throws ModelException when accessing the information of the
* {@link IDataBook} failed.
*/
private String getColumnName(IDataBook pDataBook) throws ModelException
{
return pDataBook.getRowDefinition().getColumnView(ITree.class).getColumnName(0);
}
/**
* Updates the current selection from the databooks.
*
* @throws ModelException if accessing the databooks failed.
*/
private void updateSelectionFromDataBooks() throws ModelException
{
List treePaths = new ArrayList();
TreePath lastTreePath = null;
IDataBook lastDataBook = null;
for (IDataBook dataBook : dataBooks)
{
if (dataBook.getSelectedRow() >= 0)
{
if (lastTreePath == null)
{
lastTreePath = new TreePath(dataBook.getSelectedRow());
}
else
{
int[] pieces = new int[lastTreePath.length() + 1];
System.arraycopy(lastTreePath.toArray(), 0, pieces, 0, lastTreePath.length());
pieces[pieces.length - 1] = dataBook.getSelectedRow();
lastTreePath = new TreePath(pieces);
}
treePaths.add(lastTreePath);
lastDataBook = dataBook;
}
}
if (lastDataBook != null && lastDataBook.isSelfJoined())
{
TreePath treePath = lastDataBook.getTreePath();
if (treePath != null)
{
for (int piece : treePath.toArray())
{
int[] pieces = new int[lastTreePath.length() + 1];
System.arraycopy(lastTreePath.toArray(), 0, pieces, 0, lastTreePath.length());
pieces[pieces.length - 1] = piece;
lastTreePath = new TreePath(pieces);
}
}
}
resource.getSelectionModel().deselectAll();
for (TreePath treePath : treePaths)
{
resource.expand(treePath.getParentPath());
resource.select(treePath);
}
}
/**
* Select the path in the databooks.
*
* @throws ModelException if selecting path in databooks fails
*/
private void selectPathInDataBooks() throws ModelException
{
if (selectedTreePath != null)
{
int selLength = Math.min(maxLength, selectedTreePath.length());
for (int i = 0; i < selLength; i++)
{
dataBooks[i].setSelectedDataPageRow(selectedTreePath.get(i));
currentDataBook = dataBooks[i];
}
for (int i = selLength; i < maxLength; i++)
{
dataBooks[i].setSelectedRow(-1);
}
if (selfJoinedDataBook != null)
{
int pathLen = selectedTreePath.length() - dataBooks.length;
TreePath treePath = new TreePath();
int selRow = -1;
if (pathLen >= 0)
{
for (int i = 0; i < pathLen; i++)
{
treePath = treePath.getChildPath(selectedTreePath.get(dataBooks.length - 1 + i));
}
selRow = selectedTreePath.getLast();
}
selfJoinedDataBook.setTreePath(treePath);
selfJoinedDataBook.setSelectedDataPageRow(selRow);
currentDataBook = selfJoinedDataBook;
}
}
}
//****************************************************************
// Subclass definition
//****************************************************************
/**
* The {@link SelfContainedCellEditor} is a simple container which allows to
* abuse the celleditor.
*
* @author Robert Zenz
*/
private static final class SelfContainedCellEditor
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Initialization
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/** The current {@link ICellEditor}. */
private ICellEditor cellEditor = null;
/** The current {@link ICellEditorHandler}. */
private ICellEditorHandler cellEditorHandler = null;
/** The internal {@link IDataRow}. */
private IDataRow dataRow = null;
/** The parent column name. */
private String parentColumnName = null;
/** The parent {@link IDataBook}. */
private IDataBook parentDataBook = null;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Initialization
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Creates a new instance of {@link SelfContainedCellEditor}.
*/
public SelfContainedCellEditor()
{
super();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// User-defined methods
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Commits the changes.
*/
public void commit()
{
try
{
cellEditorHandler.saveEditing();
parentDataBook.setValue(parentColumnName, dataRow.getValue("VALUE"));
}
catch (ModelException e)
{
throw new RuntimeException(e);
}
}
/**
* Creates the {@link ICellEditor} for use.
*
* @return the {@link ICellEditor} for use.
*/
public ICellEditor createCellEditor()
{
if (dataRow == null)
{
dataRow = new DataRow();
try
{
dataRow.getRowDefinition().addColumnDefinition(new ColumnDefinition("VALUE", new StringDataType()));
}
catch (ModelException e)
{
throw new RuntimeException(e);
}
}
if (cellEditor == null)
{
cellEditor = new VaadinTextCellEditor()
{
@Override
public IVaadinCellEditorHandler createCellEditorHandler(ICellEditorListener pCellEditorListener, IDataRow pDataRow, String pColumnName)
{
cellEditorHandler = super.createCellEditorHandler(pCellEditorListener, dataRow, "VALUE");
return (IVaadinCellEditorHandler)cellEditorHandler;
}
};
}
return cellEditor;
}
/**
* Discards the changes.
*/
public void discard()
{
if (parentDataBook == null || dataRow == null)
{
return;
}
try
{
dataRow.setValue("VALUE", parentDataBook.getValue(parentColumnName));
cellEditorHandler.cancelEditing();
}
catch (ModelException e)
{
throw new RuntimeException(e);
}
}
/**
* Updates the bindings.
*
* @param pDataBook the new parent {@link IDataBook}.
* @param pColumnName the new parent column name.
*/
public void updateBinding(IDataBook pDataBook, String pColumnName)
{
parentDataBook = pDataBook;
parentColumnName = pColumnName;
}
} // SelfContainedCellEditor
} // VaadinTreeGrid
© 2015 - 2025 Weber Informatics LLC | Privacy Policy