/*
* Copyright 2000-2015 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.actions;
import com.intellij.execution.ui.layout.ViewContext;
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeBundle;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileEditor.impl.EditorWindow;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentManager;
import com.intellij.ui.content.ContentManagerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Pins any kind of tab in context: editor tab, toolwindow tab or other tabs.
*
* todo drop TW and EW, both are only for menu|Window tab/editor sub-menus.
*/
public class PinActiveTabAction extends DumbAwareAction implements Toggleable {
public static abstract class Handler {
public final boolean isPinned;
public final boolean isActiveTab;
abstract void setPinned(boolean value);
public Handler(boolean isPinned, boolean isActiveTab) {
this.isPinned = isPinned;
this.isActiveTab = isActiveTab;
}
}
@Override
public void actionPerformed(AnActionEvent e) {
Handler handler = getHandler(e);
if (handler == null) return;
boolean selected = !handler.isPinned;
handler.setPinned(selected);
e.getPresentation().putClientProperty(SELECTED_PROPERTY, selected);
}
@Override
public void update(@NotNull AnActionEvent e) {
Handler handler = getHandler(e);
boolean enabled = handler != null;
boolean selected = enabled && handler.isPinned;
e.getPresentation().setIcon(ActionPlaces.isToolbarPlace(e.getPlace()) ? AllIcons.General.Pin_tab : null);
e.getPresentation().putClientProperty(SELECTED_PROPERTY, selected);
String text;
// add the word "active" if the target tab is not current
if (ActionPlaces.isMainMenuOrActionSearch(e.getPlace()) || handler != null && !handler.isActiveTab) {
text = selected ? IdeBundle.message("action.unpin.active.tab") : IdeBundle.message("action.pin.active.tab");
}
else {
text = selected ? IdeBundle.message("action.unpin.tab") : IdeBundle.message("action.pin.tab");
}
e.getPresentation().setText(text);
e.getPresentation().setEnabledAndVisible(enabled);
}
protected Handler getHandler(@NotNull AnActionEvent e) {
Project project = e.getProject();
EditorWindow currentWindow = e.getData(EditorWindow.DATA_KEY);
Content content = currentWindow != null ? null : getContentFromEvent(e);
if (content != null && content.isPinnable()) {
return createHandler(content);
}
final EditorWindow window = currentWindow != null ? currentWindow :
project != null ? FileEditorManagerEx.getInstanceEx(project).getCurrentWindow() : null;
VirtualFile selectedFile = window == null ? null : getFileFromEvent(e, window);
if (selectedFile != null) {
return createHandler(window, selectedFile);
}
return null;
}
@Nullable
protected VirtualFile getFileFromEvent(@NotNull AnActionEvent e, @NotNull EditorWindow window) {
return getFileInWindow(e, window);
}
@Nullable
protected Content getContentFromEvent(@NotNull AnActionEvent e) {
Content content = getNonToolWindowContent(e);
if (content == null) content = getToolWindowContent(e);
return content != null && content.isValid() ? content : null;
}
@NotNull
private static Handler createHandler(final Content content) {
return new Handler(content.isPinned(), content.getManager().getSelectedContent() == content) {
@Override
void setPinned(boolean value) {
content.setPinned(value);
}
};
}
@NotNull
private static Handler createHandler(final EditorWindow window, final VirtualFile selectedFile) {
return new Handler(window.isFilePinned(selectedFile), selectedFile.equals(window.getSelectedFile())) {
@Override
void setPinned(boolean value) {
window.setFilePinned(selectedFile, value);
}
};
}
@Nullable
private static Content getNonToolWindowContent(@NotNull AnActionEvent e) {
Content result = null;
Content[] contents = e.getData(ViewContext.CONTENT_KEY);
if (contents != null && contents.length == 1) result = contents[0];
if (result != null && result.isPinnable()) return result;
ContentManager contentManager = ContentManagerUtil.getContentManagerFromContext(e.getDataContext(), true);
result = contentManager != null? contentManager.getSelectedContent() : null;
if (result != null && result.isPinnable()) return result;
return null;
}
@Nullable
private static Content getToolWindowContent(@NotNull AnActionEvent e) {
// note to future readers: TW tab "pinned" icon is shown when content.getUserData(TW.SHOW_CONTENT_ICON) is true
ToolWindow window = PlatformDataKeys.TOOL_WINDOW.getData(e.getDataContext());
Content result = window != null ? window.getContentManager().getSelectedContent() : null;
return result != null && result.isPinnable() ? result : null;
}
@Nullable
private static VirtualFile getFileInWindow(@NotNull AnActionEvent e, @NotNull EditorWindow window) {
VirtualFile file = e.getData(CommonDataKeys.VIRTUAL_FILE);
if (file == null) file = window.getSelectedFile();
if (file != null && window.isFileOpen(file)) return file;
return null;
}
public static class TW extends PinActiveTabAction {
@Nullable
@Override
protected VirtualFile getFileFromEvent(@NotNull AnActionEvent e, @NotNull EditorWindow window) {
return null;
}
@Override
protected Content getContentFromEvent(@NotNull AnActionEvent e) {
return getToolWindowContent(e);
}
}
public static class EW extends PinActiveTabAction {
@Nullable
@Override
protected VirtualFile getFileFromEvent(@NotNull AnActionEvent e, @NotNull EditorWindow window) {
return window.getSelectedFile();
}
@Override
protected Content getContentFromEvent(@NotNull AnActionEvent e) {
return null;
}
}
}