/******************************************************************************* * 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.ext.java.client.navigation.openimplementation; import com.google.common.base.Optional; import com.google.gwt.core.client.Scheduler; import com.google.inject.Inject; import com.google.inject.Singleton; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.editor.EditorPartPresenter; import org.eclipse.che.ide.api.editor.OpenEditorCallbackImpl; import org.eclipse.che.ide.api.editor.position.PositionConverter; import org.eclipse.che.ide.api.editor.text.LinearRange; import org.eclipse.che.ide.api.editor.texteditor.TextEditor; import org.eclipse.che.ide.api.resources.Container; import org.eclipse.che.ide.api.resources.File; import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.api.resources.Resource; import org.eclipse.che.ide.api.resources.SyntheticFile; import org.eclipse.che.ide.api.resources.VirtualFile; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.ext.java.client.JavaLocalizationConstant; import org.eclipse.che.ide.ext.java.client.JavaResources; import org.eclipse.che.ide.ext.java.client.navigation.service.JavaNavigationService; import org.eclipse.che.ide.ext.java.client.resource.SourceFolderMarker; import org.eclipse.che.ide.ext.java.client.util.JavaUtil; import org.eclipse.che.ide.ext.java.shared.JarEntry; import org.eclipse.che.ide.ext.java.shared.dto.ClassContent; import org.eclipse.che.ide.ext.java.shared.dto.ImplementationsDescriptorDTO; import org.eclipse.che.ide.ext.java.shared.dto.Region; import org.eclipse.che.ide.ext.java.shared.dto.model.Member; import org.eclipse.che.ide.ext.java.shared.dto.model.Type; import org.eclipse.che.ide.resource.Path; import org.eclipse.che.ide.ui.popup.PopupResources; import org.eclipse.che.ide.util.loging.Log; import static com.google.common.base.Strings.isNullOrEmpty; /** * The class that manages implementations structure window. * * @author Valeriy Svydenko */ @Singleton public class OpenImplementationPresenter { private final JavaNavigationService service; private final AppContext context; private final EditorAgent editorAgent; private final DtoFactory dtoFactory; private final JavaResources javaResources; private final PopupResources popupResources; private final JavaLocalizationConstant locale; private TextEditor activeEditor; @Inject public OpenImplementationPresenter(JavaNavigationService javaNavigationService, AppContext context, DtoFactory dtoFactory, JavaResources javaResources, PopupResources popupResources, JavaLocalizationConstant locale, EditorAgent editorAgent) { this.service = javaNavigationService; this.context = context; this.dtoFactory = dtoFactory; this.javaResources = javaResources; this.popupResources = popupResources; this.locale = locale; this.editorAgent = editorAgent; } /** * Shows the implementations of the selected element. * * @param editorPartPresenter * the active editor */ public void show(final EditorPartPresenter editorPartPresenter) { if (!(editorPartPresenter instanceof TextEditor)) { Log.error(getClass(), "Open Declaration support only TextEditor as editor"); return; } activeEditor = ((TextEditor)editorPartPresenter); final VirtualFile file = activeEditor.getEditorInput().getFile(); if (file instanceof Resource) { final Optional<Project> project = ((Resource)file).getRelatedProject(); final Optional<Resource> srcFolder = ((Resource)file).getParentWithMarker(SourceFolderMarker.ID); if (!srcFolder.isPresent()) { return; } final String fqn = JavaUtil.resolveFQN((Container)srcFolder.get(), (Resource)file); service.getImplementations(project.get().getLocation(), fqn, activeEditor.getCursorOffset()).then( new Operation<ImplementationsDescriptorDTO>() { @Override public void apply(ImplementationsDescriptorDTO impls) throws OperationException { int overridingSize = impls.getImplementations().size(); String title = locale.openImplementationWindowTitle(impls.getMemberName(), overridingSize); NoImplementationWidget noImplementationWidget = new NoImplementationWidget(popupResources, javaResources, locale, OpenImplementationPresenter.this, title); if (overridingSize == 1) { actionPerformed(impls.getImplementations().get(0)); } else if (overridingSize > 1) { openOneImplementation(impls, noImplementationWidget, (TextEditor)editorPartPresenter); } else if (!isNullOrEmpty(impls.getMemberName()) && overridingSize == 0) { showNoImplementations(noImplementationWidget, (TextEditor)editorPartPresenter); } } }); } } public void actionPerformed(final Member member) { if (member.isBinary()) { final Resource resource = context.getResource(); if (resource == null) { return; } final Optional<Project> project = resource.getRelatedProject(); service.getEntry(project.get().getLocation(), member.getLibId(), member.getRootPath()) .then(new Operation<JarEntry>() { @Override public void apply(final JarEntry entry) throws OperationException { service.getContent(project.get().getLocation(), member.getLibId(), Path.valueOf(entry.getPath())) .then(new Operation<ClassContent>() { @Override public void apply(ClassContent content) throws OperationException { final String clazz = entry.getName().substring(0, entry.getName().indexOf('.')); final VirtualFile file = new SyntheticFile(entry.getName(), clazz, content.getContent()); editorAgent.openEditor(file, new OpenEditorCallbackImpl() { @Override public void onEditorOpened(EditorPartPresenter editor) { setCursor(member.getFileRegion()); } }); } }); } }); } else { context.getWorkspaceRoot().getFile(member.getRootPath()).then(new Operation<Optional<File>>() { @Override public void apply(Optional<File> file) throws OperationException { if (file.isPresent()) { editorAgent.openEditor(file.get(), new OpenEditorCallbackImpl() { @Override public void onEditorOpened(EditorPartPresenter editor) { setCursor(member.getFileRegion()); } }); } } }); } Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { @Override public void execute() { activeEditor.setFocus(); } }); } private void showNoImplementations(NoImplementationWidget noImplementationWidget, TextEditor editorPartPresenter) { int offset = editorPartPresenter.getCursorOffset(); PositionConverter.PixelCoordinates coordinates = editorPartPresenter.getPositionConverter().offsetToPixel(offset); Type type = dtoFactory.createDto(Type.class); type.setFlags(-1); noImplementationWidget.addItem(type); noImplementationWidget.show(coordinates.getX(), coordinates.getY()); } private void openOneImplementation(ImplementationsDescriptorDTO implementationsDescriptor, NoImplementationWidget implementationWidget, TextEditor editorPartPresenter) { int offset = editorPartPresenter.getCursorOffset(); PositionConverter.PixelCoordinates coordinates = editorPartPresenter.getPositionConverter().offsetToPixel(offset); for (Type type : implementationsDescriptor.getImplementations()) { implementationWidget.addItem(type); } implementationWidget.show(coordinates.getX(), coordinates.getY()); implementationWidget.asElement().getStyle().setWidth(600 + "px"); } private void setCursor(final Region region) { if (!(editorAgent.getActiveEditor() instanceof TextEditor)) { return; } Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { @Override public void execute() { TextEditor editor = (TextEditor)editorAgent.getActiveEditor(); editor.setFocus(); editor.getDocument().setSelectedRange(LinearRange.createWithStart(region.getOffset()).andLength(0), true); } }); } }