package krasa.frameswitcher;
import com.google.common.collect.Multimap;
import com.intellij.ide.RecentProjectsManagerBase;
import com.intellij.ide.ReopenProjectAction;
import com.intellij.ide.actions.QuickSwitchSchemeAction;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.keymap.ex.KeymapManagerEx;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.ui.popup.PopupFactoryImpl;
import com.intellij.ui.popup.list.ListPopupImpl;
import com.intellij.ui.popup.list.ListPopupModel;
import krasa.frameswitcher.networking.dto.RemoteProject;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.*;
public class FrameSwitchAction extends QuickSwitchSchemeAction implements DumbAware {
private final Logger LOG = Logger.getInstance("#" + getClass().getCanonicalName());
@Override
protected void fillActions(final Project currentProject, DefaultActionGroup group, DataContext dataContext) {
addFrames(currentProject, group);
addRemote(group);
addRecent(group);
addRemoteRecent(group);
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Project project = e.getData(CommonDataKeys.PROJECT);
DefaultActionGroup group = new DefaultActionGroup();
fillActions(project, group, e.getDataContext());
showPopup(e, group);
}
private void showPopup(AnActionEvent e, DefaultActionGroup group) {
if (group.getChildrenCount() == 0) return;
JBPopupFactory.ActionSelectionAid aid = getAidMethod();
Condition<AnAction> condition ;
if (FrameSwitcherSettings.getInstance().isDefaultSelectionCurrentProject()) {
//noinspection unchecked
condition = Condition.FALSE;
} else {
condition = (a) -> a.getTemplatePresentation().getIcon() != ourCurrentAction;
}
ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup(
getPopupTitle(e), group, e.getDataContext(), aid, true, null, -1,
condition, myActionPlace);
showPopup(e, popup);
}
private void addFrames(Project currentProject, DefaultActionGroup group) {
WindowManager windowManager = WindowManager.getInstance();
ArrayList<IdeFrame> ideFrames = getIdeFrames();
ProjectFocusMonitor projectFocusMonitor = FrameSwitcherApplicationComponent.getInstance().getProjectFocusMonitor();
Project[] projectsOrderedByFocus = projectFocusMonitor.getProjectsOrderedByFocus();
for (int i = projectsOrderedByFocus.length - 1; i >= 0; i--) {
Project project = projectsOrderedByFocus[i];
add(currentProject, group, project);
IdeFrame frame = (IdeFrame) windowManager.getFrame(project);
if (frame != null) {
ideFrames.remove(frame);
}
}
for (final IdeFrame frame : ideFrames) {
final Project project = frame.getProject();
if (project != null) {
add(currentProject, group, project);
}
}
}
private void add(Project currentProject, DefaultActionGroup group, final Project project) {
Icon itemIcon = (currentProject == project) ? ourCurrentAction : ourNotCurrentAction;
DumbAwareAction action = new DumbAwareAction(project.getName().replace("_","__"), null, itemIcon) {
@Override
public void actionPerformed(AnActionEvent e) {
FocusUtils.requestFocus(project, false);
}
};
group.addAction(action);
}
private void addRemote(DefaultActionGroup group) {
final FrameSwitcherApplicationComponent applicationComponent = FrameSwitcherApplicationComponent.getInstance();
applicationComponent.getRemoteInstancesState().sweepRemoteInstance();
Multimap<UUID, RemoteProject> remoteProjectMultimap = FrameSwitcherApplicationComponent.getInstance().getRemoteInstancesState().getRemoteProjects();
applicationComponent.getRemoteSender().pingRemote();
if (remoteProjectMultimap.size() > 0) {
group.addSeparator("RemoteProjects");
}
for (final UUID uuid : remoteProjectMultimap.keySet()) {
Collection<RemoteProject> remoteProjects = remoteProjectMultimap.get(uuid);
for (final RemoteProject remoteProject : remoteProjects) {
group.add(new DumbAwareAction(remoteProject.getName()) {
@Override
public void actionPerformed(AnActionEvent anActionEvent) {
FrameSwitcherApplicationComponent.getInstance().getRemoteSender().openProject(uuid, remoteProject);
}
});
}
}
}
private void addRecent(DefaultActionGroup group) {
RecentProjectsManagerBase recentProjectsManagerBase = FrameSwitcherUtils.getRecentProjectsManagerBase();
final AnAction[] recentProjectsActions = recentProjectsManagerBase.getRecentProjectsActions(false);
if (recentProjectsActions != null) {
FrameSwitcherSettings settings = FrameSwitcherSettings.getInstance();
int i = 0;
for (AnAction action : recentProjectsActions) {
ReopenProjectAction recentProjectsAction = (ReopenProjectAction) action;
if (settings.shouldShow(recentProjectsAction)) {
if (i == 0) {
group.addSeparator("Recent");
}
group.add(recentProjectsAction);
i++;
}
}
}
}
private void addRemoteRecent(DefaultActionGroup group) {
Multimap<UUID, RemoteProject> remoteRecentProjects = FrameSwitcherApplicationComponent.getInstance().getRemoteInstancesState().getRemoteRecentProjects();
Set<UUID> entries = remoteRecentProjects.keySet();
boolean addedSeparator = false;
if (remoteRecentProjects.size() > 0) {
FrameSwitcherSettings settings = FrameSwitcherSettings.getInstance();
for (UUID entry : entries.toArray(new UUID[entries.size()])) {
int i = 0;
for (RemoteProject remoteProject : remoteRecentProjects.get(entry)) {
if (settings.shouldShow(remoteProject)) {
if (!addedSeparator) {
addedSeparator = true;
group.addSeparator("Remote recent");
}
group.add(new ReopenProjectAction(remoteProject.getProjectPath(), remoteProject.getName(),
remoteProject.getName()));
i++;
}
}
}
}
}
public ArrayList<IdeFrame> getIdeFrames() {
IdeFrame[] allProjectFrames = WindowManager.getInstance().getAllProjectFrames();
ArrayList<IdeFrame> list = new ArrayList<IdeFrame>(allProjectFrames.length);
list.addAll(Arrays.asList(allProjectFrames));
Collections.sort(list, new Comparator<IdeFrame>() {
@Override
public int compare(IdeFrame o1, IdeFrame o2) {
Project project1 = o1.getProject();
Project project2 = o2.getProject();
if (project1 == null && project2 == null) {
return 0;
}
if (project1 == null) {
return -1;
}
if (project2 == null) {
return 1;
}
return project1.getName().compareToIgnoreCase(project2.getName());
}
});
return list;
}
@Override
protected void showPopup(AnActionEvent e, ListPopup p) {
final ListPopupImpl popup = (ListPopupImpl) p;
registerActions(popup);
super.showPopup(e, popup);
}
private void registerActions(final ListPopupImpl popup) {
final Ref<Boolean> invoked = Ref.create(false);
Shortcut[] frameSwitchActions = KeymapManagerEx.getInstanceEx().getActiveKeymap().getShortcuts("FrameSwitchAction");
if (frameSwitchActions == null) {
return;
}
for (Shortcut switchAction : frameSwitchActions) {
if (switchAction instanceof KeyboardShortcut) {
KeyboardShortcut keyboardShortcut = (KeyboardShortcut) switchAction;
String[] split = keyboardShortcut.getFirstKeyStroke().toString().split(" ");
for (String s : split) {
if (s.equalsIgnoreCase("alt")
|| s.equalsIgnoreCase("ctrl")
|| s.equalsIgnoreCase("meta")
) {
if (s.equalsIgnoreCase("ctrl")) {
s = "control";
}
popup.registerAction(s + "Released", KeyStroke.getKeyStroke("released " + s.toUpperCase()), new AbstractAction() {
public void actionPerformed(ActionEvent e) {
if (invoked.get()) {
popup.handleSelect(true);
}
}
});
}
}
popup.registerAction("invoke", keyboardShortcut.getFirstKeyStroke(), new AbstractAction() {
public void actionPerformed(ActionEvent e) {
invoked.set(true);
JList list = popup.getList();
int selectedIndex = list.getSelectedIndex();
int size = list.getModel().getSize();
if (selectedIndex + 1 < size) {
list.setSelectedIndex(selectedIndex + 1);
} else {
list.setSelectedIndex(0);
}
}
});
popup.registerAction("invokeWithShift", KeyStroke.getKeyStroke("shift " + keyboardShortcut.getFirstKeyStroke()), new AbstractAction() {
public void actionPerformed(ActionEvent e) {
invoked.set(true);
JList list = popup.getList();
int selectedIndex = list.getSelectedIndex();
int size = list.getModel().getSize();
if (selectedIndex - 1 >= 0) {
list.setSelectedIndex(selectedIndex - 1);
} else {
list.setSelectedIndex(size - 1);
}
}
});
popup.registerAction("invokeWithDelete", KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), new AbstractAction() {
public void actionPerformed(ActionEvent e) {
invoked.set(true);
JList list = popup.getList();
int selectedIndex = list.getSelectedIndex();
ListPopupModel model = (ListPopupModel) list.getModel();
PopupFactoryImpl.ActionItem selectedItem = (PopupFactoryImpl.ActionItem) model.get(selectedIndex);
if (selectedItem != null && selectedItem.getAction() instanceof ReopenProjectAction) {
ReopenProjectAction action = (ReopenProjectAction) selectedItem.getAction();
FrameSwitcherUtils.getRecentProjectsManagerBase().removePath(action.getProjectPath());
model.deleteItem(selectedItem);
if (selectedIndex == list.getModel().getSize()) { //is last
list.setSelectedIndex(selectedIndex - 1);
} else {
list.setSelectedIndex(selectedIndex);
}
}
}
});
}
}
}
@Override
protected boolean isEnabled() {
return true;
}
protected JBPopupFactory.ActionSelectionAid getAidMethod() {
return FrameSwitcherSettings.getInstance().getPopupSelectionAid();
}
}