/******************************************************************************* * 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.part.editor; import elemental.dom.Element; import elemental.dom.Node; import elemental.events.Event; import elemental.events.EventListener; import elemental.html.LIElement; import elemental.html.SpanElement; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.dom.client.DivElement; 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.user.client.Timer; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Widget; import com.google.inject.Provider; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.actions.CreateProjectAction; import org.eclipse.che.ide.actions.ImportProjectAction; import org.eclipse.che.ide.api.ProductInfoDataProvider; import org.eclipse.che.ide.api.action.Action; import org.eclipse.che.ide.api.action.ActionEvent; import org.eclipse.che.ide.api.action.ActionManager; import org.eclipse.che.ide.api.action.Presentation; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.keybinding.KeyBindingAgent; import org.eclipse.che.ide.api.parts.PerspectiveManager; import org.eclipse.che.ide.api.resources.Resource; import org.eclipse.che.ide.api.resources.ResourceChangedEvent; import org.eclipse.che.ide.api.resources.ResourceDelta; import org.eclipse.che.ide.api.theme.Style; import org.eclipse.che.ide.newresource.NewFileAction; import org.eclipse.che.ide.ui.toolbar.PresentationFactory; import org.eclipse.che.ide.util.dom.Elements; import org.eclipse.che.ide.util.input.KeyMapUtil; import org.vectomatic.dom.svg.ui.SVGImage; import org.vectomatic.dom.svg.ui.SVGResource; import javax.inject.Inject; import java.util.HashMap; import java.util.Map; import static java.util.Objects.nonNull; import static org.eclipse.che.ide.api.resources.Resource.PROJECT; /** * Represent empty state of editors panel */ public class EmptyEditorsPanel extends Composite implements ResourceChangedEvent.ResourceChangedHandler { private static EmptyEditorsPanelUiBinder ourUiBinder = GWT.create(EmptyEditorsPanelUiBinder.class); protected final AppContext appContext; private final ActionManager actionManager; private final Provider<PerspectiveManager> perspectiveManagerProvider; private final KeyBindingAgent keyBindingAgent; private final PresentationFactory presentationFactory; private final CoreLocalizationConstant localizationConstant; private final Map<String, Action> noFiles = new HashMap<>(); private final Map<String, Action> noProjects = new HashMap<>(); @UiField protected DivElement title; @UiField protected DivElement root; @UiField protected DivElement container; @UiField protected DivElement logo; @UiField Css style; @Inject public EmptyEditorsPanel(ActionManager actionManager, Provider<PerspectiveManager> perspectiveManagerProvider, KeyBindingAgent keyBindingAgent, ProductInfoDataProvider productInfoDataProvider, AppContext appContext, EventBus eventBus, CoreLocalizationConstant localizationConstant, NewFileAction newFileAction, CreateProjectAction createProjectAction, ImportProjectAction importProjectAction) { this(actionManager, perspectiveManagerProvider, keyBindingAgent, appContext, localizationConstant, newFileAction, createProjectAction, importProjectAction); eventBus.addHandler(ResourceChangedEvent.getType(), this); final SVGResource logo = productInfoDataProvider.getLogo(); if (nonNull(logo)) { this.logo.appendChild(new SVGImage(logo).getSvgElement().getElement()); } //Sometimes initialization of Create/Import Project actions are completed after the Empty editor page is rendered. //In this case we need to wait when actions will be initialized. Timer hoverToRenderTimer = new Timer() { @Override public void run() { renderNoProjects(); } }; hoverToRenderTimer.schedule(500); } public EmptyEditorsPanel(ActionManager actionManager, Provider<PerspectiveManager> perspectiveManagerProvider, KeyBindingAgent keyBindingAgent, AppContext appContext, CoreLocalizationConstant localizationConstant, NewFileAction newFileAction, CreateProjectAction createProjectAction, ImportProjectAction importProjectAction) { this.actionManager = actionManager; this.perspectiveManagerProvider = perspectiveManagerProvider; this.keyBindingAgent = keyBindingAgent; this.appContext = appContext; this.localizationConstant = localizationConstant; noFiles.put("Create File...", newFileAction); noFiles.put("Create Project...", createProjectAction); noProjects.put("Import Project...", importProjectAction); noProjects.put("Create Project...", createProjectAction); presentationFactory = new PresentationFactory(); Widget rootElement = ourUiBinder.createAndBindUi(this); initWidget(rootElement); } @Override public void onResourceChanged(ResourceChangedEvent event) { final ResourceDelta delta = event.getDelta(); final Resource resource = delta.getResource(); if (!(resource.getResourceType() == PROJECT && resource.getLocation().segmentCount() == 1)) { return; } Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { @Override public void execute() { updateOnProjectsChange(); } }); } private void updateOnProjectsChange() { if (appContext.getProjects().length != 0) { renderNoFiles(); } else { renderNoProjects(); } } protected void renderNoProjects() { render(localizationConstant.emptyStateNoProjects(), noProjects); } protected void renderNoFiles() { render(localizationConstant.emptyStateNoFiles(), noFiles); } private void render(String title, Map<String, Action> actions) { this.title.setInnerText(title); container.removeAllChildren(); Element listElement = Elements.createElement("ul", new String[] {style.list()}); for (Map.Entry<String, Action> pair : actions.entrySet()) { LIElement liElement = Elements.createLiElement(); liElement.appendChild(renderAction(pair.getKey(), pair.getValue())); listElement.appendChild(liElement); } container.appendChild((com.google.gwt.dom.client.Node)listElement); } private Node renderAction(String title, final Action action) { final Presentation presentation = presentationFactory.getPresentation(action); Element divElement = Elements.createDivElement(style.listElement()); divElement.addEventListener("click", new EventListener() { @Override public void handleEvent(Event evt) { ActionEvent event = new ActionEvent(presentation, actionManager, perspectiveManagerProvider.get()); action.actionPerformed(event); } }, true); divElement.getStyle().setCursor("pointer"); divElement.getStyle().setColor(Style.getOutputLinkColor()); Element label = Elements.createDivElement(style.actionLabel()); label.setInnerText(title); divElement.appendChild(label); String hotKey = KeyMapUtil.getShortcutText(keyBindingAgent.getKeyBinding(actionManager.getId(action))); if (hotKey == null) { hotKey = " "; } else { hotKey = "<nobr> " + hotKey + " </nobr>"; } SpanElement hotKeyElement = Elements.createSpanElement(style.hotKey()); hotKeyElement.setInnerHTML(hotKey); divElement.appendChild(hotKeyElement); return divElement; } interface Css extends CssResource { String list(); String parent(); String center(); String child(); String listElement(); String title(); String hotKey(); String actionLabel(); } interface EmptyEditorsPanelUiBinder extends UiBinder<Widget, EmptyEditorsPanel> {} }