Java tutorial
// This file is part of OpenTSDB. // Copyright (C) 2010 The OpenTSDB Authors. // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or (at your // option) any later version. 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 Lesser // General Public License for more details. You should have received a copy // of the GNU Lesser General Public License along with this program. If not, // see <http://www.gnu.org/licenses/>. package net.opentsdb.tsd.client; import java.util.ArrayList; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.DomEvent; import com.google.gwt.event.shared.EventHandler; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.Focusable; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.InlineLabel; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.SuggestBox; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; final class MetricForm extends HorizontalPanel implements Focusable { public static interface MetricChangeHandler extends EventHandler { void onMetricChange(MetricForm widget); } private static final String TSDB_ID_CLASS = "[-_./a-zA-Z0-9]"; private static final String TSDB_ID_RE = "^" + TSDB_ID_CLASS + "*$"; private static final String TSDB_TAGVALUE_RE = "^(\\*?" // a `*' wildcard or nothing + "|" + TSDB_ID_CLASS + "+(\\|" + TSDB_ID_CLASS + "+)*)$"; // `foo|bar|...' private final EventsHandler events_handler; private MetricChangeHandler metric_change_handler; private final CheckBox downsample = new CheckBox("Downsample"); private final ListBox downsampler = new ListBox(); private final ValidatedTextBox interval = new ValidatedTextBox(); private final CheckBox rate = new CheckBox("Rate"); private final CheckBox x1y2 = new CheckBox("Right Axis"); private final ListBox aggregators = new ListBox(); private final ValidatedTextBox metric = new ValidatedTextBox(); private final FlexTable tagtable = new FlexTable(); public MetricForm(final EventsHandler handler) { events_handler = handler; setupDownsampleWidgets(); downsample.addClickHandler(handler); downsampler.addChangeHandler(handler); interval.addBlurHandler(handler); interval.addKeyPressHandler(handler); rate.addClickHandler(handler); x1y2.addClickHandler(handler); aggregators.addChangeHandler(handler); metric.addBlurHandler(handler); metric.addKeyPressHandler(handler); { final EventsHandler metric_handler = new EventsHandler() { protected <H extends EventHandler> void onEvent(final DomEvent<H> event) { if (metric_change_handler != null) { metric_change_handler.onMetricChange(MetricForm.this); } } }; metric.addBlurHandler(metric_handler); metric.addKeyPressHandler(metric_handler); } metric.setValidationRegexp(TSDB_ID_RE); assembleUi(); } public String getMetric() { return metric.getText(); } public CheckBox x1y2() { return x1y2; } private void assembleUi() { setWidth("100%"); { // Left hand-side panel. final HorizontalPanel hbox = new HorizontalPanel(); final InlineLabel l = new InlineLabel(); l.setText("Metric:"); hbox.add(l); final SuggestBox suggest = RemoteOracle.newSuggestBox("metrics", metric); suggest.setLimit(40); hbox.add(suggest); hbox.setWidth("100%"); metric.setWidth("100%"); tagtable.setWidget(0, 0, hbox); tagtable.getFlexCellFormatter().setColSpan(0, 0, 3); addTag(null); tagtable.setText(1, 0, "Tags"); add(tagtable); } { // Right hand-side panel. final VerticalPanel vbox = new VerticalPanel(); { final HorizontalPanel hbox = new HorizontalPanel(); hbox.add(rate); hbox.add(x1y2); vbox.add(hbox); } { final HorizontalPanel hbox = new HorizontalPanel(); final InlineLabel l = new InlineLabel(); l.setText("Aggregator:"); hbox.add(l); hbox.add(aggregators); vbox.add(hbox); } vbox.add(downsample); { final HorizontalPanel hbox = new HorizontalPanel(); hbox.add(downsampler); hbox.add(interval); vbox.add(hbox); } add(vbox); } } public void setMetricChangeHandler(final MetricChangeHandler handler) { metric_change_handler = handler; } public void setAggregators(final ArrayList<String> aggs) { for (final String agg : aggs) { aggregators.addItem(agg); downsampler.addItem(agg); } setSelectedItem(aggregators, "sum"); setSelectedItem(downsampler, "avg"); } public boolean buildQueryString(final StringBuilder url) { final String metric = getMetric(); if (metric.isEmpty()) { return false; } url.append("&m="); url.append(selectedValue(aggregators)); if (downsample.getValue()) { url.append(':').append(interval.getValue()).append('-').append(selectedValue(downsampler)); } if (rate.getValue()) { url.append(":rate"); } url.append(':').append(metric); { final int ntags = getNumTags(); url.append('{'); for (int tag = 0; tag < ntags; tag++) { final String tagname = getTagName(tag); final String tagvalue = getTagValue(tag); if (tagname.isEmpty() || tagvalue.isEmpty()) { continue; } url.append(tagname).append('=').append(tagvalue).append(','); } final int last = url.length() - 1; if (url.charAt(last) == '{') { // There was no tag. url.setLength(last); // So remove the `{'. } else { // Need to replace the last `,' with a `}'. url.setCharAt(url.length() - 1, '}'); } } url.append("&o="); if (x1y2.getValue()) { url.append("axis x1y2"); } return true; } private int getNumTags() { return tagtable.getRowCount() - 1; } private String getTagName(final int i) { return ((SuggestBox) tagtable.getWidget(i + 1, 1)).getValue(); } private String getTagValue(final int i) { return ((SuggestBox) tagtable.getWidget(i + 1, 2)).getValue(); } private void setTagName(final int i, final String value) { ((SuggestBox) tagtable.getWidget(i + 1, 1)).setValue(value); } private void setTagValue(final int i, final String value) { ((SuggestBox) tagtable.getWidget(i + 1, 2)).setValue(value); } private void addTag(final String default_tagname) { final int row = tagtable.getRowCount(); final ValidatedTextBox tagname = new ValidatedTextBox(); final SuggestBox suggesttagk = RemoteOracle.newSuggestBox("tagk", tagname); final ValidatedTextBox tagvalue = new ValidatedTextBox(); final SuggestBox suggesttagv = RemoteOracle.newSuggestBox("tagv", tagvalue); tagname.setValidationRegexp(TSDB_ID_RE); tagvalue.setValidationRegexp(TSDB_TAGVALUE_RE); tagname.setWidth("100%"); tagvalue.setWidth("100%"); tagname.addBlurHandler(recompact_tagtable); tagname.addBlurHandler(events_handler); tagname.addKeyPressHandler(events_handler); tagvalue.addBlurHandler(recompact_tagtable); tagvalue.addBlurHandler(events_handler); tagvalue.addKeyPressHandler(events_handler); tagtable.setWidget(row, 1, suggesttagk); tagtable.setWidget(row, 2, suggesttagv); if (row > 2) { final Button remove = new Button("x"); remove.addClickHandler(removetag); tagtable.setWidget(row - 1, 0, remove); } if (default_tagname != null) { tagname.setText(default_tagname); tagvalue.setFocus(true); } } public void autoSuggestTag(final String tag) { // First try to see if the tag is already in the table. final int nrows = tagtable.getRowCount(); int unused_row = -1; for (int row = 1; row < nrows; row++) { final SuggestBox tagname = ((SuggestBox) tagtable.getWidget(row, 1)); final SuggestBox tagvalue = ((SuggestBox) tagtable.getWidget(row, 2)); final String thistag = tagname.getValue(); if (thistag.equals(tag)) { return; // This tag is already in the table. } if (thistag.isEmpty() && tagvalue.getValue().isEmpty()) { unused_row = row; } } if (unused_row >= 0) { ((SuggestBox) tagtable.getWidget(unused_row, 1)).setValue(tag); } else { addTag(tag); } } private final BlurHandler recompact_tagtable = new BlurHandler() { public void onBlur(final BlurEvent event) { int ntags = getNumTags(); // Is the first line empty? If yes, move everything up by 1 line. if (getTagName(0).isEmpty() && getTagValue(0).isEmpty()) { for (int tag = 1; tag < ntags; tag++) { final String tagname = getTagName(tag); final String tagvalue = getTagValue(tag); setTagName(tag - 1, tagname); setTagValue(tag - 1, tagvalue); } } // Try to remove empty lines from the tag table (but never remove the // first line or last line, even if they're empty). Walk the table // from the end to make it easier to delete rows as we iterate. for (int tag = ntags - 1; tag >= 1; tag--) { final String tagname = getTagName(tag); final String tagvalue = getTagValue(tag); if (tagname.isEmpty() && tagvalue.isEmpty()) { tagtable.removeRow(tag + 1); } } ntags = getNumTags(); // How many lines are left? // If the last line isn't empty, add another one. final String tagname = getTagName(ntags - 1); final String tagvalue = getTagValue(ntags - 1); if (!tagname.isEmpty() && !tagvalue.isEmpty()) { addTag(null); } } }; private final ClickHandler removetag = new ClickHandler() { public void onClick(final ClickEvent event) { if (!(event.getSource() instanceof Button)) { return; } final Widget source = (Widget) event.getSource(); final int ntags = getNumTags(); for (int tag = 1; tag < ntags; tag++) { if (source == tagtable.getWidget(tag + 1, 0)) { tagtable.removeRow(tag + 1); events_handler.onClick(event); break; } } } }; private void setupDownsampleWidgets() { downsampler.setEnabled(false); interval.setEnabled(false); interval.setMaxLength(5); interval.setVisibleLength(5); interval.setValue("10m"); interval.setValidationRegexp("^[1-9][0-9]*[smhdwy]$"); downsample.addClickHandler(new ClickHandler() { public void onClick(final ClickEvent event) { final boolean checked = ((CheckBox) event.getSource()).getValue(); downsampler.setEnabled(checked); interval.setEnabled(checked); if (checked) { downsampler.setFocus(true); } } }); } private static String selectedValue(final ListBox list) { // They should add return list.getValue(list.getSelectedIndex()); // this to GWT... } /** * If the given item is in the list, mark it as selected. * @param list The list to manipulate. * @param item The item to select if present. */ private void setSelectedItem(final ListBox list, final String item) { final int nitems = list.getItemCount(); for (int i = 0; i < nitems; i++) { if (item.equals(list.getValue(i))) { list.setSelectedIndex(i); return; } } } // ------------------- // // Focusable interface // // ------------------- // public int getTabIndex() { return metric.getTabIndex(); } public void setTabIndex(final int index) { metric.setTabIndex(index); } public void setAccessKey(final char key) { metric.setAccessKey(key); } public void setFocus(final boolean focused) { metric.setFocus(focused); } }