/*******************************************************************************
* 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.machine.create;
import elemental.dom.Element;
import elemental.dom.Node;
import elemental.html.TableCellElement;
import elemental.html.TableElement;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Style;
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.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
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.Command;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor;
import org.eclipse.che.ide.api.autocomplete.AutoCompleteResources;
import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant;
import org.eclipse.che.ide.extension.machine.client.MachineResources;
import org.eclipse.che.ide.ui.list.SimpleList;
import org.eclipse.che.ide.ui.toolbar.ToolbarResources;
import org.eclipse.che.ide.ui.window.Window;
import org.eclipse.che.ide.util.dom.Elements;
import org.vectomatic.dom.svg.ui.SVGImage;
import java.util.ArrayList;
import java.util.List;
import static com.google.gwt.dom.client.Style.Overflow.AUTO;
import static com.google.gwt.event.dom.client.KeyCodes.KEY_DOWN;
import static com.google.gwt.event.dom.client.KeyCodes.KEY_ENTER;
import static com.google.gwt.event.dom.client.KeyCodes.KEY_ESCAPE;
import static com.google.gwt.event.dom.client.KeyCodes.KEY_LEFT;
import static com.google.gwt.event.dom.client.KeyCodes.KEY_RIGHT;
import static com.google.gwt.event.dom.client.KeyCodes.KEY_UP;
/**
* The implementation of {@link CreateMachineView}.
*
* @author Artem Zatsarynnyi
*/
@Singleton
public class CreateMachineViewImpl extends Window implements CreateMachineView {
private static final CreateMachineViewImplUiBinder UI_BINDER = GWT.create(CreateMachineViewImplUiBinder.class);
private final MachineResources machineResources;
private final org.eclipse.che.ide.Resources coreResources;
private final AutoCompleteResources.Css css;
private final SimpleList.ListItemRenderer<RecipeDescriptor> listItemRenderer =
new SimpleList.ListItemRenderer<RecipeDescriptor>() {
@Override
public void render(Element itemElement, RecipeDescriptor itemData) {
final TableCellElement icon = Elements.createTDElement(css.proposalIcon());
final TableCellElement label = Elements.createTDElement(css.proposalLabel());
final TableCellElement group = Elements.createTDElement(css.proposalGroup());
final SVGImage image = new SVGImage(machineResources.recipe());
image.getElement().setAttribute("class", toolbarResources.toolbar().iconButtonIcon());
image.getElement().getStyle().setMargin(0, Style.Unit.PX);
icon.appendChild((Node)image.getElement());
label.setInnerHTML(itemData.getName());
group.setInnerHTML(itemData.getType());
itemElement.appendChild(icon);
itemElement.appendChild(label);
itemElement.appendChild(group);
}
@Override
public Element createElement() {
return Elements.createTRElement();
}
};
private final PopupPanel popupPanel;
@UiField(provided = true)
MachineLocalizationConstant localizationConstant;
@UiField
TextBox machineName;
@UiField
TextBox recipeURL;
@UiField
Label errorHint;
@UiField
TextBox tags;
@UiField
Label noRecipeHint;
private ToolbarResources toolbarResources;
private SimpleList<RecipeDescriptor> list;
private ActionDelegate delegate;
private final SimpleList.ListEventDelegate<RecipeDescriptor> eventDelegate = new SimpleList.ListEventDelegate<RecipeDescriptor>() {
@Override
public void onListItemClicked(Element listItemBase, RecipeDescriptor itemData) {
list.getSelectionModel().setSelectedItem(itemData);
}
@Override
public void onListItemDoubleClicked(Element listItemBase, RecipeDescriptor itemData) {
delegate.onRecipeSelected(itemData);
popupPanel.hide();
tags.setFocus(true);
}
};
private Button createButton;
private Button replaceButton;
private Button cancelButton;
@Inject
public CreateMachineViewImpl(MachineLocalizationConstant localizationConstant,
MachineResources machineResources,
org.eclipse.che.ide.Resources coreResources,
AutoCompleteResources autoCompleteResources,
ToolbarResources toolbarResources) {
this.localizationConstant = localizationConstant;
this.machineResources = machineResources;
this.coreResources = coreResources;
this.toolbarResources = toolbarResources;
css = autoCompleteResources.autocompleteComponentCss();
popupPanel = new PopupPanel();
setWidget(UI_BINDER.createAndBindUi(this));
setTitle(localizationConstant.viewCreateMachineTitle());
machineName.addKeyUpHandler(new KeyUpHandler() {
@Override
public void onKeyUp(KeyUpEvent event) {
delegate.onNameChanged();
}
});
recipeURL.addKeyUpHandler(new KeyUpHandler() {
@Override
public void onKeyUp(KeyUpEvent event) {
delegate.onRecipeUrlChanged();
}
});
createFooterButtons();
}
private void createFooterButtons() {
createButton = createButton(localizationConstant.viewCreateMachineButtonCreate(), "window-create-machine-create",
new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onCreateClicked();
}
});
replaceButton = createButton(localizationConstant.viewCreateMachineButtonReplace(), "window-create-machine-replace",
new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onReplaceDevMachineClicked();
}
});
cancelButton = createButton(localizationConstant.cancelButton(), "window-create-machine-cancel",
new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onCancelClicked();
}
});
addButtonToFooter(createButton);
addButtonToFooter(replaceButton);
addButtonToFooter(cancelButton);
}
@Override
public void setDelegate(ActionDelegate delegate) {
this.delegate = delegate;
}
@Override
public void show() {
super.show();
new Timer() {
@Override
public void run() {
machineName.setFocus(true);
}
}.schedule(300);
}
@Override
public void close() {
hide();
}
@Override
protected void onClose() {
super.onClose();
popupPanel.hide();
}
@Override
public String getMachineName() {
return machineName.getValue();
}
@Override
public void setMachineName(String name) {
machineName.setValue(name);
delegate.onNameChanged();
}
@Override
public String getRecipeURL() {
return recipeURL.getValue();
}
@Override
public void setRecipeURL(String url) {
recipeURL.setValue(url);
recipeURL.setTitle(url);
delegate.onRecipeUrlChanged();
}
@Override
public void setErrorHint(boolean show) {
errorHint.setVisible(show);
}
@Override
public List<String> getTags() {
final List<String> tagList = new ArrayList<>();
for (String tag : tags.getValue().split(" ")) {
if (!tag.isEmpty()) {
tagList.add(tag.trim());
}
}
return tagList;
}
@Override
public void setTags(String tags) {
this.tags.setValue(tags);
}
@Override
public void setNoRecipeHint(boolean show) {
noRecipeHint.setVisible(show);
}
@Override
public void setRecipes(List<RecipeDescriptor> recipes) {
if (recipes.isEmpty()) {
popupPanel.hide();
return;
}
popupPanel.clear();
final TableElement itemHolder = Elements.createTableElement();
itemHolder.setClassName(css.items());
final HTML html = new HTML();
html.setStyleName(css.container());
html.getElement().getStyle().setOverflow(AUTO);
html.getElement().appendChild(((com.google.gwt.dom.client.Element)itemHolder));
((Element)html.getElement()).getStyle().setProperty("max-height", "200px");
final HTML container = new HTML();
container.getElement().appendChild(html.getElement());
list = SimpleList.create((SimpleList.View)container.getElement().cast(),
(Element)html.getElement(),
itemHolder,
coreResources.defaultSimpleListCss(),
listItemRenderer,
eventDelegate);
list.render(recipes);
popupPanel.add(container);
popupPanel.setWidth(tags.getOffsetWidth() - 10 + "px");
popupPanel.setPopupPositionAndShow(new PositionCallback() {
@Override
public void setPosition(int offsetWidth, int offsetHeight) {
popupPanel.setPopupPosition(tags.getAbsoluteLeft(), tags.getAbsoluteTop() + tags.getOffsetHeight());
}
});
list.getSelectionModel().setSelectedItem(0);
}
@Override
public void setCreateButtonState(boolean enabled) {
createButton.setEnabled(enabled);
}
@Override
public void setReplaceButtonState(boolean enabled) {
replaceButton.setEnabled(enabled);
}
@UiHandler("tags")
void handleKeyDown(KeyDownEvent event) {
switch (event.getNativeKeyCode()) {
case KEY_UP:
if (popupPanel.isShowing()) {
event.preventDefault();
if (list.getSelectionModel().getSelectedIndex() == 0) {
list.getSelectionModel().setSelectedItem(list.getSelectionModel().size() - 1);
} else {
list.getSelectionModel().selectPrevious();
}
}
break;
case KEY_DOWN:
if (popupPanel.isShowing()) {
event.preventDefault();
if (list.getSelectionModel().getSelectedIndex() == list.getSelectionModel().size() - 1) {
list.getSelectionModel().setSelectedItem(0);
} else {
list.getSelectionModel().selectNext();
}
}
break;
case KEY_ENTER:
if (popupPanel.isShowing()) {
delegate.onRecipeSelected(list.getSelectionModel().getSelectedItem());
popupPanel.hide();
}
break;
case KEY_ESCAPE:
if (popupPanel.isShowing()) {
popupPanel.hide();
}
break;
case KEY_LEFT:
case KEY_RIGHT:
break;
default:
Scheduler.get().scheduleDeferred(new Command() {
@Override
public void execute() {
delegate.onTagsChanged();
}
});
break;
}
}
interface CreateMachineViewImplUiBinder extends UiBinder<Widget, CreateMachineViewImpl> {
}
}