1 package org.jetbrains.plugins.ipnb.editor.panels;
3 import com.intellij.openapi.actionSystem.DefaultActionGroup;
4 import com.intellij.openapi.diagnostic.Logger;
5 import com.intellij.openapi.ui.popup.ListPopup;
6 import com.intellij.openapi.util.text.StringUtil;
7 import com.intellij.ui.JBColor;
8 import com.intellij.ui.awt.RelativePoint;
9 import com.intellij.ui.OnePixelSplitter;
10 import com.intellij.util.ui.JBUI;
11 import com.intellij.util.ui.UIUtil;
12 import org.jetbrains.annotations.NotNull;
13 import org.jetbrains.annotations.Nullable;
14 import org.jetbrains.plugins.ipnb.editor.IpnbEditorUtil;
15 import org.jetbrains.plugins.ipnb.editor.actions.IpnbMergeCellAboveAction;
16 import org.jetbrains.plugins.ipnb.editor.actions.IpnbMergeCellBelowAction;
17 import org.jetbrains.plugins.ipnb.editor.actions.IpnbSplitCellAction;
18 import org.jetbrains.plugins.ipnb.format.cells.IpnbEditableCell;
21 import javax.swing.text.BadLocationException;
22 import javax.swing.text.Document;
24 import java.awt.event.KeyAdapter;
25 import java.awt.event.KeyEvent;
26 import java.awt.event.MouseAdapter;
27 import java.awt.event.MouseEvent;
28 import java.util.Arrays;
30 public abstract class IpnbEditablePanel<T extends JComponent, K extends IpnbEditableCell> extends IpnbPanel<T, K> {
31 private static final Logger LOG = Logger.getInstance(IpnbEditablePanel.class);
32 private boolean myEditing;
33 protected JTextArea myEditablePanel;
34 public final static String EDITABLE_PANEL = "Editable panel";
35 public final static String VIEW_PANEL = "View panel";
36 protected boolean isRunning = false;
37 private OnePixelSplitter mySplitter;
38 private JPanel myViewPrompt;
39 private JPanel myEditablePrompt;
41 public IpnbEditablePanel(@NotNull K cell) {
45 public IpnbEditablePanel(@NotNull K cell, @NotNull final LayoutManager layoutManager) {
46 super(cell, layoutManager);
49 protected void initPanel() {
50 mySplitter = new OnePixelSplitter(true);
53 mySplitter.setFirstComponent(myViewPrompt);
54 mySplitter.setSecondComponent(null);
55 setBackground(IpnbEditorUtil.getBackground());
60 private void addEditablePanel() {
61 myEditablePanel = createEditablePanel();
62 myEditablePrompt = new JPanel(new GridBagLayout());
64 myEditablePrompt.setName(EDITABLE_PANEL);
65 myEditablePrompt.setBackground(IpnbEditorUtil.getBackground());
66 addPromptPanel(myEditablePrompt, null, IpnbEditorUtil.PromptType.None, myEditablePanel);
69 private void addViewPanel() {
70 myViewPanel = createViewPanel();
71 myViewPanel.addMouseListener(new MouseAdapter() {
73 public void mouseClicked(MouseEvent e) {
74 final Container parent = getParent();
75 final MouseEvent parentEvent = SwingUtilities.convertMouseEvent(myViewPanel, e, parent);
76 parent.dispatchEvent(parentEvent);
77 if (e.getClickCount() == 2) {
82 myViewPanel.setName(VIEW_PANEL);
84 myViewPrompt = new JPanel(new GridBagLayout());
85 addPromptPanel(myViewPrompt, null, IpnbEditorUtil.PromptType.None, myViewPanel);
86 myViewPrompt.setBackground(IpnbEditorUtil.getBackground());
89 public void addPromptPanel(@NotNull final JComponent parent, Integer promptNumber,
90 @NotNull final IpnbEditorUtil.PromptType promptType,
91 @NotNull final JComponent component) {
92 final GridBagConstraints c = new GridBagConstraints();
93 c.fill = GridBagConstraints.HORIZONTAL;
99 c.anchor = GridBagConstraints.NORTHWEST;
100 Integer number = promptNumber;
105 final JComponent promptComponent = IpnbEditorUtil.createPromptComponent(number, promptType);
106 c.insets = JBUI.insets(2, 2, 2, 5);
107 parent.add(promptComponent, c);
111 c.insets = JBUI.insets(2);
112 c.anchor = GridBagConstraints.CENTER;
113 parent.add(component, c);
117 public void switchToEditing() {
120 mySplitter.setFirstComponent(myEditablePrompt);
121 UIUtil.requestFocus(myEditablePanel);
122 mySplitter.setSecondComponent(null);
125 public boolean isModified() {
126 final Component[] components = getComponents();
127 for (Component component : components) {
128 final String name = component.getName();
129 if (component.isVisible() && EDITABLE_PANEL.equals(name)) return true;
134 protected String getRawCellText() { return ""; }
136 public void runCell(boolean selectNext) {
137 if (mySplitter != null) {
140 mySplitter.setFirstComponent(myViewPrompt);
141 mySplitter.setSecondComponent(null);
143 final Container parent = getParent();
144 if (parent instanceof IpnbFilePanel) {
145 UIUtil.requestFocus((IpnbFilePanel)parent);
147 ((IpnbFilePanel)parent).selectNext(this, true);
153 private JTextArea createEditablePanel() {
154 final JTextArea textArea = new JTextArea(getRawCellText());
155 textArea.setLineWrap(true);
156 textArea.setEditable(true);
157 textArea.setBorder(BorderFactory.createLineBorder(JBColor.lightGray));
158 textArea.setBackground(IpnbEditorUtil.getEditablePanelBackground());
159 textArea.addMouseListener(new MouseAdapter() {
161 public void mouseClicked(MouseEvent e) {
162 if (e.getClickCount() == 1) {
164 final Container parent = getParent();
166 if (parent instanceof IpnbFilePanel) {
167 ((IpnbFilePanel)parent).setSelectedCellPanel(IpnbEditablePanel.this);
168 textArea.requestFocus();
173 textArea.addKeyListener(new KeyAdapter() {
175 public void keyReleased(KeyEvent e) {
176 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
178 final Container parent = getParent();
179 if (parent instanceof IpnbFilePanel) {
181 UIUtil.requestFocus((IpnbFilePanel)parent);
189 public boolean contains(int y) {
190 return y >= getTop() && y <= getBottom();
193 public int getTop() {
197 public int getBottom() {
198 return getTop() + getHeight();
201 public boolean isEditing() {
205 public void setEditing(boolean editing) {
209 public void updateCellView() {
212 public int getCaretPosition() {
213 return (myEditing && myEditablePanel != null) ? myEditablePanel.getCaretPosition() : -1;
217 protected void addRightClickMenu() {
218 myViewPanel.addMouseListener(new MouseAdapter() {
220 public void mousePressed(MouseEvent e) {
221 if (SwingUtilities.isRightMouseButton(e) && e.getClickCount() == 1) {
222 final DefaultActionGroup group = new DefaultActionGroup(new IpnbMergeCellAboveAction(), new IpnbMergeCellBelowAction());
223 final ListPopup menu = createPopupMenu(group);
224 menu.show(RelativePoint.fromScreen(e.getLocationOnScreen()));
228 myEditablePanel.addMouseListener(new MouseAdapter() {
230 public void mousePressed(MouseEvent e) {
231 if (SwingUtilities.isRightMouseButton(e) && e.getClickCount() == 1) {
232 final DefaultActionGroup group = new DefaultActionGroup(new IpnbSplitCellAction());
233 final ListPopup menu = createPopupMenu(group);
234 menu.show(RelativePoint.fromScreen(e.getLocationOnScreen()));
243 public String getText(int from, int to) {
244 if (myEditing && myEditablePanel != null) {
246 return myEditablePanel.getDocument().getText(from, to - from);
248 catch (BadLocationException e) {
249 LOG.warn(e.getMessage());
255 public String getText(int from) {
256 if (myEditing && myEditablePanel != null) {
257 final Document document = myEditablePanel.getDocument();
258 final int to = document.getLength();
259 return getText(from, to);
264 public void updateCellSource() {
265 final String text = myEditablePanel.getText();
266 myCell.setSource(Arrays.asList(StringUtil.splitByLinesKeepSeparators(text != null ? text : "")));
269 @SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException")
271 protected Object clone() {
273 return super.clone();
275 catch (CloneNotSupportedException e) {
285 public JTextArea getEditablePanel() {
286 return myEditablePanel;