/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.extension.machine.client.command.edit;
import elemental.events.KeyboardEvent;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.dom.client.Style;
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.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.ide.CoreLocalizationConstant;
import org.eclipse.che.ide.api.icon.Icon;
import org.eclipse.che.ide.api.icon.IconRegistry;
import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant;
import org.eclipse.che.ide.extension.machine.client.command.CommandConfiguration;
import org.eclipse.che.ide.extension.machine.client.command.CommandType;
import org.eclipse.che.ide.ui.list.CategoriesList;
import org.eclipse.che.ide.ui.list.Category;
import org.eclipse.che.ide.ui.list.CategoryRenderer;
import org.eclipse.che.ide.ui.window.Window;
import org.vectomatic.dom.svg.ui.SVGImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* The implementation of {@link EditCommandsView}.
*
* @author Artem Zatsarynnyi
* @author Oleksii Orel
*/
@Singleton
public class EditCommandsViewImpl extends Window implements EditCommandsView {
private static final EditCommandsViewImplUiBinder UI_BINDER = GWT.create(EditCommandsViewImplUiBinder.class);
private final EditCommandResources commandResources;
private final IconRegistry iconRegistry;
private final CoreLocalizationConstant coreLocale;
private final Button cancelButton;
private final Button saveButton;
private final Label hintLabel;
private final CategoryRenderer<CommandConfiguration> projectImporterRenderer =
new CategoryRenderer<CommandConfiguration>() {
@Override
public void renderElement(Element element, CommandConfiguration data) {
UIObject.ensureDebugId(element, "commandsManager-type-" + data.getType().getId());
element.addClassName(commandResources.getCss().categorySubElementHeader());
element.setInnerText(data.getName().trim().isEmpty() ? "<none>" : data.getName());
element.appendChild(renderSubElementButtons(data));
}
@Override
public SpanElement renderCategory(Category<CommandConfiguration> category) {
return renderCategoryHeader(category.getTitle());
}
};
private final Category.CategoryEventDelegate<CommandConfiguration> projectImporterDelegate =
new Category.CategoryEventDelegate<CommandConfiguration>() {
@Override
public void onListItemClicked(Element listItemBase, CommandConfiguration itemData) {
selectType = itemData.getType();
setSelectedConfiguration(itemData);
}
};
private ActionDelegate delegate;
private CategoriesList list;
private Map<CommandType, List<CommandConfiguration>> categories;
private CommandConfiguration selectConfiguration;
private CommandType selectType;
private String filterTextValue;
@UiField
MachineLocalizationConstant machineLocale;
@UiField
SimplePanel categoriesPanel;
@UiField
TextBox filterInputField;
@UiField
TextBox configurationName;
@UiField
TextBox configurationPreviewUrl;
@UiField
SimplePanel contentPanel;
@UiField
FlowPanel savePanel;
@UiField
FlowPanel previewUrlPanel;
@UiField
FlowPanel overFooter;
@Inject
protected EditCommandsViewImpl(org.eclipse.che.ide.Resources resources,
EditCommandResources commandResources,
MachineLocalizationConstant machineLocale,
CoreLocalizationConstant coreLocale,
IconRegistry iconRegistry) {
this.commandResources = commandResources;
this.machineLocale = machineLocale;
this.coreLocale = coreLocale;
this.iconRegistry = iconRegistry;
selectConfiguration = null;
categories = new HashMap<>();
commandResources.getCss().ensureInjected();
setWidget(UI_BINDER.createAndBindUi(this));
setTitle(machineLocale.editCommandsViewTitle());
getWidget().getElement().setId("commandsManagerView");
hintLabel = new Label(machineLocale.editCommandsViewHint());
hintLabel.addStyleName(commandResources.getCss().hintLabel());
filterInputField.getElement().setAttribute("placeholder", machineLocale.editCommandsViewPlaceholder());
filterInputField.getElement().addClassName(commandResources.getCss().filterPlaceholder());
list = new CategoriesList(resources);
list.addDomHandler(new KeyDownHandler() {
@Override
public void onKeyDown(KeyDownEvent event) {
switch (event.getNativeKeyCode()) {
case KeyboardEvent.KeyCode.INSERT:
delegate.onAddClicked();
resetFilter();
break;
case KeyboardEvent.KeyCode.DELETE:
delegate.onRemoveClicked(selectConfiguration);
break;
}
}
}, KeyDownEvent.getType());
categoriesPanel.add(list);
savePanel.setVisible(false);
previewUrlPanel.setVisible(false);
contentPanel.clear();
saveButton = createButton(coreLocale.save(), "window-edit-configurations-save", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onSaveClicked();
}
});
saveButton.addStyleName(this.resources.windowCss().primaryButton());
overFooter.add(saveButton);
cancelButton = createButton(coreLocale.cancel(), "window-edit-configurations-cancel", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onCancelClicked();
}
});
overFooter.add(cancelButton);
createFooterButton();
resetFilter();
getWidget().getElement().getStyle().setPadding(0, Style.Unit.PX);
}
private CommandType getTypeById(String commandId) {
for (CommandType type : categories.keySet()) {
if (type.getId().equals(commandId)) {
return type;
}
}
return null;
}
private SpanElement renderSubElementButtons(CommandConfiguration commandConfiguration) {
SpanElement categorySubElement = Document.get().createSpanElement();
categorySubElement.setClassName(commandResources.getCss().buttonArea());
SpanElement removeCommandButtonElement = Document.get().createSpanElement();
categorySubElement.appendChild(removeCommandButtonElement);
removeCommandButtonElement.appendChild(this.commandResources.removeCommandButton().getSvg().getElement());
Event.sinkEvents(removeCommandButtonElement, Event.ONCLICK);
Event.setEventListener(removeCommandButtonElement, new EventListener() {
@Override
public void onBrowserEvent(Event event) {
if (Event.ONCLICK == event.getTypeInt()) {
event.stopPropagation();
setSelectedConfiguration(selectConfiguration);
delegate.onRemoveClicked(selectConfiguration);
}
}
});
SpanElement duplicateCommandButton = Document.get().createSpanElement();
categorySubElement.appendChild(duplicateCommandButton);
duplicateCommandButton.appendChild(this.commandResources.duplicateCommandButton().getSvg().getElement());
Event.sinkEvents(duplicateCommandButton, Event.ONCLICK);
Event.setEventListener(duplicateCommandButton, new EventListener() {
@Override
public void onBrowserEvent(Event event) {
if (Event.ONCLICK == event.getTypeInt()) {
event.stopPropagation();
delegate.onDuplicateClicked();
}
}
});
return categorySubElement;
}
private SpanElement renderCategoryHeader(final String commandId) {
SpanElement categoryHeaderElement = Document.get().createSpanElement();
categoryHeaderElement.setClassName(commandResources.getCss().categoryHeader());
SpanElement iconElement = Document.get().createSpanElement();
categoryHeaderElement.appendChild(iconElement);
SpanElement textElement = Document.get().createSpanElement();
categoryHeaderElement.appendChild(textElement);
CommandType currentCommandType = getTypeById(commandId);
textElement.setInnerText(currentCommandType != null ? currentCommandType.getDisplayName() : commandId);
SpanElement buttonElement = Document.get().createSpanElement();
buttonElement.appendChild(commandResources.addCommandButton().getSvg().getElement());
categoryHeaderElement.appendChild(buttonElement);
Event.sinkEvents(buttonElement, Event.ONCLICK);
Event.setEventListener(buttonElement, new EventListener() {
@Override
public void onBrowserEvent(Event event) {
if (Event.ONCLICK == event.getTypeInt()) {
event.stopPropagation();
savePanel.setVisible(true);
previewUrlPanel.setVisible(true);
selectType = getTypeById(commandId);
delegate.onAddClicked();
resetFilter();
}
}
});
Icon icon = iconRegistry.getIconIfExist(commandId + ".commands.category.icon");
if (icon != null) {
final SVGImage iconSVG = icon.getSVGImage();
if (iconSVG != null) {
iconElement.appendChild(iconSVG.getElement());
return categoryHeaderElement;
}
}
return categoryHeaderElement;
}
private void resetFilter() {
filterInputField.setText("");//reset filter
filterTextValue = "";
}
private void renderCategoriesList(Map<CommandType, List<CommandConfiguration>> categories) {
if (categories == null) {
return;
}
final List<Category<?>> categoriesList = new ArrayList<>();
for (CommandType type : categories.keySet()) {
List<CommandConfiguration> configurations = new ArrayList<>();
if (filterTextValue.isEmpty()) {
configurations = categories.get(type);
} else { // filtering List
for (final CommandConfiguration configuration : categories.get(type)) {
if (configuration.getName().contains(filterTextValue)) {
configurations.add(configuration);
}
}
}
Category<CommandConfiguration> category =
new Category<>(type.getId(), projectImporterRenderer, configurations, projectImporterDelegate);
categoriesList.add(category);
}
list.clear();
list.render(categoriesList);
if (selectConfiguration != null) {
list.selectElement(selectConfiguration);
if (filterTextValue.isEmpty()) {
selectText(configurationName.getElement());
}
} else {
contentPanel.clear();
contentPanel.add(hintLabel);
savePanel.setVisible(false);
previewUrlPanel.setVisible(false);
}
}
@Override
public void selectNextItem() {
final CommandConfiguration nextItem;
final List<CommandConfiguration> configurations = categories.get(selectConfiguration.getType());
int selectPosition = configurations.indexOf(selectConfiguration);
if (configurations.size() < 2 || selectPosition == -1) {
nextItem = null;
} else {
if (selectPosition > 0) {
selectPosition--;
} else {
selectPosition++;
}
nextItem = configurations.get(selectPosition);
}
list.selectElement(nextItem);
selectConfiguration = nextItem;
}
@Override
public void setData(Map<CommandType, List<CommandConfiguration>> categories) {
this.categories = categories;
renderCategoriesList(categories);
}
private void createFooterButton() {
final Button closeButton = createButton(coreLocale.close(), "window-edit-configurations-close",
new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onCloseClicked();
}
});
closeButton.addDomHandler(new BlurHandler() {
@Override
public void onBlur(BlurEvent blurEvent) {
//set default focus
selectText(filterInputField.getElement());
}
}, BlurEvent.getType());
addButtonToFooter(closeButton);
Element dummyFocusElement = DOM.createSpan();
dummyFocusElement.setTabIndex(0);
getFooter().getElement().appendChild(dummyFocusElement);
}
/**
* Select text.
*/
private native void selectText(Element inputElement) /*-{
inputElement.focus();
inputElement.setSelectionRange(0, inputElement.value.length);
}-*/;
@Override
public void setDelegate(ActionDelegate delegate) {
this.delegate = delegate;
}
@Override
public void show() {
super.show();
configurationName.setText("");
configurationPreviewUrl.setText("");
}
@Override
public void close() {
this.hide();
}
@Override
public AcceptsOneWidget getCommandConfigurationsContainer() {
return contentPanel;
}
@Override
public void clearCommandConfigurationsContainer() {
contentPanel.clear();
}
@Override
public String getConfigurationName() {
return configurationName.getText().trim();
}
@Override
public void setConfigurationPreviewUrl(String configurationPreviewUrl) {
this.configurationPreviewUrl.setText(configurationPreviewUrl);
}
@Override
public String getConfigurationPreviewUrl() {
return configurationPreviewUrl.getText().trim();
}
@Override
public void setConfigurationName(String name) {
configurationName.setText(name);
}
@Override
public void setCancelButtonState(boolean enabled) {
cancelButton.setEnabled(enabled);
}
@Override
public void setSaveButtonState(boolean enabled) {
saveButton.setEnabled(enabled);
}
@Override
public void setFilterState(boolean enabled) {
filterInputField.setEnabled(enabled);
}
@Nullable
@Override
public CommandType getSelectedCommandType() {
return selectType;
}
@Override
public void setSelectedConfiguration(CommandConfiguration selectConfiguration) {
this.selectConfiguration = selectConfiguration;
if (selectConfiguration != null) {
savePanel.setVisible(true);
previewUrlPanel.setVisible(true);
delegate.onConfigurationSelected(selectConfiguration);
}
}
@Nullable
@Override
public CommandConfiguration getSelectedConfiguration() {
return selectConfiguration;
}
@UiHandler("configurationName")
public void onNameKeyUp(KeyUpEvent event) {
delegate.onNameChanged();
}
@UiHandler("configurationPreviewUrl")
public void onPreviewUrlKeyUp(KeyUpEvent event) {
delegate.onPreviewUrlChanged();
}
@UiHandler("filterInputField")
public void onFilterKeyUp(KeyUpEvent event) {
if (!filterTextValue.equals(filterInputField.getText())) {
filterTextValue = filterInputField.getText();
renderCategoriesList(categories);
}
}
@Override
protected void onEnterClicked() {
if (saveButton.isEnabled()) {
delegate.onSaveClicked();
}
}
@Override
protected void onClose() {
setSelectedConfiguration(selectConfiguration);
}
interface EditCommandsViewImplUiBinder extends UiBinder<Widget, EditCommandsViewImpl> {
}
}