/*******************************************************************************
* Copyright (c) 2012-2017 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.plugin.debugger.ide.configuration;
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 org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.ide.CoreLocalizationConstant;
import org.eclipse.che.ide.api.debug.DebugConfiguration;
import org.eclipse.che.ide.api.debug.DebugConfigurationType;
import org.eclipse.che.ide.api.icon.Icon;
import org.eclipse.che.ide.api.icon.IconRegistry;
import org.eclipse.che.plugin.debugger.ide.DebuggerLocalizationConstant;
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 EditDebugConfigurationsView}.
*
* @author Artem Zatsarynnyi
*/
public class EditDebugConfigurationsViewImpl extends Window implements EditDebugConfigurationsView {
private static final EditDebugConfigurationsViewImplUiBinder UI_BINDER = GWT.create(EditDebugConfigurationsViewImplUiBinder.class);
private final EditConfigurationsResources editConfigurationsResources;
private final IconRegistry iconRegistry;
private final CoreLocalizationConstant coreLocale;
private final Label hintLabel;
private final Category.CategoryEventDelegate<DebugConfiguration> categoryEventDelegate;
private final CategoryRenderer<DebugConfiguration> categoryRenderer;
@UiField(provided = true)
DebuggerLocalizationConstant locale;
@UiField
SimplePanel categoriesPanel;
@UiField
TextBox filterInputField;
@UiField
TextBox configurationName;
@UiField
SimplePanel contentPanel;
@UiField
FlowPanel namePanel;
@UiField
FlowPanel overFooter;
private Button cancelButton;
private Button saveButton;
private Button closeButton;
private Button debugButton;
private ActionDelegate delegate;
private CategoriesList list;
private Map<DebugConfigurationType, List<DebugConfiguration>> categories;
private DebugConfiguration selectedConfiguration;
private DebugConfigurationType selectedType;
private String filterTextValue;
@Inject
protected EditDebugConfigurationsViewImpl(org.eclipse.che.ide.Resources resources,
final EditConfigurationsResources editConfigurationsResources,
DebuggerLocalizationConstant locale,
CoreLocalizationConstant coreLocale,
IconRegistry iconRegistry) {
this.editConfigurationsResources = editConfigurationsResources;
this.locale = locale;
this.coreLocale = coreLocale;
this.iconRegistry = iconRegistry;
categories = new HashMap<>();
editConfigurationsResources.getCss().ensureInjected();
setWidget(UI_BINDER.createAndBindUi(this));
setTitle(locale.editConfigurationsViewTitle());
getWidget().getElement().setId("editDebugConfigurationsView");
hintLabel = new Label(locale.editConfigurationsViewHint());
hintLabel.addStyleName(editConfigurationsResources.getCss().hintLabel());
filterInputField.getElement().setAttribute("placeholder", locale.editConfigurationsViewPlaceholder());
filterInputField.getElement().addClassName(editConfigurationsResources.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(selectedConfiguration);
break;
}
}
}, KeyDownEvent.getType());
categoriesPanel.add(list);
categoryEventDelegate = new Category.CategoryEventDelegate<DebugConfiguration>() {
@Override
public void onListItemClicked(Element listItemBase, DebugConfiguration itemData) {
selectedType = itemData.getType();
setSelectedConfiguration(itemData);
}
};
categoryRenderer = new CategoryRenderer<DebugConfiguration>() {
@Override
public void renderElement(Element element, DebugConfiguration data) {
UIObject.ensureDebugId(element, "debug-configuration-type-" + data.getType().getId());
element.addClassName(editConfigurationsResources.getCss().categorySubElementHeader());
element.setInnerText(data.getName().trim().isEmpty() ? "<none>" : data.getName());
element.appendChild(renderSubElementButtons());
}
@Override
public SpanElement renderCategory(Category<DebugConfiguration> category) {
return renderCategoryHeader(category.getTitle());
}
};
namePanel.setVisible(false);
contentPanel.clear();
createButtons();
resetFilter();
getWidget().getElement().getStyle().setPadding(0, Style.Unit.PX);
}
private SpanElement renderSubElementButtons() {
final SpanElement categorySubElement = Document.get().createSpanElement();
categorySubElement.setClassName(editConfigurationsResources.getCss().buttonArea());
final SpanElement removeConfigurationButtonElement = Document.get().createSpanElement();
categorySubElement.appendChild(removeConfigurationButtonElement);
removeConfigurationButtonElement.appendChild(this.editConfigurationsResources.removeConfigurationButton().getSvg().getElement());
Event.sinkEvents(removeConfigurationButtonElement, Event.ONCLICK);
Event.setEventListener(removeConfigurationButtonElement, new EventListener() {
@Override
public void onBrowserEvent(Event event) {
if (Event.ONCLICK == event.getTypeInt()) {
event.stopPropagation();
setSelectedConfiguration(selectedConfiguration);
delegate.onRemoveClicked(selectedConfiguration);
}
}
});
final SpanElement duplicateConfigurationButton = Document.get().createSpanElement();
categorySubElement.appendChild(duplicateConfigurationButton);
duplicateConfigurationButton.appendChild(this.editConfigurationsResources.duplicateConfigurationButton().getSvg().getElement());
Event.sinkEvents(duplicateConfigurationButton, Event.ONCLICK);
Event.setEventListener(duplicateConfigurationButton, new EventListener() {
@Override
public void onBrowserEvent(Event event) {
if (Event.ONCLICK == event.getTypeInt()) {
event.stopPropagation();
delegate.onDuplicateClicked();
}
}
});
return categorySubElement;
}
private SpanElement renderCategoryHeader(final String categoryTitle) {
SpanElement categoryHeaderElement = Document.get().createSpanElement();
categoryHeaderElement.setClassName(editConfigurationsResources.getCss().categoryHeader());
SpanElement iconElement = Document.get().createSpanElement();
categoryHeaderElement.appendChild(iconElement);
SpanElement textElement = Document.get().createSpanElement();
categoryHeaderElement.appendChild(textElement);
DebugConfigurationType currentDebugConfigurationType = getTypeById(categoryTitle);
textElement.setInnerText(currentDebugConfigurationType != null ? currentDebugConfigurationType.getDisplayName() : categoryTitle);
SpanElement buttonElement = Document.get().createSpanElement();
buttonElement.appendChild(editConfigurationsResources.addConfigurationButton().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();
namePanel.setVisible(true);
selectedType = getTypeById(categoryTitle);
delegate.onAddClicked();
resetFilter();
}
}
});
Icon icon = iconRegistry.getIconIfExist(categoryTitle + ".debug.configuration.type.icon");
if (icon != null) {
final SVGImage iconSVG = icon.getSVGImage();
if (iconSVG != null) {
iconElement.appendChild(iconSVG.getElement());
return categoryHeaderElement;
}
}
return categoryHeaderElement;
}
private DebugConfigurationType getTypeById(String typeId) {
for (DebugConfigurationType type : categories.keySet()) {
if (type.getId().equals(typeId)) {
return type;
}
}
return null;
}
private void resetFilter() {
filterInputField.setText("");//reset filter
filterTextValue = "";
}
private void renderCategoriesList(Map<DebugConfigurationType, List<DebugConfiguration>> categories) {
if (categories == null) {
return;
}
final List<Category<?>> categoriesList = new ArrayList<>();
for (DebugConfigurationType type : categories.keySet()) {
List<DebugConfiguration> configurations = new ArrayList<>();
if (filterTextValue.isEmpty()) {
configurations = categories.get(type);
} else { // filtering List
for (final DebugConfiguration configuration : categories.get(type)) {
if (configuration.getName().contains(filterTextValue)) {
configurations.add(configuration);
}
}
}
Category<DebugConfiguration> category = new Category<>(type.getId(),
categoryRenderer,
configurations,
categoryEventDelegate);
categoriesList.add(category);
}
list.clear();
list.render(categoriesList, true);
if (selectedConfiguration != null) {
list.selectElement(selectedConfiguration);
if (filterTextValue.isEmpty()) {
selectText(configurationName.getElement());
}
} else {
contentPanel.clear();
contentPanel.add(hintLabel);
namePanel.setVisible(false);
}
}
@Override
public void selectNextItem() {
final DebugConfiguration nextItem;
final List<DebugConfiguration> configurations = categories.get(selectedConfiguration.getType());
int selectPosition = configurations.indexOf(selectedConfiguration);
if (configurations.size() < 2 || selectPosition == -1) {
nextItem = null;
} else {
if (selectPosition > 0) {
selectPosition--;
} else {
selectPosition++;
}
nextItem = configurations.get(selectPosition);
}
list.selectElement(nextItem);
selectedConfiguration = nextItem;
}
@Override
public void setData(Map<DebugConfigurationType, List<DebugConfiguration>> categories) {
this.categories = categories;
renderCategoriesList(categories);
}
private void createButtons() {
saveButton = createButton(coreLocale.save(), "window-edit-debug-configurations-save", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onSaveClicked();
}
});
saveButton.addStyleName(Window.resources.windowCss().primaryButton());
overFooter.add(saveButton);
cancelButton = createButton(coreLocale.cancel(), "window-edit-debug-configurations-cancel", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onCancelClicked();
}
});
overFooter.add(cancelButton);
debugButton = createButton(coreLocale.debug(), "window-edit-debug-configurations-debug", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onDebugClicked();
}
});
overFooter.add(debugButton);
closeButton = createButton(coreLocale.close(), "window-edit-debug-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);
}
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("");
}
@Override
public void close() {
this.hide();
}
@Override
public AcceptsOneWidget getDebugConfigurationPageContainer() {
return contentPanel;
}
@Override
public void clearDebugConfigurationPageContainer() {
contentPanel.clear();
}
@Override
public String getConfigurationName() {
return configurationName.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 setDebugButtonState(boolean enabled) {
debugButton.setEnabled(enabled);
}
@Override
public void setFilterState(boolean enabled) {
filterInputField.setEnabled(enabled);
}
@Nullable
@Override
public DebugConfigurationType getSelectedConfigurationType() {
return selectedType;
}
@Nullable
@Override
public DebugConfiguration getSelectedConfiguration() {
return selectedConfiguration;
}
@Override
public void setSelectedConfiguration(DebugConfiguration selectConfiguration) {
this.selectedConfiguration = selectConfiguration;
if (selectConfiguration != null) {
namePanel.setVisible(true);
delegate.onConfigurationSelected(selectConfiguration);
}
}
@Override
public void focusCloseButton() {
closeButton.setFocus(true);
}
@UiHandler("configurationName")
public void onNameKeyUp(KeyUpEvent event) {
delegate.onNameChanged();
}
@UiHandler("filterInputField")
public void onFilterKeyUp(KeyUpEvent event) {
if (!filterTextValue.equals(filterInputField.getText())) {
filterTextValue = filterInputField.getText();
renderCategoriesList(categories);
}
}
@Override
protected void onEnterClicked() {
delegate.onEnterPressed();
}
@Override
protected void onClose() {
super.onClose();
setSelectedConfiguration(selectedConfiguration);
}
@Override
public boolean isCancelButtonFocused() {
return isWidgetFocused(cancelButton);
}
@Override
public boolean isCloseButtonFocused() {
return isWidgetFocused(closeButton);
}
interface EditDebugConfigurationsViewImplUiBinder extends UiBinder<Widget, EditDebugConfigurationsViewImpl> {
}
}