/******************************************************************************* * Copyright (c) 2012-2015 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 org.eclipse.che.api.project.shared.dto.ProjectTemplateDescriptor; import org.eclipse.che.api.project.shared.dto.ProjectTypeDefinition; 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.ui.Styles; 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 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.KeyCodes; import com.google.gwt.event.dom.client.KeyUpEvent; import com.google.gwt.event.logical.shared.ValueChangeEvent; 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.DockLayoutPanel; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.RadioButton; 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 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<ProjectTypeDefinition> projectTypeCategoryEventDelegate = new Category.CategoryEventDelegate<ProjectTypeDefinition>() { @Override public void onListItemClicked(Element listItemBase, ProjectTypeDefinition itemData) { selectNextWizardType(itemData); } }; private final CategoryRenderer<ProjectTypeDefinition> projectTypeCategoryRenderer = new CategoryRenderer<ProjectTypeDefinition>() { @Override public void renderElement(Element element, ProjectTypeDefinition data) { element.setInnerText(data.getDisplayName()); } @Override public SpanElement renderCategory(Category<ProjectTypeDefinition> category) { return renderCategoryWithIcon(category.getTitle()); } }; private final CategoryRenderer<ProjectTemplateDescriptor> templateCategoryRenderer = new CategoryRenderer<ProjectTemplateDescriptor>() { @Override public void renderElement(Element element, ProjectTemplateDescriptor data) { element.setInnerText(data.getDisplayName()); } @Override public SpanElement renderCategory(Category<ProjectTemplateDescriptor> category) { return renderCategoryWithIcon(category.getTitle()); } }; private final IconRegistry iconRegistry; @UiField(provided = true) Style style; @UiField SimplePanel categoriesPanel; @UiField HTMLPanel descriptionArea; @UiField Label configurationAreaText; @UiField HTMLPanel configurationArea; @UiField Label projectType; @UiField TextBox projectName; @UiField TextArea projectDescription; @UiField RadioButton projectPrivate; @UiField RadioButton projectPublic; private ActionDelegate delegate; private Map<String, Set<ProjectTypeDefinition>> typesByCategory; private Map<String, Set<ProjectTemplateDescriptor>> templatesByCategory; private Resources resources; private CategoriesList categoriesList; private List<ProjectTypeDefinition> availableProjectTypes; @Inject public CategoriesPageViewImpl(Resources resources, IconRegistry iconRegistry, ProjectWizardResources wizardResources, CategoriesComparator categoriesComparator, ProjectTypeComparator projectTypesComparator, TemplatesComparator templatesComparator) { this.resources = resources; style = wizardResources.mainPageStyle(); this.categoriesComparator = categoriesComparator; this.projectTypesComparator = projectTypesComparator; this.templatesComparator = templatesComparator; style.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); } @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()); } @UiHandler({"projectPublic", "projectPrivate"}) void visibilityHandler(ValueChangeEvent<Boolean> event) { delegate.projectVisibilityChanged(projectPublic.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 ProjectTypeDefinition) { delegate.projectTypeSelected((ProjectTypeDefinition)itemData); descriptionArea.getElement().setInnerText(((ProjectTypeDefinition)itemData).getDisplayName()); projectType.setText(((ProjectTypeDefinition)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); projectPublic.setEnabled(enabled); projectPrivate.setEnabled(enabled); } private SpanElement renderCategoryWithIcon(String category) { SpanElement textElement = Document.get().createSpanElement(); textElement.setClassName(resources.defaultCategoriesListCss().headerText()); textElement.setInnerText(category.toUpperCase()); Icon icon = iconRegistry.getIconIfExist(category + ".samples.category.icon"); if (icon != null) { Element iconElement = null; if (icon.getSVGImage() != null) { iconElement = icon.getSVGImage().getElement(); iconElement.setAttribute("class", resources.defaultCategoriesListCss().headerIcon()); } else if (icon.getImage() != null) { iconElement = icon.getImage().getElement(); iconElement.setClassName(resources.defaultCategoriesListCss().headerIcon()); } if (iconElement != null) { SpanElement spanElement = Document.get().createSpanElement(); spanElement.appendChild(iconElement); spanElement.appendChild(textElement); return spanElement; } } return textElement; } @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 resetName() { projectName.setText(""); projectDescription.setText(""); projectPublic.setValue(true); projectPrivate.setValue(false); changeEnabledState(true); } @Override public void setName(String name) { projectName.setValue(name, true); } /** {@inheritDoc} */ @Override public void setDescription(String description) { projectDescription.setValue(description); } @Override public void setVisibility(boolean visible) { projectPublic.setValue(visible, false); projectPrivate.setValue(!visible, false); } @Override public void removeNameError() { projectName.removeStyleName(style.inputError()); } @Override public void showNameError() { projectName.addStyleName(style.inputError()); } @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) { ProjectTypeDefinition typeDescriptor = null; for (String category : typesByCategory.keySet()) { for (ProjectTypeDefinition descriptor : typesByCategory.get(category)) { if (descriptor.getId().equals(projectTypeId)) { typeDescriptor = descriptor; break; } } if (typeDescriptor != null) { break; } } if (typeDescriptor != null) { for (ProjectTypeDefinition existingProjectTypeDescriptor : availableProjectTypes) { if (existingProjectTypeDescriptor.getId().equals(typeDescriptor.getId())) { categoriesList.selectElement(typeDescriptor); selectNextWizardType(typeDescriptor); } } } projectName.setFocus(true); } @Override public void setProjectTypes(List<ProjectTypeDefinition> availableProjectTypes) { this.availableProjectTypes = availableProjectTypes; } @Override public void setCategories(Map<String, Set<ProjectTypeDefinition>> typesByCategory, Map<String, Set<ProjectTemplateDescriptor>> templatesByCategory) { this.typesByCategory = typesByCategory; this.templatesByCategory = templatesByCategory; } @Override public void updateCategories(boolean includeTemplates) { List<Category<?>> categories = new ArrayList<>(); for (String typeCategory : typesByCategory.keySet()) { List<ProjectTypeDefinition> projectTypeDescriptors = new ArrayList<>(); projectTypeDescriptors.addAll(typesByCategory.get(typeCategory)); Collections.sort(projectTypeDescriptors, projectTypesComparator); categories.add(new Category<>(typeCategory, projectTypeCategoryRenderer, projectTypeDescriptors, projectTypeCategoryEventDelegate)); } // Sort project type categories only. Project templates categories should be in the end. Collections.sort(categories, categoriesComparator); if (includeTemplates) { for (String templateCategory : templatesByCategory.keySet()) { List<ProjectTemplateDescriptor> templateDescriptors = new ArrayList<>(); templateDescriptors.addAll(templatesByCategory.get(templateCategory)); Collections.sort(templateDescriptors, templatesComparator); categories.add(new Category<>(templateCategory, templateCategoryRenderer, templateDescriptors, templateCategoryEventDelegate)); } } categoriesList.render(categories); } @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 Styles { String mainPanel(); String leftPart(); String rightPart(); String namePanel(); String labelPosition(); String inputFieldPosition(); String radioButtonPosition(); String categories(); String description(); String configuration(); String label(); String horizontalLine(); String labelTitle(); String treeIcon(); } /** * 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<ProjectTypeDefinition> { @Override public int compare(ProjectTypeDefinition o1, ProjectTypeDefinition 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()); } } }