From 72a24a21a65cadf700fbecd9312f0f42e6a46c66 Mon Sep 17 00:00:00 2001 From: Giancarlo Panichi Date: Wed, 25 Jun 2014 17:16:45 +0000 Subject: [PATCH] Start ColumnMapping dev git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/portlets/user/tabular-data-column-widget@97811 82a268e6-3cf1-43bd-a215-b396298e98cf --- .../client/custom/IconButton.html | 4 + .../client/custom/IconButton.java | 47 +++++ .../client/custom/IconButtonAppearance.java | 17 ++ .../custom/IconButtonAppearanceDefault.java | 75 ++++++++ .../client/custom/IconButtonStyle.css | 17 ++ .../client/mapping/ColumnMappingData.java | 63 +++++++ .../client/mapping/ColumnMappingDialog.java | 102 +++++++++++ .../client/mapping/ColumnMappingList.java | 52 ++++++ .../client/mapping/ColumnMappingListener.java | 32 ++++ .../client/mapping/ColumnMappingPanel.java | 164 ++++++++++++++++++ .../client/resources/ResourceBundle.java | 10 ++ .../td/columnwidget/client/resources/add.png | Bin 0 -> 660 bytes .../columnwidget/client/resources/add_32.png | Bin 0 -> 1486 bytes .../columnwidget/client/resources/delete.png | Bin 0 -> 614 bytes .../client/resources/delete_32.png | Bin 0 -> 1360 bytes .../td/columnwidget/client/resources/add.png | Bin 0 -> 660 bytes .../columnwidget/client/resources/add_32.png | Bin 0 -> 1486 bytes .../columnwidget/client/resources/delete.png | Bin 0 -> 614 bytes .../client/resources/delete_32.png | Bin 0 -> 1360 bytes 19 files changed, 583 insertions(+) create mode 100644 src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButton.html create mode 100644 src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButton.java create mode 100644 src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButtonAppearance.java create mode 100644 src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButtonAppearanceDefault.java create mode 100644 src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButtonStyle.css create mode 100644 src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingData.java create mode 100644 src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingDialog.java create mode 100644 src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingList.java create mode 100644 src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingListener.java create mode 100644 src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingPanel.java create mode 100644 src/main/java/org/gcube/portlets/user/td/columnwidget/client/resources/add.png create mode 100644 src/main/java/org/gcube/portlets/user/td/columnwidget/client/resources/add_32.png create mode 100644 src/main/java/org/gcube/portlets/user/td/columnwidget/client/resources/delete.png create mode 100644 src/main/java/org/gcube/portlets/user/td/columnwidget/client/resources/delete_32.png create mode 100644 src/main/resources/org/gcube/portlets/user/td/columnwidget/client/resources/add.png create mode 100644 src/main/resources/org/gcube/portlets/user/td/columnwidget/client/resources/add_32.png create mode 100644 src/main/resources/org/gcube/portlets/user/td/columnwidget/client/resources/delete.png create mode 100644 src/main/resources/org/gcube/portlets/user/td/columnwidget/client/resources/delete_32.png diff --git a/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButton.html b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButton.html new file mode 100644 index 0000000..9b36b96 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButton.html @@ -0,0 +1,4 @@ + +
+
+
\ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButton.java b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButton.java new file mode 100644 index 0000000..04e14a8 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButton.java @@ -0,0 +1,47 @@ +package org.gcube.portlets.user.td.columnwidget.client.custom; + + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.HasClickHandlers; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.resources.client.ImageResource; +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.user.client.Event; +import com.sencha.gxt.core.client.dom.XDOM; +import com.sencha.gxt.widget.core.client.Component; + +/** + * + * @author "Giancarlo Panichi" + * g.panichi@isti.cnr.it + * + */ +public class IconButton extends Component implements HasClickHandlers { + + private IconButtonAppearance appearance; + + public IconButton() { + this((IconButtonAppearance) GWT.create(IconButtonAppearanceDefault.class)); + } + + public IconButton(IconButtonAppearance appearance) { + this.appearance = appearance; + + SafeHtmlBuilder sb = new SafeHtmlBuilder(); + this.appearance.render(sb); + + setElement(XDOM.create(sb.toSafeHtml())); + sinkEvents(Event.ONCLICK); + } + + public HandlerRegistration addClickHandler(ClickHandler handler) { + return addDomHandler(handler, ClickEvent.getType()); + } + + + public void setIcon(ImageResource icon) { + appearance.onUpdateIcon(getElement(), icon); + } +} diff --git a/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButtonAppearance.java b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButtonAppearance.java new file mode 100644 index 0000000..5687497 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButtonAppearance.java @@ -0,0 +1,17 @@ +package org.gcube.portlets.user.td.columnwidget.client.custom; + +import com.google.gwt.resources.client.ImageResource; +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.sencha.gxt.core.client.dom.XElement; + +/** + * + * @author "Giancarlo Panichi" + * g.panichi@isti.cnr.it + * + */ +public interface IconButtonAppearance { + void render(SafeHtmlBuilder sb); + void onUpdateIcon(XElement parent, ImageResource icon); +} + diff --git a/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButtonAppearanceDefault.java b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButtonAppearanceDefault.java new file mode 100644 index 0000000..cd7a024 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButtonAppearanceDefault.java @@ -0,0 +1,75 @@ +package org.gcube.portlets.user.td.columnwidget.client.custom; + + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Element; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; +import com.google.gwt.resources.client.ImageResource; +import com.google.gwt.safehtml.shared.SafeHtml; +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.user.client.ui.Image; +import com.sencha.gxt.core.client.XTemplates; +import com.sencha.gxt.core.client.dom.XElement; + +/** + * + * @author "Giancarlo Panichi" + * g.panichi@isti.cnr.it + * + */ +public class IconButtonAppearanceDefault implements IconButtonAppearance { + + public interface Template extends XTemplates { + @XTemplate(source = "IconButton.html") + SafeHtml template(IconButtonStyle style); + } + + public interface IconButtonStyle extends CssResource { + @ClassName("iconButton") + public String getIconButton(); + + @ClassName("iconButtonImage") + public String getIconButtonImage(); + + @ClassName("iconButtonRef") + public String getIconButtonRef(); + + } + + private final IconButtonStyle style; + private final Template template; + + public interface IconButtonResources extends ClientBundle { + public static final IconButtonResources INSTANCE = GWT.create(IconButtonResources.class); + + @Source("IconButtonStyle.css") + IconButtonStyle style(); + } + + public IconButtonAppearanceDefault() { + this(IconButtonResources.INSTANCE); + } + + public IconButtonAppearanceDefault(IconButtonResources resources) { + this.style = resources.style(); + this.style.ensureInjected(); + + this.template = GWT.create(Template.class); + } + + + + public void onUpdateIcon(XElement parent, ImageResource icon) { + XElement element = parent.selectNode("." + style.getIconButtonImage()); + Image image=new Image(icon); + Element img=image.getElement(); + img.setClassName(style.getIconButtonRef()); + element.appendChild(img); + + } + + public void render(SafeHtmlBuilder sb) { + sb.append(template.template(style)); + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButtonStyle.css b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButtonStyle.css new file mode 100644 index 0000000..98ef72c --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/custom/IconButtonStyle.css @@ -0,0 +1,17 @@ +@CHARSET "UTF-8"; + +.iconButton { + border: none; + font-size: 12px; + margin: 0px; + padding: 0px; +} + +.iconButton .iconButtonImage { + vertical-align: center; +} + +.iconButtonRef { + vertical-align: center; + cursor: pointer; +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingData.java b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingData.java new file mode 100644 index 0000000..d655b9e --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingData.java @@ -0,0 +1,63 @@ +package org.gcube.portlets.user.td.columnwidget.client.mapping; + +import java.io.Serializable; + + +import org.gcube.portlets.user.td.gwtservice.shared.tr.DimensionRow; + +/** + * + * @author "Giancarlo Panichi" + * email: g.panichi@isti.cnr.it + * + */ +public class ColumnMappingData implements Serializable { + + private static final long serialVersionUID = 733237646914552402L; + + protected DimensionRow sourceArg; + protected DimensionRow targetArg; + + /** + * + */ + public ColumnMappingData(){ + + } + + /** + * + * @param sourceArg + * @param targetArg + */ + public ColumnMappingData(DimensionRow sourceArg, DimensionRow targetArg){ + this.sourceArg=sourceArg; + this.targetArg=targetArg; + } + + public DimensionRow getSourceArg() { + return sourceArg; + } + + public void setSourceArg(DimensionRow sourceArg) { + this.sourceArg = sourceArg; + } + + public DimensionRow getTargetArg() { + return targetArg; + } + + public void setTargetArg(DimensionRow targetArg) { + this.targetArg = targetArg; + } + + @Override + public String toString() { + return "ColumnMappingData [sourceArg=" + sourceArg + ", targetArg=" + + targetArg + "]"; + } + + + + +} diff --git a/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingDialog.java b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingDialog.java new file mode 100644 index 0000000..80e0e4c --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingDialog.java @@ -0,0 +1,102 @@ +package org.gcube.portlets.user.td.columnwidget.client.mapping; + +import java.util.ArrayList; + +import org.gcube.portlets.user.td.columnwidget.client.resources.ResourceBundle; +import org.gcube.portlets.user.td.gwtservice.shared.tr.ColumnData; +import org.gcube.portlets.user.td.gwtservice.shared.tr.TabResource; +import org.gcube.portlets.user.td.widgetcommonevent.shared.TRId; + +import com.allen_sauer.gwt.log.client.Log; +import com.google.web.bindery.event.shared.EventBus; +import com.sencha.gxt.widget.core.client.Window; +import com.sencha.gxt.widget.core.client.event.SelectEvent; +import com.sencha.gxt.widget.core.client.event.SelectEvent.SelectHandler; + +public class ColumnMappingDialog extends Window { + protected String WIDTH = "650px"; + protected String HEIGHT = "530px"; + + protected TRId trId; + protected ColumnData selectedColumn; + protected TabResource dimensionTR; + protected ColumnData columnReference; + protected EventBus eventBus; + + protected ArrayList listeners; + + public ColumnMappingDialog(TRId trId, ColumnData selectedColumn, + TabResource dimensionTR, ColumnData columnReference, + EventBus eventBus) { + this.trId = trId; + this.selectedColumn = selectedColumn; + this.dimensionTR = dimensionTR; + this.columnReference= columnReference; + this.eventBus = eventBus; + Log.debug("ColumnMappingDialog: [trId:" + trId + + ", selectedColumn:" + selectedColumn + ", dimensionTR:" + + dimensionTR + ", columnReference:" + columnReference + + ", eventBus:" + eventBus + + "]"); + listeners=new ArrayList(); + + initWindow(); + ColumnMappingPanel columnMappingPanel = new ColumnMappingPanel(this, + trId, selectedColumn, + dimensionTR, columnReference, + eventBus); + add(columnMappingPanel); + } + + protected void initWindow() { + setWidth(WIDTH); + setHeight(HEIGHT); + setBodyBorder(false); + setResizable(false); + setHeadingText("Column Mapping"); + setClosable(true); + setModal(true); + forceLayoutOnResize = true; + getHeader().setIcon(ResourceBundle.INSTANCE.replaceBatch()); + + } + + /** + * {@inheritDoc} + */ + @Override + protected void initTools() { + super.initTools(); + + closeBtn.addSelectHandler(new SelectHandler() { + + public void onSelect(SelectEvent event) { + close(); + } + }); + + } + + protected void close() { + hide(); + + } + + /** + * + * @param listener + */ + public void addColumnMappingListener(ColumnMappingListener listener) { + listeners.add(listener); + } + + /** + * + * @param listener + */ + public void removeColumnMappingListener(ColumnMappingListener listener) { + listeners.remove(listener); + } + + +} diff --git a/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingList.java b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingList.java new file mode 100644 index 0000000..5d29982 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingList.java @@ -0,0 +1,52 @@ +package org.gcube.portlets.user.td.columnwidget.client.mapping; + +import java.io.Serializable; +import java.util.ArrayList; + +import org.gcube.portlets.user.td.gwtservice.shared.tr.DimensionRow; + +/** + * + * @author "Giancarlo Panichi" + * email: g.panichi@isti.cnr.it + * + */ +public class ColumnMappingList implements Serializable{ + + private static final long serialVersionUID = 733237646914552402L; + + protected ArrayList mapping; + + /** + * + */ + public ColumnMappingList(){ + + } + + /** + * + * @param mapping + */ + public ColumnMappingList(ArrayList mapping){ + this.mapping=mapping; + + } + + public ArrayList getMapping() { + return mapping; + } + + public void setMapping(ArrayList mapping) { + this.mapping = mapping; + } + + @Override + public String toString() { + return "ColumnMappingList [mapping=" + mapping + "]"; + } + + + + +} diff --git a/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingListener.java b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingListener.java new file mode 100644 index 0000000..2761f10 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingListener.java @@ -0,0 +1,32 @@ +package org.gcube.portlets.user.td.columnwidget.client.mapping; + + + + +/** + * + * @author "Giancarlo Panichi" + * g.panichi@isti.cnr.it + * + */ +public interface ColumnMappingListener { + + /** + * Called when created column mapping without errors + */ + public void selectedColumnMappingListener(ColumnMappingList columnMappingData); + + /** + * Called when the column mapping operation is aborted by the user. + */ + public void abortedColumnMapping(); + + /** + * Called when the something in the wizard is failed. + * + * @param reason + * @param detail + */ + public void failedColumnMapping(String reason, String detail); + +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingPanel.java b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingPanel.java new file mode 100644 index 0000000..5316b46 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/mapping/ColumnMappingPanel.java @@ -0,0 +1,164 @@ +package org.gcube.portlets.user.td.columnwidget.client.mapping; + +import org.gcube.portlets.user.td.columnwidget.client.custom.IconButton; +import org.gcube.portlets.user.td.columnwidget.client.dimension.DimensionRowSelectionListener; +import org.gcube.portlets.user.td.columnwidget.client.resources.ResourceBundle; +import org.gcube.portlets.user.td.gwtservice.shared.tr.ColumnData; +import org.gcube.portlets.user.td.gwtservice.shared.tr.DimensionRow; +import org.gcube.portlets.user.td.gwtservice.shared.tr.TabResource; +import org.gcube.portlets.user.td.widgetcommonevent.shared.TRId; + +import com.allen_sauer.gwt.log.client.Log; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.web.bindery.event.shared.EventBus; +import com.sencha.gxt.core.client.dom.ScrollSupport.ScrollMode; +import com.sencha.gxt.widget.core.client.FramedPanel; +import com.sencha.gxt.widget.core.client.container.HBoxLayoutContainer; +import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer; +import com.sencha.gxt.widget.core.client.form.TextField; + +/** + * + * @author "Giancarlo Panichi" + * email: g.panichi@isti.cnr.it + * + */ +public class ColumnMappingPanel extends FramedPanel implements + DimensionRowSelectionListener { + protected String WIDTH = "560px"; + protected String HEIGHT = "520px"; + + protected ColumnMappingPanel thisPanel; + + protected ColumnMappingDialog parent; + protected TRId trId; + protected ColumnData selectedColumn; + protected TabResource dimensionTR; + protected ColumnData columnReference; + protected EventBus eventBus; + + protected VerticalLayoutContainer vert; + protected String itemIdSourceValueArg; + protected String itemIdTargetValueArg; + protected String itemIdBtnAdd; + protected String itemIdBtnDel; + + protected ColumnMappingList columnMappingList; + + /** + * + * + * @param parent + * @param trId + * @param selectedColumn + * @param dimensionTR + * @param columnReference + * @param eventBus + */ + public ColumnMappingPanel(ColumnMappingDialog parent, TRId trId, + ColumnData selectedColumn, TabResource dimensionTR, + ColumnData columnReference, EventBus eventBus) { + this.parent = parent; + this.trId = trId; + this.selectedColumn = selectedColumn; + this.dimensionTR = dimensionTR; + this.columnReference = columnReference; + this.eventBus = eventBus; + thisPanel=this; + Log.debug("ColumnMappingPanel: [parent:" + parent + " , trId:" + trId + + ", selectedColumn:" + selectedColumn + ", dimensionTR:" + + dimensionTR + ", columnReference:" + columnReference + + ", eventBus:" + eventBus + + "]"); + columnMappingList=new ColumnMappingList(); + + + } + + + protected void setup(){ + itemIdSourceValueArg = "SourceArg" + selectedColumn.getName(); + itemIdTargetValueArg = "TargetArg" + selectedColumn.getName(); + + + vert = new VerticalLayoutContainer(); + vert.setScrollMode(ScrollMode.AUTO); + vert.setAdjustForScroll(true); + + final HBoxLayoutContainer horiz = new HBoxLayoutContainer(); + + + + final TextField sourceValueArg = new TextField(); + sourceValueArg.setItemId(itemIdSourceValueArg); + + + final TextField targetValueArg = new TextField(); + targetValueArg.setItemId(itemIdTargetValueArg); + + final IconButton btnAdd = new IconButton(); + btnAdd.setItemId(itemIdBtnAdd); + btnAdd.setIcon(ResourceBundle.INSTANCE.add()); + btnAdd.addClickHandler(new ClickHandler() { + + public void onClick(ClickEvent event) { + Log.debug("Clicked btnAdd"); + addColumnMappingData(); + thisPanel.forceLayout(); + vert.forceLayout(); + + } + }); + btnAdd.setVisible(false); + + final IconButton btnDel = new IconButton(); + btnDel.setItemId(itemIdBtnDel); + btnDel.setIcon(ResourceBundle.INSTANCE.delete()); + btnDel.addClickHandler(new ClickHandler() { + + public void onClick(ClickEvent event) { + Log.debug("Clicked btnDel"); + vert.remove(horiz); + if (vert.getWidgetCount() == 0) { + setup(); + } else { + + } + thisPanel.forceLayout(); + vert.forceLayout(); + + } + }); + btnDel.setVisible(false); + + + add(vert); + } + + protected void addColumnMappingData(){ + + } + + + @Override + public void selectedDimensionRow(DimensionRow dimensionRow) { + // TODO Auto-generated method stub + + } + + @Override + public void abortedDimensionRowSelection() { + // TODO Auto-generated method stub + + } + + @Override + public void failedDimensionRowSelection(String reason, String detail) { + // TODO Auto-generated method stub + + } + + + +} diff --git a/src/main/java/org/gcube/portlets/user/td/columnwidget/client/resources/ResourceBundle.java b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/resources/ResourceBundle.java index ce42270..bbca134 100644 --- a/src/main/java/org/gcube/portlets/user/td/columnwidget/client/resources/ResourceBundle.java +++ b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/resources/ResourceBundle.java @@ -89,7 +89,17 @@ public interface ResourceBundle extends ClientBundle { @Source("codelist-link-break_32.png") ImageResource codelistLinkBreak32(); + @Source("add.png") + ImageResource add(); + @Source("add_32.png") + ImageResource add32(); + + @Source("delete.png") + ImageResource delete(); + + @Source("delete_32.png") + ImageResource delete32(); } \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/td/columnwidget/client/resources/add.png b/src/main/java/org/gcube/portlets/user/td/columnwidget/client/resources/add.png new file mode 100644 index 0000000000000000000000000000000000000000..6b1ab4733aeb46cc540c336985d2501f587bc1a5 GIT binary patch literal 660 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 Sl2Y9O0000cG#j=lT?7W*brGf@qBq@y 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 Sl2Y9O0000