Greg Sheremeta has uploaded a new change for review. Change subject: userportal, webadmin: WIP - dont merge - new tooltip infrastructure ......................................................................
userportal, webadmin: WIP - dont merge - new tooltip infrastructure New tooltip infrastructure that works with Elements / Cells and uses PatternFly tooltips. Change-Id: Ie60ebe16e2d8830498fd819ffdb39aa043daadd2 Signed-off-by: Greg Sheremeta <gsher...@redhat.com> --- A frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/AbstractCell.java A frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/AbstractColumn.java A frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/ImageResourceCell.java A frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/TooltipCell.java A frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/tooltip/ElementTooltip.java M frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabClusterView.java A frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/table/column/CommentColumn2.java 7 files changed, 803 insertions(+), 3 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/97/36597/1 diff --git a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/AbstractCell.java b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/AbstractCell.java new file mode 100644 index 0000000..eee9491 --- /dev/null +++ b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/AbstractCell.java @@ -0,0 +1,160 @@ +package org.ovirt.engine.ui.common.widget.table.column; + +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Logger; + +import org.ovirt.engine.ui.common.widget.tooltip.ElementTooltip; + +import com.google.gwt.cell.client.ValueUpdater; +import com.google.gwt.dom.client.BrowserEvents; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.safehtml.shared.SafeHtml; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Timer; + +/** + * Cell that displays a tooltip when hovered over. Uses the jQuery-based Bootstrap / PatternFly Tooltip + * widget, {@link ElementTooltip}. + * + * @param <T> + */ +public abstract class AbstractCell<C> extends com.google.gwt.cell.client.AbstractCell<C> implements TooltipCell<C> { + + private static final Logger logger = Logger.getLogger(AbstractCell.class.getName()); + + private static Set<String> tooltipCellRegistry = new HashSet<String>(); + + private Timer initialShowTimer = null; + + private Timer debounceTimer = null; + private Element debouncingParent = null; + + /** + * Events to sink. By default, we only sink events that tooltips need -- 'mouseover' and 'mouseout'. + * Override this (and include addAll(super.getConsumedEvents())'s events!) if your cell needs to + * respond to additional events. + */ + @Override + public Set<String> getConsumedEvents() { + Set<String> set = new HashSet<String>(); + set.add(BrowserEvents.MOUSEOVER); + set.add(BrowserEvents.MOUSEOUT); + return set; + } + + public void onBrowserEvent(Context context, final Element parent, C value, final SafeHtml tooltipContent, + final NativeEvent event, ValueUpdater<C> valueUpdater) { + + if (BrowserEvents.MOUSEOVER.equals(event.getType())) { + + // debounce events + + if (debounceTimer != null && debounceTimer.isRunning()) { + if (debouncingParent.equals(parent)) { + logger.info("MOUSEOVER debounced"); //$NON-NLS-1$ + return; + } + else { + logger.info("MOUSEOVER canceled because MOUSEOVER someone else"); //$NON-NLS-1$ + // debouncing someone else. cancel + debouncingParent = null; + debounceTimer.cancel(); + debounceTimer = null; + } + } + + debouncingParent = parent; + debounceTimer = new Timer() { + @Override + public void run() { + logger.info("MOUSEOVER!!"); //$NON-NLS-1$ + handleMouseover(event.getType(), parent, tooltipContent); + debouncingParent = null; + debounceTimer = null; + } + }; + debounceTimer.schedule(200); + logger.info("MOUSEOVER timer"); //$NON-NLS-1$ + } + + if (BrowserEvents.MOUSEOUT.equals(event.getType())) { + if (debounceTimer != null && debounceTimer.isRunning()) { + logger.info("MOUSEOUT ignored"); //$NON-NLS-1$ + } + else { + logger.info("MOUSEOUT"); //$NON-NLS-1$ + handleMouseout(event.getType(), parent); + } + } + } + + private void handleMouseover(String eventType, Element parent, SafeHtml tooltipContent) { + logger.info("handleMouseover"); //$NON-NLS-1$ + if (tooltipContent == null || tooltipContent.asString().trim().isEmpty()) { + // there is no tooltip for this render. no-op. + logger.info("null or empty tooltip content"); //$NON-NLS-1$ + return; + } + + if (isTooltipConfigured(parent)) { + logger.info("tooltip already configured -- no-op"); //$NON-NLS-1$ + } + else { + + logger.info("tooltip not configured yet -- adding"); //$NON-NLS-1$ + final ElementTooltip tooltip = addTooltipToCell(tooltipContent, parent); + + // manually call show the first time, since we just added the tooltip + // in the handler. jQuery will handle it from here on out. + initialShowTimer = new Timer() { + @Override + public void run() { + logger.info("calling tooltip force show"); //$NON-NLS-1$ + tooltip.show(); + } + }; + + initialShowTimer.schedule(tooltip.getShowDelayMs()); + logger.info("scheduled a show"); //$NON-NLS-1$ + } + } + + private void handleMouseout(String eventType, Element parent) { + if (initialShowTimer != null && initialShowTimer.isRunning()) { + logger.info("**** CANCELING INITIAL SHOW TIMER ****"); //$NON-NLS-1$ + initialShowTimer.cancel(); + } + } + + private ElementTooltip addTooltipToCell(SafeHtml tooltipContent, Element parent) { + ElementTooltip tooltip = new ElementTooltip(parent); + tooltip.setContainer("body"); //$NON-NLS-1$ + + tooltip.setContent(tooltipContent); + tooltip.reconfigure(); + + String cellId = parent.getId(); + if (cellId == null || cellId.isEmpty()) { + cellId = DOM.createUniqueId(); + parent.setId(cellId); + } + + tooltipCellRegistry.add(cellId); + logger.finer("*** " + cellId); //$NON-NLS-1$ + + return tooltip; + } + + private boolean isTooltipConfigured(Element parent) { + String cellId = parent.getId(); + logger.finer("checking tooltip registry for " + cellId); //$NON-NLS-1$ + + if (cellId == null || cellId.isEmpty()) { + return false; + } + return tooltipCellRegistry.contains(cellId); + } + +} diff --git a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/AbstractColumn.java b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/AbstractColumn.java new file mode 100644 index 0000000..3c8a9d8 --- /dev/null +++ b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/AbstractColumn.java @@ -0,0 +1,59 @@ +package org.ovirt.engine.ui.common.widget.table.column; + +import com.google.gwt.cell.client.Cell.Context; +import com.google.gwt.cell.client.ValueUpdater; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.safehtml.shared.SafeHtml; +import com.google.gwt.user.cellview.client.Column; + +/** + * A {@link Column} that allows setting options for server-side and client-side sorting. + * Supports tooltips. Supports setting ids on its cells. + * + * @param <T> + * Table row data type. + * @param <C> + * Cell data type. + */ +public abstract class AbstractColumn<T, C> extends Column<T, C> { + + public AbstractColumn(TooltipCell<C> cell) { + super(cell); + } + + public TooltipCell<C> getCell() { + return (TooltipCell<C>) super.getCell(); + } + + /** + * <p> + * Implement this to return tooltip content for T object. You'll likely use some member(s) + * of T to build a tooltip. You could also use a constant if the tooltip is always the same + * for this column. + * </p> + * <p> + * The tooltip cell will then use this value when rendering the cell. + * </p> + * + * @param object + * @return tooltip content + */ + public abstract SafeHtml getTooltip(T object); + + /** + * This is copied from GWT's Column, but we also inject the tooltip content into the cell. + * TODO-GWT: make sure that this method is in sync with Column::onBroswerEvent. + */ + public void onBrowserEvent(Context context, Element elem, final T object, NativeEvent event) { + final int index = context.getIndex(); + ValueUpdater<C> valueUpdater = (getFieldUpdater() == null) ? null : new ValueUpdater<C>() { + @Override + public void update(C value) { + getFieldUpdater().update(index, object, value); + } + }; + getCell().onBrowserEvent(context, elem, getValue(object), /***/ getTooltip(object) /***/, event, valueUpdater); + } + +} diff --git a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/ImageResourceCell.java b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/ImageResourceCell.java new file mode 100644 index 0000000..5776c4a --- /dev/null +++ b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/ImageResourceCell.java @@ -0,0 +1,55 @@ +package org.ovirt.engine.ui.common.widget.table.column; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ImageResource; +import com.google.gwt.safehtml.client.SafeHtmlTemplates; +import com.google.gwt.safehtml.shared.SafeHtml; +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.safehtml.shared.SafeHtmlUtils; +import com.google.gwt.user.client.ui.AbstractImagePrototype; + +/** + * Cell that renders and ImageResource. Supports setting a style / class. Supports tooltips. + * TODO: this will replace StyledImageResourceCell. Delete it and change references. + */ +public class ImageResourceCell extends AbstractCell<ImageResource> implements HasStyleClass { + + interface CellTemplate extends SafeHtmlTemplates { + @Template("<div style=\"{0}\" class=\"{1}\">{2}</div>") + SafeHtml imageContainerWithStyleClass(String style, String styleClass, SafeHtml imageHtml); + } + + private String style = "line-height: 100%; text-align: center; vertical-align: middle;"; //$NON-NLS-1$ + private String styleClass = ""; //$NON-NLS-1$ + + private static CellTemplate template; + + public ImageResourceCell() { + super(); + + // Delay cell template creation until the first time it's needed + if (template == null) { + template = GWT.create(CellTemplate.class); + } + } + + @Override + public void render(Context context, ImageResource value, SafeHtmlBuilder sb) { + if (value != null) { + sb.append(template.imageContainerWithStyleClass( + style, + styleClass, + SafeHtmlUtils.fromTrustedString(AbstractImagePrototype.create(value).getHTML()))); + } + } + + public void setStyle(String style) { + this.style = style; + } + + @Override + public void setStyleClass(String styleClass) { + this.styleClass = styleClass == null ? "" : styleClass; //$NON-NLS-1$ + } + +} diff --git a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/TooltipCell.java b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/TooltipCell.java new file mode 100644 index 0000000..43e8fdd --- /dev/null +++ b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/table/column/TooltipCell.java @@ -0,0 +1,23 @@ +package org.ovirt.engine.ui.common.widget.table.column; + +import com.google.gwt.cell.client.Cell; +import com.google.gwt.cell.client.ValueUpdater; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.safehtml.shared.SafeHtml; + +/** + * A Cell with a tooltip. All Cells should implement this by extending ovirt's AbstractCell. + * + * @param <C> cell render type + */ +public interface TooltipCell<C> extends Cell<C> { + + /** + * Called by AbstractColumn when an event occurs in a Cell. The only difference from GWT's native + * Column is that here we ask the column to provide us a tooltip value in addition to the cell's + * C value. + */ + public void onBrowserEvent(Context context, final Element parent, C value, final SafeHtml tooltipContent, + final NativeEvent event, ValueUpdater<C> valueUpdater); +} diff --git a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/tooltip/ElementTooltip.java b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/tooltip/ElementTooltip.java new file mode 100644 index 0000000..318d462 --- /dev/null +++ b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/tooltip/ElementTooltip.java @@ -0,0 +1,445 @@ +package org.ovirt.engine.ui.common.widget.tooltip; + +import java.util.logging.Logger; + +import org.gwtbootstrap3.client.ui.base.HasHover; +import org.gwtbootstrap3.client.ui.base.HasId; +import org.gwtbootstrap3.client.ui.constants.Placement; +import org.gwtbootstrap3.client.ui.constants.Trigger; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.safehtml.shared.SafeHtml; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.Timer; + +/** + * <p> + * Implementation of Bootstrap tooltips that are capable of wrapping non-GWT elements. + * This is designed primarily for use in grids, but could be used in any Cell. Since + * Cells don't support Widget's event system, we must use a reaper timer to check for + * when a tooltip's Element has been detached from the document. + * </p> + * <p> + * Bootstrap tooltips use jQuery under the hood. jQuery must be present for this widget + * to function. + * </p> + * <p> + * <br/> + * See also: <br/> + * <a href="http://getbootstrap.com/javascript/#tooltips">Bootstrap Documentation</a> + * <br/> + * See also: <br/> + * {@link Tooltip} + * </p> + * <p> + * ** Must call reconfigure() after altering any/all Tooltips! + * </p> + * + * @author Joshua Godi + * @author Pontus Enmark + * @author Greg Sheremeta + */ +public class ElementTooltip implements HasId, HasHover { + private static final String TOGGLE = "toggle"; //$NON-NLS-1$ + private static final String SHOW = "show"; //$NON-NLS-1$ + private static final String HIDE = "hide"; //$NON-NLS-1$ + private static final String DESTROY = "destroy"; //$NON-NLS-1$ + + // Defaults from http://getbootstrap.com/javascript/#tooltips + private boolean isAnimated = true; + private boolean isHTML = true; + private Placement placement = Placement.BOTTOM; + private Trigger trigger = Trigger.HOVER; + private SafeHtml content = null; + private String container = null; + private final String selector = null; + + private int hideDelayMs = 1000; + private int showDelayMs = 500; + private int reaperInterval = 7000; + private Timer reaperTimer = null; + + private Element element; + private String id; + + private static final Logger logger = Logger.getLogger(ElementTooltip.class.getName()); + + /** + * Creates an empty ElementTooltip + */ + public ElementTooltip() { + } + + /** + * Creates the tooltip around this element + * + * @param e Element for the tooltip + */ + public ElementTooltip(final Element e) { + setElement(e); + } + + /** + * Sets the Element that this tooltip hovers over. + * @param e Element for the tooltip + */ + public void setElement(final Element e) { + element = e; + bindJavaScriptEvents(element); + } + + /** + * Return the Element that this tooltip hovers over. + */ + public Element getElement() { + return element; + } + + /** + * Return the reaper interval. + */ + public int getReaperInterval() { + return reaperInterval; + } + + /** + * Sets the reaper interval. + */ + public void setReaperInterval(int reaperInterval) { + this.reaperInterval = reaperInterval; + } + + /** + * Starts a timer that checks for this tooltip to be hanging open. + * This can happen when the Element or one of its ancestors is detached from the document. + * Such detaching happens frequently when Grids are refreshed -- GWT replaces an entire + * grid row, but doesn't actually delete the row. The row just gets removed from its parent + * table. To detect this, we search up the ancestor tree for a null ancestor. + */ + public void startHangingTooltipReaper() { + if (reaperTimer != null && reaperTimer.isRunning()) { + return; + } + + reaperTimer = new Timer() { + + @Override + public void run() { + if (hasNullAncestor()) { + logger.info("tooltip for cell " + element.getId() + " dying"); //$NON-NLS-1$ //$NON-NLS-2$ + ElementTooltip.this.destroy(); + // cancel this timer since this tooltip is dead + cancel(); + } + else { + logger.info("tooltip for cell " + element.getId() + " lives on"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + }; + + reaperTimer.scheduleRepeating(getReaperInterval()); + } + + /** + * Check up this Elements ancestor tree, and return true if we find a null parent. + * @return true if a null parent is found, false if this Element has body as an ancestor + * (meaning it's still attached). + */ + public boolean hasNullAncestor() { + Element parent = element.getParentElement(); + while (parent != null) { + if (parent.getTagName().equalsIgnoreCase("body")) { //$NON-NLS-1$ + return false; + } + parent = parent.getParentElement(); + } + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public void setId(final String id) { + this.id = id; + if (element != null) { + element.setId(id); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getId() { + return (element == null) ? id : element.getId(); + } + + @Override + public void setIsAnimated(final boolean isAnimated) { + this.isAnimated = isAnimated; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isAnimated() { + return isAnimated; + } + + /** + * {@inheritDoc} + */ + @Override + public void setIsHtml(final boolean isHTML) { + this.isHTML = isHTML; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isHtml() { + return isHTML; + } + + /** + * {@inheritDoc} + */ + @Override + public void setPlacement(final Placement placement) { + this.placement = placement; + } + + /** + * {@inheritDoc} + */ + @Override + public Placement getPlacement() { + return placement; + } + + /** + * {@inheritDoc} + */ + @Override + public void setTrigger(final Trigger trigger) { + this.trigger = trigger; + } + + /** + * {@inheritDoc} + */ + @Override + public Trigger getTrigger() { + return trigger; + } + + @Override + public void setShowDelayMs(final int showDelayMs) { + this.showDelayMs = showDelayMs; + } + + /** + * {@inheritDoc} + */ + @Override + public int getShowDelayMs() { + return showDelayMs; + } + + /** + * {@inheritDoc} + */ + @Override + public void setHideDelayMs(final int hideDelayMs) { + this.hideDelayMs = hideDelayMs; + } + + /** + * {@inheritDoc} + */ + @Override + public int getHideDelayMs() { + return hideDelayMs; + } + + /** + * {@inheritDoc} + */ + @Override + public void setContainer(final String container) { + this.container = container; + } + + /** + * {@inheritDoc} + */ + @Override + public String getContainer() { + return container; + } + + /** + * Sets the tooltip's HTML content + */ + public void setContent(final SafeHtml content) { + this.isHTML = true; + this.content = content; + } + + /** + * Reconfigures the tooltip, must be called when altering any tooltip after it has already been shown + */ + public void reconfigure() { + // First destroy the old tooltip + destroy(); + + // Setup the new tooltip + if (container != null && selector != null) { + logger.info("tooltip mode 1 on element id " + element.getId()); //$NON-NLS-1$ + tooltip(element, isAnimated, isHTML, placement.getCssName(), selector, content.asString(), + trigger.getCssName(), showDelayMs, hideDelayMs, container); + } else if (container != null) { + logger.info("tooltip mode 2 on element id " + element.getId()); //$NON-NLS-1$ + tooltip(element, isAnimated, isHTML, placement.getCssName(), content.asString(), + trigger.getCssName(), showDelayMs, hideDelayMs, container); + } else if (selector != null) { + logger.info("tooltip mode 3 on element id " + element.getId()); //$NON-NLS-1$ + tooltip(element, isAnimated, isHTML, placement.getCssName(), selector, content.asString(), + trigger.getCssName(), showDelayMs, hideDelayMs); + } else { + logger.info("tooltip mode 4 on element id " + element.getId()); //$NON-NLS-1$ + tooltip(element, isAnimated, isHTML, placement.getCssName(), content.asString(), + trigger.getCssName(), showDelayMs, hideDelayMs); + } + } + + /** + * Toggle the Tooltip to either show/hide + */ + public void toggle() { + call(element, TOGGLE); + } + + /** + * Force show the Tooltip. If you must, be sure to wrap this call in a Timer delay + * of getShowDelayMs() ms. + */ + public void show() { + logger.info("tooltip show on element id " + element.getId()); //$NON-NLS-1$ + call(element, SHOW); + } + + /** + * Force hide the Tooltip + */ + public void hide() { + call(element, HIDE); + } + + /** + * Force the Tooltip to be destroyed + */ + public void destroy() { + call(element, DESTROY); + } + + /** + * Called when the tooltip is shown. + * Starts the hanging tooltip reaper timer. + * + * @param evt Event + */ + protected void onShow(final Event evt) { + if (hasNullAncestor()) { + logger.info("dirty tooltip -- destroying"); //$NON-NLS-1$ + hide(); + destroy(); + } + else { + logger.info("showing"); //$NON-NLS-1$ + } + logger.info("starting reaper"); //$NON-NLS-1$ + this.startHangingTooltipReaper(); + } + + private native void call(final Element e, final String arg) /*-{ + $wnd.jQuery(e).tooltip(arg); + }-*/; + + // @formatter:off + private native void bindJavaScriptEvents(final Element e) /*-{ + var target = this; + var $tooltip = $wnd.jQuery(e); + + $tooltip.on('show.bs.tooltip', function (evt) { + targ...@org.ovirt.engine.ui.common.widget.tooltip.ElementTooltip::onShow(Lcom/google/gwt/user/client/Event;)(evt); + }); + }-*/; + + private native void tooltip(Element e, boolean animation, boolean html, String placement, String selector, + String content, String trigger, int showDelay, int hideDelay, String container) /*-{ + $wnd.jQuery(e).tooltip({ + animation: animation, + html: html, + placement: placement, + selector: selector, + title: content, + trigger: trigger, + delay: { + show: showDelay, + hide: hideDelay + }, + container: container + }); + }-*/; + + private native void tooltip(Element e, boolean animation, boolean html, String placement, + String content, String trigger, int showDelay, int hideDelay, String container) /*-{ + $wnd.jQuery(e).tooltip({ + animation: animation, + html: html, + placement: placement, + title: content, + trigger: trigger, + delay: { + show: showDelay, + hide: hideDelay + }, + container: container + }); + }-*/; + + private native void tooltip(Element e, boolean animation, boolean html, String placement, String selector, + String content, String trigger, int showDelay, int hideDelay) /*-{ + $wnd.jQuery(e).tooltip({ + animation: animation, + html: html, + placement: placement, + selector: selector, + title: content, + trigger: trigger, + delay: { + show: showDelay, + hide: hideDelay + } + }); + }-*/; + + private native void tooltip(Element e, boolean animation, boolean html, String placement, + String content, String trigger, int showDelay, int hideDelay) /*-{ + console.log($wnd.jQuery(e).tooltip({ + animation: animation, + html: html, + placement: placement, + title: content, + trigger: trigger, + delay: { + show: showDelay, + hide: hideDelay + } + })); + }-*/; +} diff --git a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabClusterView.java b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabClusterView.java index f4823cc..3ed044b 100644 --- a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabClusterView.java +++ b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabClusterView.java @@ -24,7 +24,7 @@ import org.ovirt.engine.ui.webadmin.widget.action.WebAdminButtonDefinition; import org.ovirt.engine.ui.webadmin.widget.action.WebAdminImageButtonDefinition; import org.ovirt.engine.ui.webadmin.widget.action.WebAdminMenuBarButtonDefinition; -import org.ovirt.engine.ui.webadmin.widget.table.column.CommentColumn; +import org.ovirt.engine.ui.webadmin.widget.table.column.CommentColumn2; import com.google.gwt.core.client.GWT; import com.google.inject.Inject; @@ -57,8 +57,11 @@ nameColumn.makeSortable(ClusterConditionFieldAutoCompleter.NAME); getTable().addColumn(nameColumn, constants.nameCluster(), "150px"); //$NON-NLS-1$ - CommentColumn<VDSGroup> commentColumn = new CommentColumn<VDSGroup>(); - getTable().addColumnWithHtmlHeader(commentColumn, commentColumn.getHeaderHtml(), "30px"); //$NON-NLS-1$ + CommentColumn2<VDSGroup> commentColumn = new CommentColumn2<VDSGroup>(); + // TODO: add support for tooltips on headers + // TODO: don't hardcode "Comment" -- use image + // getTable().addColumnWithHtmlHeader(commentColumn, commentColumn.getHeaderHtml(), "30px"); //$NON-NLS-1$ + getTable().addColumn(commentColumn, "Comment", "50px"); //$NON-NLS-1$ //$NON-NLS-2$ if (ApplicationModeHelper.getUiMode() != ApplicationMode.GlusterOnly) { TextColumnWithTooltip<VDSGroup> dataCenterColumn = new TextColumnWithTooltip<VDSGroup>() { diff --git a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/table/column/CommentColumn2.java b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/table/column/CommentColumn2.java new file mode 100644 index 0000000..3bf83d5 --- /dev/null +++ b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/table/column/CommentColumn2.java @@ -0,0 +1,55 @@ +package org.ovirt.engine.ui.webadmin.widget.table.column; + +import org.ovirt.engine.core.common.businessentities.Commented; +import org.ovirt.engine.ui.common.CommonApplicationResources; +import org.ovirt.engine.ui.common.widget.table.column.AbstractColumn; +import org.ovirt.engine.ui.common.widget.table.column.ImageResourceCell; +import org.ovirt.engine.ui.common.widget.table.column.TooltipCell; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ImageResource; +import com.google.gwt.safehtml.shared.SafeHtml; +import com.google.gwt.safehtml.shared.SafeHtmlUtils; + +/** + * Column that render a comment image (yellow paper icon) that, when hovered, shows the + * actual comment in a tooltip. + * + * @param <T> row type + */ +public class CommentColumn2<T extends Commented> extends AbstractColumn<T, ImageResource> { + + private static final CommonApplicationResources RESOURCES = GWT.create(CommonApplicationResources.class); + + public CommentColumn2() { + super(new ImageResourceCell()); + } + + public CommentColumn2(TooltipCell<ImageResource> cell) { + super(cell); + } + + /** + * Using some row value of type T, build an ImageResource to render in this column. + * + * @see com.google.gwt.user.cellview.client.Column#getValue(java.lang.Object) + */ + @Override + public ImageResource getValue(T value) { + if (value.getComment() != null && !value.getComment().isEmpty()) { + return RESOURCES.commentImage(); + } + return null; + } + + /** + * Using some row value of type T, build a SafeHtml tooltip to render when this column is moused over. + * + * @see org.ovirt.engine.ui.common.widget.table.column.AbstractColumn#getTooltip(java.lang.Object) + */ + @Override + public SafeHtml getTooltip(T value) { + return SafeHtmlUtils.fromString(value.getComment()); + } + +} -- To view, visit http://gerrit.ovirt.org/36597 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ie60ebe16e2d8830498fd819ffdb39aa043daadd2 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Greg Sheremeta <gsher...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches