/* * Copyright 2015 JBoss, by Red Hat, 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. */ package org.uberfire.ext.widgets.common.client.tables; import com.google.gwt.cell.client.AbstractCell; import com.google.gwt.cell.client.Cell; import com.google.gwt.cell.client.Cell.Context; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Style.Cursor; import com.google.gwt.dom.client.Style.Position; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.safehtml.shared.SafeHtmlUtils; import com.google.gwt.user.cellview.client.AbstractCellTable; import com.google.gwt.user.cellview.client.Column; import com.google.gwt.user.cellview.client.Header; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Event.NativePreviewEvent; import com.google.gwt.user.client.Event.NativePreviewHandler; public class ResizableHeader<T> extends Header<String> { private static final int width = 20; private Column<T, ?> column = null; private AbstractCellTable<T> cellTable; private String title = ""; public ResizableHeader(String title, AbstractCellTable<T> cellTable, Column<T, ?> column) { super(new HeaderCell()); this.title = title; this.cellTable = cellTable; this.column = column; } @Override public String getValue() { return title; } @Override public void onBrowserEvent(Context context, Element target, NativeEvent event) { String eventType = event.getType(); if (eventType.equals("mousemove")) { new ColumnResizeHelper<T>(cellTable, column, target); } else { return; } } private void setCursor(Element element, Cursor cursor) { element.getStyle().setCursor(cursor); } static class HeaderCell extends AbstractCell<String> { public HeaderCell() { super("click", "mousedown", "mousemove", "dblclick"); } @Override public void render(Context context, String value, SafeHtmlBuilder sb) { sb.append(SafeHtmlUtils.fromString(value)); } } class ColumnResizeHelper<E> implements NativePreviewHandler { private HandlerRegistration handler; private AbstractCellTable<E> table; private Column<E, ?> col; private Element el; private boolean mousedown; private Element measuringElement; public ColumnResizeHelper(AbstractCellTable<E> table, Column<E, ?> col, Element el) { this.el = el; this.table = table; this.col = col; handler = Event.addNativePreviewHandler(this); } @SuppressWarnings("unchecked") @Override public void onPreviewNativeEvent(NativePreviewEvent event) { NativeEvent nativeEvent = event.getNativeEvent(); nativeEvent.preventDefault(); nativeEvent.stopPropagation(); String eventType = nativeEvent.getType(); int clientX = nativeEvent.getClientX(); if (eventType.equals("mousemove") && mousedown) { int absoluteLeft = el.getAbsoluteLeft(); int newWidth = clientX - absoluteLeft; newWidth = newWidth < width ? width : newWidth; table.setColumnWidth(col, newWidth + "px"); return; } if (eventType.equals("mousemove") || eventType.equals("mousedown")) { Element eventTargetEl = nativeEvent.getEventTarget().cast(); int absoluteLeft = eventTargetEl.getAbsoluteLeft(); int offsetWidth = eventTargetEl.getOffsetWidth(); if (clientX > absoluteLeft + offsetWidth - width) { if (eventType.equals("mousedown")) { mousedown = true; } else { setCursor(el, Cursor.COL_RESIZE); } } else { removeHandler(); return; } } else if (eventType.equals("mouseup")) { mousedown = false; } else if (eventType.equals("mouseout") && !mousedown) { removeHandler(); return; } if (eventType.equals("dblclick")) { // Get column nativeEvent.preventDefault(); nativeEvent.stopPropagation(); double max = 0; startMeasuring(); for (E t : table.getVisibleItems()) { Object value = col.getValue(t); SafeHtmlBuilder sb = new SafeHtmlBuilder(); Cell<Object> cell = (Cell<Object>) col.getCell(); cell.render(null, value, sb); max = Math.max(measureText(sb.toSafeHtml().asString()), max); } finishMeasuring(); table.setColumnWidth(col, (max + width) + "px"); removeHandler(); } } private void removeHandler() { handler.removeHandler(); setCursor(el, Cursor.DEFAULT); } private void startMeasuring() { Document document = Document.get(); measuringElement = document.createElement("div"); measuringElement.getStyle().setPosition(Position.ABSOLUTE); measuringElement.getStyle().setLeft(-1000, Unit.PX); measuringElement.getStyle().setTop(-1000, Unit.PX); document.getBody().appendChild(measuringElement); } private double measureText(String text) { measuringElement.setInnerHTML(text); return measuringElement.getOffsetWidth(); } private void finishMeasuring() { Document.get().getBody().removeChild(measuringElement); } } }