blob: e3bf3b5e6f6fab924e685df2213c2a5cd87e3b27 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide.browsers.actions;
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.browsers.*;
import com.intellij.ide.browsers.impl.WebBrowserServiceImpl;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.AsyncResult;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.ui.ColoredListCellRenderer;
import com.intellij.ui.components.JBList;
import com.intellij.util.Consumer;
import com.intellij.util.ObjectUtils;
import com.intellij.util.Url;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xml.util.HtmlUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.event.InputEvent;
import java.util.Collection;
public abstract class BaseOpenInBrowserAction extends DumbAwareAction {
private static final Logger LOG = Logger.getInstance(BaseOpenInBrowserAction.class);
protected BaseOpenInBrowserAction(@NotNull WebBrowser browser) {
super(browser.getName(), null, browser.getIcon());
}
@SuppressWarnings("UnusedDeclaration")
protected BaseOpenInBrowserAction(@Nullable String text, @Nullable String description, @Nullable Icon icon) {
super(text, description, icon);
}
@Nullable
protected abstract WebBrowser getBrowser(@NotNull AnActionEvent event);
@Override
public final void update(AnActionEvent e) {
WebBrowser browser = getBrowser(e);
if (browser == null) {
e.getPresentation().setEnabledAndVisible(false);
return;
}
Pair<OpenInBrowserRequest, WebBrowserUrlProvider> result = doUpdate(e);
if (result == null) {
return;
}
String description = getTemplatePresentation().getText();
if (ActionPlaces.CONTEXT_TOOLBAR.equals(e.getPlace())) {
StringBuilder builder = new StringBuilder(description);
builder.append(" (");
Shortcut[] shortcuts = KeymapManager.getInstance().getActiveKeymap().getShortcuts("WebOpenInAction");
boolean exists = shortcuts.length > 0;
if (exists) builder.append(KeymapUtil.getShortcutText(shortcuts[0]));
if (HtmlUtil.isHtmlFile(result.first.getFile())) {
builder.append(exists ? ", " : "").append("hold Shift to open URL of local file");
}
builder.append(')');
description = builder.toString();
}
e.getPresentation().setText(description);
}
@Override
public final void actionPerformed(AnActionEvent e) {
WebBrowser browser = getBrowser(e);
if (browser != null) {
open(e, browser);
}
}
@Nullable
public static OpenInBrowserRequest createRequest(@NotNull DataContext context) {
final Editor editor = CommonDataKeys.EDITOR.getData(context);
if (editor != null) {
Project project = editor.getProject();
if (project != null && project.isInitialized()) {
PsiFile psiFile = CommonDataKeys.PSI_FILE.getData(context);
if (psiFile == null) {
psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
}
if (psiFile != null) {
return new OpenInBrowserRequest(psiFile) {
private PsiElement element;
@NotNull
@Override
public PsiElement getElement() {
if (element == null) {
element = getFile().findElementAt(editor.getCaretModel().getOffset());
}
return ObjectUtils.chooseNotNull(element, getFile());
}
};
}
}
}
else {
PsiFile psiFile = CommonDataKeys.PSI_FILE.getData(context);
VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(context);
Project project = CommonDataKeys.PROJECT.getData(context);
if (virtualFile != null && !virtualFile.isDirectory() && virtualFile.isValid() && project != null && project.isInitialized()) {
psiFile = PsiManager.getInstance(project).findFile(virtualFile);
}
if (psiFile != null) {
return OpenInBrowserRequest.create(psiFile);
}
}
return null;
}
@Nullable
public static Pair<OpenInBrowserRequest, WebBrowserUrlProvider> doUpdate(@NotNull AnActionEvent event) {
OpenInBrowserRequest request = createRequest(event.getDataContext());
boolean applicable = false;
WebBrowserUrlProvider provider = null;
if (request != null) {
applicable = WebBrowserServiceImpl.isHtmlOrXmlFile(request.getFile()) && !(request.getVirtualFile() instanceof LightVirtualFile);
if (!applicable) {
provider = WebBrowserServiceImpl.getProvider(request);
applicable = provider != null;
}
}
event.getPresentation().setEnabledAndVisible(applicable);
return applicable ? Pair.create(request, provider) : null;
}
public static void open(@NotNull AnActionEvent event, @Nullable WebBrowser browser) {
open(createRequest(event.getDataContext()), (event.getModifiers() & InputEvent.SHIFT_MASK) != 0, browser);
}
public static void open(@Nullable final OpenInBrowserRequest request, boolean preferLocalUrl, @Nullable final WebBrowser browser) {
if (request == null) {
return;
}
try {
Collection<Url> urls = WebBrowserService.getInstance().getUrlsToOpen(request, preferLocalUrl);
if (!urls.isEmpty()) {
chooseUrl(urls).doWhenDone(new Consumer<Url>() {
@Override
public void consume(Url url) {
ApplicationManager.getApplication().saveAll();
BrowserLauncher.getInstance().browse(url.toExternalForm(), browser, request.getProject());
}
});
}
}
catch (WebBrowserUrlProvider.BrowserException e1) {
Messages.showErrorDialog(e1.getMessage(), IdeBundle.message("browser.error"));
}
catch (Exception e1) {
LOG.error(e1);
}
}
@NotNull
private static AsyncResult<Url> chooseUrl(@NotNull Collection<Url> urls) {
if (urls.size() == 1) {
return new AsyncResult.Done<Url>(ContainerUtil.getFirstItem(urls));
}
final JBList list = new JBList(urls);
list.setCellRenderer(new ColoredListCellRenderer() {
@Override
protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) {
// todo icons looks good, but is it really suitable for all URLs providers?
setIcon(AllIcons.Nodes.Servlet);
append(((Url)value).toDecodedForm());
}
});
final AsyncResult<Url> result = new AsyncResult<Url>();
JBPopupFactory.getInstance().
createListPopupBuilder(list).
setTitle("Choose Url").
setItemChoosenCallback(new Runnable() {
@Override
public void run() {
Url value = (Url)list.getSelectedValue();
if (value != null) {
result.setDone(value);
}
else {
result.setRejected();
}
}
}).
createPopup().showInFocusCenter();
return result;
}
}