/******************************************************************************* * 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.ide.projecttype.wizard.categoriespage; 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.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.KeyUpEvent; import com.google.gwt.resources.client.CssResource; 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.Timer; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.DockLayoutPanel; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Widget; import com.google.inject.Inject; import org.eclipse.che.api.project.shared.dto.ProjectTypeDto; import org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor; import org.eclipse.che.ide.Resources; import org.eclipse.che.ide.api.icon.Icon; import org.eclipse.che.ide.api.icon.IconRegistry; import org.eclipse.che.ide.projecttype.wizard.ProjectWizardResources; import org.eclipse.che.ide.resource.Path; 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.vectomatic.dom.svg.ui.SVGImage; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; /** * @author Evgen Vidolob * @author Oleksii Orel */ public class CategoriesPageViewImpl implements CategoriesPageView { private static MainPageViewImplUiBinder ourUiBinder = GWT.create(MainPageViewImplUiBinder.class); private final CategoriesComparator categoriesComparator; private final ProjectTypeComparator projectTypesComparator; private final TemplatesComparator templatesComparator; private final DockLayoutPanel rootElement; private final Category.CategoryEventDelegate<ProjectTemplateDescriptor> templateCategoryEventDelegate = new Category.CategoryEventDelegate<ProjectTemplateDescriptor>() { @Override public void onListItemClicked(Element listItemBase, ProjectTemplateDescriptor itemData) { selectNextWizardType(itemData); } }; private final Category.CategoryEventDelegate<ProjectTypeDto> projectTypeCategoryEventDelegate = new Category.CategoryEventDelegate<ProjectTypeDto>() { @Override public void onListItemClicked(Element listItemBase, ProjectTypeDto itemData) { selectNextWizardType(itemData); } }; private final CategoryRenderer<ProjectTypeDto> projectTypeCategoryRenderer = new CategoryRenderer<ProjectTypeDto>() { @Override public void renderElement(Element element, ProjectTypeDto data) { element.setInnerText(data.getDisplayName()); } @Override public Element renderCategory(Category<ProjectTypeDto> category) { return renderCategoryHeader(category.getTitle()); } }; private final CategoryRenderer<ProjectTemplateDescriptor> templateCategoryRenderer = new CategoryRenderer<ProjectTemplateDescriptor>() { @Override public void renderElement(Element element, ProjectTemplateDescriptor data) { element.setInnerText(data.getDisplayName()); } @Override public Element renderCategory(Category<ProjectTemplateDescriptor> category) { return renderCategoryHeader(category.getTitle()); } }; private final IconRegistry iconRegistry; @UiField(provided = true) Style styles; @UiField SimplePanel categoriesPanel; @UiField HTMLPanel descriptionArea; @UiField Label configurationAreaText; @UiField HTMLPanel configurationArea; @UiField Label projectType; @UiField TextBox projectName; @UiField TextArea projectDescription; @UiField Button selectPath; @UiField Label parentPath; private ActionDelegate delegate; private Map<String, Set<ProjectTypeDto>> typesByCategory; private Map<String, Set<ProjectTemplateDescriptor>> templatesByCategory; private Resources resources; private CategoriesList categoriesList; private List<ProjectTypeDto> availableProjectTypes; @Inject public CategoriesPageViewImpl(Resources resources, IconRegistry iconRegistry, ProjectWizardResources wizardResources, CategoriesComparator categoriesComparator, ProjectTypeComparator projectTypesComparator, TemplatesComparator templatesComparator) { this.resources = resources; styles = wizardResources.mainPageStyle(); this.categoriesComparator = categoriesComparator; this.projectTypesComparator = projectTypesComparator; this.templatesComparator = templatesComparator; styles.ensureInjected(); this.iconRegistry = iconRegistry; rootElement = ourUiBinder.createAndBindUi(this); reset(); projectName.getElement().setAttribute("placeholder", "Define the name of your project..."); projectName.getElement().setAttribute("maxlength", "128"); projectName.getElement().setAttribute("spellcheck", "false"); projectDescription.getElement().setAttribute("placeholder", "Add a description to your project..."); projectDescription.getElement().setAttribute("maxlength", "256"); setConfigOptions(null); selectPath.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { delegate.selectPathClicked(); } }); } @UiHandler("projectName") void onProjectNameChanged(KeyUpEvent event) { if (projectName.getValue() != null && projectName.getValue().contains(" ")) { String tmp = projectName.getValue(); while (tmp.contains(" ")) { tmp = tmp.replaceAll(" ", "-"); } projectName.setValue(tmp); } if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) { return; } delegate.projectNameChanged(projectName.getText()); } @UiHandler("projectDescription") void onProjectDescriptionChanged(KeyUpEvent event) { if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) { return; } delegate.projectDescriptionChanged(projectDescription.getValue()); } private void selectNextWizardType(Object itemData) { if (itemData instanceof ProjectTemplateDescriptor) { delegate.projectTemplateSelected((ProjectTemplateDescriptor)itemData); descriptionArea.getElement().setInnerText(((ProjectTemplateDescriptor)itemData).getDescription()); projectType.setText(((ProjectTemplateDescriptor)itemData).getDisplayName()); } else if (itemData instanceof ProjectTypeDto) { delegate.projectTypeSelected((ProjectTypeDto)itemData); descriptionArea.getElement().setInnerText(((ProjectTypeDto)itemData).getDisplayName()); projectType.setText(((ProjectTypeDto)itemData).getDisplayName()); } else { descriptionArea.getElement().setInnerText(""); resetConfigOptions(); projectType.setText(""); } } private void resetConfigOptions() { configurationArea.getElement().setInnerText(""); } private void changeEnabledState(boolean enabled) { projectName.setEnabled(enabled); if (enabled) { projectName.setFocus(true); } changeEnabledStateAll(enabled); } private void changeEnabledStateAll(boolean enabled) { projectDescription.setEnabled(enabled); } private Element renderCategoryHeader(String category) { SpanElement categoryElement = Document.get().createSpanElement(); categoryElement.setClassName(resources.defaultCategoriesListCss().headerText()); SpanElement iconElement = Document.get().createSpanElement(); categoryElement.appendChild(iconElement); SpanElement textElement = Document.get().createSpanElement(); categoryElement.appendChild(textElement); textElement.setInnerText(category); Icon icon = iconRegistry.getIconIfExist(category + ".samples.category.icon"); if (icon != null) { final SVGImage iconSVG = icon.getSVGImage(); if (iconSVG != null) { iconElement.appendChild(iconSVG.getElement()); return categoryElement; } } return categoryElement; } @Override public void setConfigOptions(List<String> options) { StringBuilder optionsHTMLBuilder = new StringBuilder(); if (options != null) { for (String option : options) { if (option != null && option.length() > 0) { optionsHTMLBuilder.append("<p>- ").append(option).append("</p>\n"); } } } if (optionsHTMLBuilder.length() > 0) { configurationArea.getElement().setInnerHTML(optionsHTMLBuilder.toString()); configurationAreaText.setVisible(true); configurationArea.setVisible(true); } else { configurationAreaText.setVisible(false); configurationArea.setVisible(false); configurationArea.getElement().setInnerText(""); } } @Override public void setName(String name) { projectName.setValue(name, true); } /** {@inheritDoc} */ @Override public void setDescription(String description) { projectDescription.setValue(description); } @Override public void removeNameError() { projectName.removeStyleName(styles.inputError()); } @Override public void showNameError() { projectName.addStyleName(styles.inputError()); } @Override public void focusSelectPathButton() { new Timer() { @Override public void run() { selectPath.setFocus(true); } }.schedule(300); } @Override public void focusName() { new Timer() { @Override public void run() { projectName.setFocus(true); } }.schedule(300); } @Override public void setDelegate(ActionDelegate delegate) { this.delegate = delegate; } @Override public Widget asWidget() { return rootElement; } @Override public void selectProjectType(final String projectTypeId) { ProjectTypeDto typeDescriptor = null; for (Map.Entry<String, Set<ProjectTypeDto>> entry : typesByCategory.entrySet()) { for (ProjectTypeDto typeDefinition : entry.getValue()) { if (typeDefinition.getId().equals(projectTypeId)) { typeDescriptor = typeDefinition; break; } } if (typeDescriptor != null) { break; } } if (typeDescriptor != null) { for (ProjectTypeDto existingProjectTypeDescriptor : availableProjectTypes) { if (existingProjectTypeDescriptor.getId().equals(typeDescriptor.getId())) { categoriesList.selectElement(typeDescriptor); selectNextWizardType(typeDescriptor); } } } projectName.setFocus(true); } @Override public void setProjectTypes(List<ProjectTypeDto> availableProjectTypes) { this.availableProjectTypes = availableProjectTypes; } @Override public void setNameFieldReadOnly(boolean readOnly) { projectName.setReadOnly(readOnly); } @Override public void setParentPath(Path path) { parentPath.setText(path.toString()); } @Override public void setCategories(Map<String, Set<ProjectTypeDto>> typesByCategory, Map<String, Set<ProjectTemplateDescriptor>> templatesByCategory) { this.typesByCategory = typesByCategory; this.templatesByCategory = templatesByCategory; } @Override public void updateCategories(boolean includeTemplates) { List<Category<?>> categories = new ArrayList<>(); for (Map.Entry<String, Set<ProjectTypeDto>> entry : typesByCategory.entrySet()) { final Set<ProjectTypeDto> projectTypes = entry.getValue(); List<ProjectTypeDto> projectTypeDescriptors = new ArrayList<>(); projectTypeDescriptors.addAll(projectTypes); Collections.sort(projectTypeDescriptors, projectTypesComparator); categories.add(new Category<>(entry.getKey(), projectTypeCategoryRenderer, projectTypeDescriptors, projectTypeCategoryEventDelegate)); } // Sort project type categories only. Project templates categories should be in the end. Collections.sort(categories, categoriesComparator); if (includeTemplates) { for (Map.Entry<String, Set<ProjectTemplateDescriptor>> entry : templatesByCategory.entrySet()) { final Set<ProjectTemplateDescriptor> projectTemplates = entry.getValue(); List<ProjectTemplateDescriptor> templateDescriptors = new ArrayList<>(); templateDescriptors.addAll(projectTemplates); Collections.sort(templateDescriptors, templatesComparator); categories.add(new Category<>(entry.getKey(), templateCategoryRenderer, templateDescriptors, templateCategoryEventDelegate)); } } categoriesList.render(categories, true); } @Override public void reset() { // resetName(); categoriesPanel.clear(); categoriesList = new CategoriesList(resources); categoriesPanel.add(categoriesList); com.google.gwt.dom.client.Style style = categoriesList.getElement().getStyle(); style.setWidth(100, com.google.gwt.dom.client.Style.Unit.PCT); style.setHeight(100, com.google.gwt.dom.client.Style.Unit.PCT); style.setPosition(com.google.gwt.dom.client.Style.Position.RELATIVE); descriptionArea.getElement().setInnerHTML(""); configurationArea.getElement().setInnerText(""); } interface MainPageViewImplUiBinder extends UiBinder<DockLayoutPanel, CategoriesPageViewImpl> { } public interface Style extends CssResource { String mainPanel(); String leftPart(); String rightPart(); String namePanel(); String labelPosition(); String inputFieldPosition(); String categories(); String description(); String configuration(); String label(); String labelTitle(); String inputError(); } /** * Helps to sort categories by title. * * @author Oleksii Orel */ static final class CategoriesComparator implements Comparator<Category> { @Override public int compare(Category o1, Category o2) { return o1.getTitle().compareTo(o2.getTitle()); } } /** * Helps to sort the project types by display name. * * @author Oleksii Orel */ static final class ProjectTypeComparator implements Comparator<ProjectTypeDto> { @Override public int compare(ProjectTypeDto o1, ProjectTypeDto o2) { return o1.getDisplayName().compareTo(o2.getDisplayName()); } } /** * Helps to sort the template descriptors by display name. * * @author Oleksii Orel */ static final class TemplatesComparator implements Comparator<ProjectTemplateDescriptor> { @Override public int compare(ProjectTemplateDescriptor o1, ProjectTemplateDescriptor o2) { return o1.getDisplayName().compareTo(o2.getDisplayName()); } } }