package jetbrains.mps.execution.lib.ui; /*Generated by MPS */ import javax.swing.JPanel; import javax.swing.JList; import java.util.List; import jetbrains.mps.internal.collections.runtime.ListSequence; import java.util.ArrayList; import java.awt.event.ActionListener; import com.intellij.openapi.project.Project; import jetbrains.mps.project.MPSProject; import jetbrains.mps.ide.project.ProjectHelper; import java.awt.GridBagLayout; import java.awt.BorderLayout; import com.intellij.ui.components.JBList; import javax.swing.JScrollPane; import com.intellij.ui.ScrollPaneFactory; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.DefaultActionGroup; import jetbrains.mps.workbench.action.ActionUtils; import com.intellij.openapi.actionSystem.ActionToolbar; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.ui.components.JBLabel; import jetbrains.mps.ide.common.LayoutUtil; import org.jetbrains.mps.openapi.model.SNode; import org.jetbrains.mps.openapi.model.SNodeReference; import org.jetbrains.mps.openapi.util.ProgressMonitor; import com.intellij.openapi.progress.ProgressManager; import jetbrains.mps.progress.ProgressMonitorAdapter; import jetbrains.mps.internal.collections.runtime.ISelector; import jetbrains.mps.ide.platform.dialogs.choosers.NodeChooserDialog; import javax.swing.AbstractListModel; import jetbrains.mps.workbench.dialogs.project.components.parts.actions.ListAddAction; import com.intellij.openapi.actionSystem.AnActionEvent; import jetbrains.mps.baseLanguage.closures.runtime.Wrappers; import jetbrains.mps.smodel.SNodePointer; import jetbrains.mps.workbench.dialogs.project.components.parts.actions.ListRemoveAction; /** * This class was split up without thinking, just to make something work quickly. * TODO: refactor */ public abstract class ListPanel<T> extends JPanel { private final Object myLock = new Object(); private final JList myListComponent; protected final List<T> myValues = ListSequence.fromList(new ArrayList<T>()); protected final List<T> myCandidates = ListSequence.fromList(new ArrayList<T>()); private ActionListener myListener; private final ListPanel.MyAbstractListModel myListModel; protected Project myProject; private final MPSProject myMpsProject; private final String myTitle; private boolean isEditable = true; public ListPanel(Project p, String title) { myProject = p; myMpsProject = ProjectHelper.fromIdeaProject(p); myTitle = title; setLayout(new GridBagLayout()); JPanel mainPanel = new JPanel(new BorderLayout()); myListModel = new ListPanel.MyAbstractListModel(); myListComponent = new JBList(myListModel); JScrollPane scrolledListComponent = ScrollPaneFactory.createScrollPane(myListComponent); scrolledListComponent.doLayout(); mainPanel.add(scrolledListComponent, BorderLayout.CENTER); AnAction add = new ListPanel.MyListAddAction(myListComponent); AnAction remove = new ListPanel.MyListRemoveAction(this.myListComponent); DefaultActionGroup group = ActionUtils.groupFromActions(add, remove); ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, false); mainPanel.add(toolbar.getComponent(), BorderLayout.EAST); this.add(new JBLabel(myTitle + ":"), LayoutUtil.createLabelConstraints(0)); this.add(mainPanel, LayoutUtil.createPanelConstraints(1)); } protected abstract T wrap(SNode node); protected abstract SNodeReference unwrap(T element); protected abstract String getFqName(T element); protected abstract List<T> collectCandidates(ProgressMonitor progress); public void addItem(T item) { ListSequence.fromList(myValues).addElement(item); myListComponent.updateUI(); } public void addActionListener(ActionListener listener) { myListener = listener; } public List<T> getItems() { return myValues; } public void clear() { ListSequence.fromList(myValues).clear(); myListComponent.updateUI(); } public void setData(List<? extends T> data) { ListSequence.fromList(myValues).clear(); ListSequence.fromList(myValues).addSequence(ListSequence.fromList(data)); myListComponent.updateUI(); } private List<SNodeReference> getCandidates() { boolean needsUpdate; synchronized (myLock) { needsUpdate = ListSequence.fromList(this.myCandidates).isEmpty(); } if (needsUpdate) { ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { @Override public void run() { List<T> candidates = collectCandidates(new ProgressMonitorAdapter(ProgressManager.getInstance().getProgressIndicator())); synchronized (myLock) { ListSequence.fromList(myCandidates).clear(); ListSequence.fromList(myCandidates).addSequence(ListSequence.fromList(candidates)); } } }, "Searching for nodes", false, myProject); } synchronized (myLock) { ListSequence.fromList(this.myCandidates).removeSequence(ListSequence.fromList(this.myValues)); return ListSequence.fromList(this.myCandidates).select(new ISelector<T, SNodeReference>() { public SNodeReference select(T it) { return unwrap(it); } }).toListSequence(); } } public void setEditable(boolean editable) { isEditable = editable; } public NodeChooserDialog createNodeChooserDialog(List<SNodeReference> nodesList) { return new NodeChooserDialog(myProject, nodesList); } private class MyAbstractListModel extends AbstractListModel { public MyAbstractListModel() { } @Override public Object getElementAt(int p0) { return getFqName(ListSequence.fromList(ListPanel.this.myValues).getElement(p0)); } @Override public int getSize() { return ListSequence.fromList(ListPanel.this.myValues).count(); } public void fireSomethingChanged() { fireContentsChanged(this, 0, ListSequence.fromList(myValues).count()); } } private class MyListAddAction extends ListAddAction { public MyListAddAction(JList list) { super(list); } @Override protected int doAdd(AnActionEvent p0) { List<SNodeReference> nodesList = getCandidates(); NodeChooserDialog chooserDialog = ListPanel.this.createNodeChooserDialog(nodesList); chooserDialog.show(); final SNodeReference resultNode = chooserDialog.getResult(); if (resultNode == null) { return -1; } final Wrappers._T<T> wrapper = new Wrappers._T<T>(); myMpsProject.getModelAccess().runReadAction(new Runnable() { public void run() { wrapper.value = wrap(((SNodePointer) resultNode).resolve(myMpsProject.getRepository())); } }); if (wrapper.value == null) { return -1; } ListSequence.fromList(ListPanel.this.myValues).addElement(wrapper.value); if (ListPanel.this.myListener != null) { ListPanel.this.myListener.actionPerformed(null); } ListPanel.this.myListComponent.updateUI(); ListPanel.this.myListModel.fireSomethingChanged(); return ListSequence.fromList(ListPanel.this.myValues).indexOf(wrapper.value); } @Override public void update(AnActionEvent event) { event.getPresentation().setEnabled(isEditable); super.update(event); } } private class MyListRemoveAction extends ListRemoveAction { public MyListRemoveAction(JList list) { super(list); } @Override protected void doRemove(AnActionEvent p0) { for (Object value : ListPanel.this.myListComponent.getSelectedValuesList()) { for (final T node : ListPanel.this.myValues) { final Wrappers._T<String> fqName = new Wrappers._T<String>(); myMpsProject.getModelAccess().runReadAction(new Runnable() { public void run() { fqName.value = getFqName(node); } }); if (fqName.value.equals(value)) { ListSequence.fromList(ListPanel.this.myValues).removeElement(node); break; } } } if (ListPanel.this.myListener != null) { ListPanel.this.myListener.actionPerformed(null); } ListPanel.this.myListComponent.updateUI(); ListPanel.this.myListModel.fireSomethingChanged(); } @Override public void update(AnActionEvent event) { event.getPresentation().setEnabled(isEditable); super.update(event); } } }