blob: fcd7372084ab511f879cb962c5983e6789ba87b4 [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.scratch;
import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.CustomStatusBarWidget;
import com.intellij.openapi.wm.StatusBarWidget;
import com.intellij.openapi.wm.impl.status.EditorBasedWidget;
import com.intellij.openapi.wm.impl.status.TextPanel;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.ui.ClickListener;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.FileContentUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.Collections;
import java.util.List;
class ScratchWidget extends EditorBasedWidget implements CustomStatusBarWidget.Multiframe, CustomStatusBarWidget {
public static final String ID = "Scratch";
private final MyTextPanel myPanel = new MyTextPanel();
public ScratchWidget(Project project) {
super(project);
new ClickListener() {
@Override
public boolean onClick(@NotNull MouseEvent e, int clickCount) {
Project project = getProject();
Editor editor = getEditor();
VirtualFile selectedFile = getSelectedFile();
if (project == null || editor == null || selectedFile == null) return false;
DataContext dataContext = createDataContext(editor, myPanel, selectedFile, project);
actionPerformed(dataContext);
update();
return true;
}
}.installOn(myPanel);
}
@NotNull
@Override
public String ID() {
return ID;
}
@Nullable
@Override
public WidgetPresentation getPresentation(@NotNull PlatformType type) {
return null;
}
private void update() {
VirtualFile file = getSelectedFile();
boolean enabled = checkEnabled(file);
if (enabled) {
Language lang = ((LightVirtualFile)file).getLanguage();
myPanel.setText(lang.getDisplayName());
myPanel.setBorder(WidgetBorder.INSTANCE);
myPanel.setIcon(getDefaultIcon(lang));
}
else {
myPanel.setBorder(null);
}
myPanel.setVisible(enabled);
if (myStatusBar != null) myStatusBar.updateWidget(ID);
}
@NotNull
public static DataContext createDataContext(Editor editor, Component component, VirtualFile selectedFile, Project project) {
DataContext parent = DataManager.getInstance().getDataContext(component);
DataContext context = SimpleDataContext.getSimpleContext(PlatformDataKeys.CONTEXT_COMPONENT.getName(), editor == null ? null : editor.getComponent(), parent);
DataContext projectContext = SimpleDataContext.getSimpleContext(CommonDataKeys.PROJECT.getName(), project, context);
return SimpleDataContext.getSimpleContext(CommonDataKeys.VIRTUAL_FILE.getName(), selectedFile, projectContext);
}
void actionPerformed(DataContext context) {
ListPopup popup = createPopup(context);
if (popup != null) {
Dimension dimension = popup.getContent().getPreferredSize();
Point at = new Point(0, -dimension.height);
popup.show(new RelativePoint(myPanel, at));
}
}
@Nullable
private ListPopup createPopup(DataContext context) {
final VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(context);
boolean enabled = checkEnabled(virtualFile);
if (!enabled) return null;
List<Language> languages = CreateScratchFileAction.getLanguages();
DefaultActionGroup group = createActionGroup(virtualFile, languages);
ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup("Choose language", group, context, JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false);
return CreateScratchFileAction.updatePopupSize(popup, languages);
}
@NotNull
private DefaultActionGroup createActionGroup(@NotNull VirtualFile virtualFile, @NotNull List<Language> languages) {
List<AnAction> list = ContainerUtil.newArrayListWithCapacity(languages.size());
for (Language language : languages) {
list.add(new ChangeLanguageAction(virtualFile, language));
}
return new DefaultActionGroup("Change language", list);
}
@Contract("null -> false")
private static boolean checkEnabled(@Nullable VirtualFile virtualFile) {
return virtualFile != null && virtualFile.getFileSystem() instanceof ScratchpadFileSystem;
}
@Override
public StatusBarWidget copy() {
return new ScratchWidget(myProject);
}
@Override
public JComponent getComponent() {
return myPanel;
}
@Override
public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
update();
super.fileOpened(source, file);
}
@Override
public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
update();
super.fileClosed(source, file);
}
@Override
public void selectionChanged(@NotNull FileEditorManagerEvent event) {
update();
super.selectionChanged(event);
}
private static Icon getDefaultIcon(@NotNull Language language) {
LanguageFileType associatedLanguage = language.getAssociatedFileType();
return associatedLanguage != null ? associatedLanguage.getIcon() : null;
}
private static class MyTextPanel extends TextPanel {
private int myIconTextGap = 2;
private Icon myIcon;
@Override
protected void paintComponent(@NotNull final Graphics g) {
super.paintComponent(g);
if (getText() != null) {
Rectangle r = getBounds();
Insets insets = getInsets();
AllIcons.Ide.Statusbar_arrows.paintIcon(this, g, r.width - insets.right - AllIcons.Ide.Statusbar_arrows.getIconWidth() - 2,
r.height / 2 - AllIcons.Ide.Statusbar_arrows.getIconHeight() / 2);
if (myIcon != null) {
myIcon.paintIcon(this, g, insets.left - myIconTextGap - myIcon.getIconWidth(), r.height / 2 - myIcon.getIconHeight() / 2);
}
}
}
@NotNull
@Override
public Insets getInsets() {
Insets insets = super.getInsets();
if (myIcon != null) {
insets.left += myIcon.getIconWidth() + myIconTextGap * 2;
}
return insets;
}
@Override
public Dimension getPreferredSize() {
final Dimension preferredSize = super.getPreferredSize();
int deltaWidth = AllIcons.Ide.Statusbar_arrows.getIconWidth() + myIconTextGap * 2;
if (myIcon != null) {
deltaWidth += myIcon.getIconWidth() + myIconTextGap * 2;
}
return new Dimension(preferredSize.width + deltaWidth, preferredSize.height);
}
public void setIcon(Icon icon) {
myIcon = icon;
}
}
private class ChangeLanguageAction extends AnAction implements DumbAware {
private final VirtualFile myVirtualFile;
private final Language myLanguage;
public ChangeLanguageAction(@NotNull VirtualFile virtualFile, @NotNull Language language) {
super(language.getDisplayName(), "", getDefaultIcon(language));
myVirtualFile = virtualFile;
myLanguage = language;
}
@Override
public void actionPerformed(AnActionEvent e) {
Project project = e.getProject();
if (project == null) return;
if (myVirtualFile instanceof LightVirtualFile) {
((LightVirtualFile)myVirtualFile).setLanguage(myLanguage);
FileContentUtil.reparseFiles(project, Collections.singletonList(myVirtualFile), false);
ScratchWidget.this.update();
}
}
}
}