// Copyright (C) 2014 The Android Open Source Project // // 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 com.google.gerrit.client; import com.google.gerrit.client.ui.NavigationTable; import com.google.gerrit.client.ui.OnEditEnabler; import com.google.gerrit.client.ui.SmallHeading; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyPressEvent; import com.google.gwt.event.dom.client.KeyPressHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.FocusWidget; import com.google.gwt.user.client.ui.HasEnabled; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.ImageResourceRenderer; import com.google.gwtexpui.globalkey.client.NpTextBox; import java.util.ArrayList; import java.util.List; public class StringListPanel extends FlowPanel implements HasEnabled { private final StringListTable t; private HorizontalPanel titlePanel; protected final HorizontalPanel buttonPanel; private final Button deleteButton; private Image info; protected FocusWidget widget; public StringListPanel(String title, List<String> fieldNames, FocusWidget w, boolean autoSort) { widget = w; if (title != null) { titlePanel = new HorizontalPanel(); SmallHeading titleLabel = new SmallHeading(title); titlePanel.add(titleLabel); add(titlePanel); } t = new StringListTable(fieldNames, autoSort); add(t); buttonPanel = new HorizontalPanel(); buttonPanel.setStyleName(Gerrit.RESOURCES.css().stringListPanelButtons()); deleteButton = new Button(Gerrit.C.stringListPanelDelete()); deleteButton.setEnabled(false); deleteButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { widget.setEnabled(true); t.deleteChecked(); } }); buttonPanel.add(deleteButton); add(buttonPanel); } public void display(List<List<String>> values) { t.display(values); } public void setInfo(String msg) { if (info == null && titlePanel != null) { info = new Image(Gerrit.RESOURCES.info()); titlePanel.add(info); } if (info != null) { info.setTitle(msg); } } public List<List<String>> getValues() { return t.getValues(); } public List<String> getValues(int i) { List<List<String>> allValuesList = getValues(); List<String> singleValueList = new ArrayList<>(allValuesList.size()); for (List<String> values : allValuesList) { singleValueList.add(values.get(i)); } return singleValueList; } private class StringListTable extends NavigationTable<List<String>> { private final Button addButton; private final List<NpTextBox> inputs; private final boolean autoSort; StringListTable(List<String> names, boolean autoSort) { this.autoSort = autoSort; addButton = new Button(new ImageResourceRenderer().render(Gerrit.RESOURCES.listAdd())); addButton.setTitle(Gerrit.C.stringListPanelAdd()); OnEditEnabler e = new OnEditEnabler(addButton); inputs = new ArrayList<>(); FlexCellFormatter fmt = table.getFlexCellFormatter(); fmt.addStyleName(0, 0, Gerrit.RESOURCES.css().iconHeader()); fmt.addStyleName(0, 0, Gerrit.RESOURCES.css().leftMostCell()); for (int i = 0; i < names.size(); i++) { fmt.addStyleName(0, i + 1, Gerrit.RESOURCES.css().dataHeader()); table.setText(0, i + 1, names.get(i)); NpTextBox input = new NpTextBox(); input.setVisibleLength(35); input.addKeyPressHandler(new KeyPressHandler() { @Override public void onKeyPress(KeyPressEvent event) { if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) { widget.setEnabled(true); add(); } } }); inputs.add(input); fmt.addStyleName(1, i + 1, Gerrit.RESOURCES.css().dataHeader()); table.setWidget(1, i + 1, input); e.listenTo(input); } addButton.setEnabled(false); addButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { widget.setEnabled(true); add(); } }); fmt.addStyleName(1, 0, Gerrit.RESOURCES.css().iconHeader()); fmt.addStyleName(1, 0, Gerrit.RESOURCES.css().leftMostCell()); table.setWidget(1, 0, addButton); if (!autoSort) { fmt.addStyleName(0, names.size() + 1, Gerrit.RESOURCES.css().iconHeader()); fmt.addStyleName(0, names.size() + 2, Gerrit.RESOURCES.css().iconHeader()); fmt.addStyleName(1, names.size() + 1, Gerrit.RESOURCES.css().iconHeader()); fmt.addStyleName(1, names.size() + 2, Gerrit.RESOURCES.css().iconHeader()); } } void display(List<List<String>> values) { for (int row = 2; row < table.getRowCount(); row++) { table.removeRow(row--); } int row = 2; for (List<String> v : values) { populate(row, v); row++; } updateNavigationLinks(); } List<List<String>> getValues() { List<List<String>> values = new ArrayList<>(); for (int row = 2; row < table.getRowCount(); row++) { values.add(getRowItem(row)); } return values; } @Override protected List<String> getRowItem(int row) { List<String> v = new ArrayList<>(); for (int i = 0; i < inputs.size(); i++) { v.add(table.getText(row, i + 1)); } return v; } private void populate(final int row, List<String> values) { FlexCellFormatter fmt = table.getFlexCellFormatter(); fmt.addStyleName(row, 0, Gerrit.RESOURCES.css().iconCell()); fmt.addStyleName(row, 0, Gerrit.RESOURCES.css().leftMostCell()); CheckBox checkBox = new CheckBox(); checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() { @Override public void onValueChange(ValueChangeEvent<Boolean> event) { enableDelete(); } }); table.setWidget(row, 0, checkBox); for (int i = 0; i < values.size(); i++) { fmt.addStyleName(row, i + 1, Gerrit.RESOURCES.css().dataCell()); table.setText(row, i + 1, values.get(i)); } if (!autoSort) { fmt.addStyleName(row, values.size() + 1, Gerrit.RESOURCES.css().iconCell()); fmt.addStyleName(row, values.size() + 2, Gerrit.RESOURCES.css().dataCell()); Image down = new Image(Gerrit.RESOURCES.arrowDown()); down.setTitle(Gerrit.C.stringListPanelDown()); down.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { moveDown(row); } }); table.setWidget(row, values.size() + 1, down); Image up = new Image(Gerrit.RESOURCES.arrowUp()); up.setTitle(Gerrit.C.stringListPanelUp()); up.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { moveUp(row); } }); table.setWidget(row, values.size() + 2, up); } } @Override protected void onCellSingleClick(Event event, int row, int column) { if (column == inputs.size() + 1 && row >= 2 && row < table.getRowCount() - 2) { moveDown(row); } else if (column == inputs.size() + 2 && row > 2) { moveUp(row); } } void moveDown(int row) { if (row < table.getRowCount() - 1) { swap(row, row + 1); } } void moveUp(int row) { if (row > 2) { swap(row - 1, row); } } void swap(int row1, int row2) { List<String> value = getRowItem(row1); List<String> nextValue = getRowItem(row2); populate(row1, nextValue); populate(row2, value); updateNavigationLinks(); widget.setEnabled(true); } private void updateNavigationLinks() { if (!autoSort) { for (int row = 2; row < table.getRowCount(); row++) { table.getWidget(row, inputs.size() + 1).setVisible( row < table.getRowCount() - 1); table.getWidget(row, inputs.size() + 2).setVisible(row > 2); } } } void add() { List<String> values = new ArrayList<>(); for (NpTextBox input : inputs) { values.add(input.getValue().trim()); input.setValue(""); } insert(values); } void insert(List<String> v) { int insertPos = table.getRowCount(); if (autoSort) { for (int row = 1; row < table.getRowCount(); row++) { int compareResult = v.get(0).compareTo(table.getText(row, 1)); if (compareResult < 0) { insertPos = row; break; } else if (compareResult == 0) { return; } } } table.insertRow(insertPos); populate(insertPos, v); updateNavigationLinks(); } void enableDelete() { for (int row = 2; row < table.getRowCount(); row++) { if (((CheckBox) table.getWidget(row, 0)).getValue()) { deleteButton.setEnabled(true); return; } } deleteButton.setEnabled(false); } void deleteChecked() { deleteButton.setEnabled(false); for (int row = 2; row < table.getRowCount(); row++) { if (((CheckBox) table.getWidget(row, 0)).getValue()) { table.removeRow(row--); } } updateNavigationLinks(); } @Override protected void onOpenRow(int row) { } @Override protected Object getRowItemKey(List<String> item) { return item.get(0); } void setEnabled(boolean enabled) { addButton.setVisible(enabled); for (NpTextBox input : inputs) { input.setEnabled(enabled); } for (int row = 2; row < table.getRowCount(); row++) { table.getWidget(row, 0).setVisible(enabled); if (!autoSort) { table.getWidget(row, inputs.size() + 1).setVisible(enabled); table.getWidget(row, inputs.size() + 2).setVisible(enabled); } } if (enabled) { updateNavigationLinks(); } } } @Override public boolean isEnabled() { return deleteButton.isVisible(); } @Override public void setEnabled(boolean enabled) { t.setEnabled(enabled); deleteButton.setVisible(enabled); } }