2 * Copyright 2000-2014 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.jetbrains.plugins.ipnb.editor.panels.code;
18 import com.intellij.openapi.Disposable;
19 import com.intellij.openapi.actionSystem.CustomShortcutSet;
20 import com.intellij.openapi.editor.Editor;
21 import com.intellij.openapi.editor.EditorFactory;
22 import com.intellij.openapi.editor.event.EditorMouseListener;
23 import com.intellij.openapi.project.Project;
24 import com.intellij.openapi.util.Disposer;
25 import com.intellij.ui.Gray;
26 import com.intellij.ui.components.panels.HorizontalLayout;
27 import com.intellij.util.ui.UIUtil;
28 import org.jetbrains.annotations.NotNull;
29 import org.jetbrains.plugins.ipnb.editor.IpnbEditorUtil;
30 import org.jetbrains.plugins.ipnb.editor.IpnbFileEditor;
31 import org.jetbrains.plugins.ipnb.editor.actions.IpnbRunCellAction;
32 import org.jetbrains.plugins.ipnb.editor.actions.IpnbRunCellBaseAction;
33 import org.jetbrains.plugins.ipnb.editor.actions.IpnbRunCellInplaceAction;
34 import org.jetbrains.plugins.ipnb.editor.panels.IpnbEditorPanel;
35 import org.jetbrains.plugins.ipnb.editor.panels.IpnbFilePanel;
36 import org.jetbrains.plugins.ipnb.editor.panels.IpnbPanel;
37 import org.jetbrains.plugins.ipnb.format.cells.IpnbCodeCell;
41 import java.awt.event.*;
46 public class IpnbCodeSourcePanel extends IpnbPanel<JComponent, IpnbCodeCell> implements IpnbEditorPanel {
47 private Editor myEditor;
48 @NotNull private final Project myProject;
49 @NotNull private final IpnbCodePanel myParent;
50 @NotNull private final String mySource;
52 public IpnbCodeSourcePanel(@NotNull final Project project, @NotNull final IpnbCodePanel parent, @NotNull final IpnbCodeCell cell) {
53 super(cell, new HorizontalLayout(5));
56 mySource = cell.getSourceAsString();
57 final JComponent panel = createViewPanel();
61 public void addMouseListener(@NotNull final EditorMouseListener listener) {
62 myEditor.addEditorMouseListener(listener);
66 public IpnbCodePanel getIpnbCodePanel() {
72 public Editor getEditor() {
77 protected JComponent createViewPanel() {
78 final JPanel panel = new JPanel(new BorderLayout());
79 panel.setBackground(UIUtil.isUnderDarcula() ? IpnbEditorUtil.getBackground() : Gray._247);
81 myEditor = IpnbEditorUtil.createPythonCodeEditor(myProject, this);
82 Disposer.register(myParent.getFileEditor(), new Disposable() {
84 public void dispose() {
85 EditorFactory.getInstance().releaseEditor(myEditor);
88 final JComponent component = myEditor.getComponent();
89 final JComponent contentComponent = myEditor.getContentComponent();
91 new IpnbRunCellAction().registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke("shift ENTER")), contentComponent);
92 new IpnbRunCellInplaceAction().registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke("ctrl ENTER")), contentComponent);
94 contentComponent.addKeyListener(new KeyAdapter() {
96 public void keyPressed(KeyEvent e) {
97 final int keyCode = e.getKeyCode();
98 final Container parent = myParent.getParent();
99 if (keyCode == KeyEvent.VK_ESCAPE && parent instanceof IpnbFilePanel) {
100 getIpnbCodePanel().setEditing(false);
102 UIUtil.requestFocus(getIpnbCodePanel().getFileEditor().getIpnbFilePanel());
106 private void updateVisibleArea(boolean up) {
107 final IpnbFileEditor fileEditor = myParent.getFileEditor();
108 final IpnbFilePanel ipnbPanel = fileEditor.getIpnbFilePanel();
109 final Rectangle rect = ipnbPanel.getVisibleRect();
111 final Rectangle cellBounds = IpnbCodeSourcePanel.this.getIpnbCodePanel().getBounds();
112 final JScrollPane scrollPane = fileEditor.getScrollPane();
114 final int y = cellBounds.y + myEditor.visualPositionToXY(myEditor.getCaretModel().getVisualPosition()).y;
115 int delta = myEditor.getLineHeight() * 2;
116 if (y <= rect.getY() && up) {
117 scrollPane.getVerticalScrollBar().setValue(y);
119 if (y + delta > rect.getY() + rect.getHeight() && !up) {
120 scrollPane.getVerticalScrollBar().setValue(y - rect.height + delta);
125 public void keyReleased(KeyEvent e) {
126 final int keyCode = e.getKeyCode();
127 final Container parent = myParent.getParent();
129 final int height = myEditor.getLineHeight() * Math.max(myEditor.getDocument().getLineCount(), 1) + 10;
130 contentComponent.setPreferredSize(new Dimension(parent.getWidth() - 300, height));
131 panel.setPreferredSize(new Dimension(parent.getWidth() - 300, height));
132 myParent.revalidate();
137 if (parent instanceof IpnbFilePanel) {
138 IpnbFilePanel ipnbFilePanel = (IpnbFilePanel)parent;
139 ipnbFilePanel.revalidate();
140 ipnbFilePanel.repaint();
141 if (keyCode == KeyEvent.VK_ENTER && InputEvent.CTRL_MASK == e.getModifiers()) {
142 IpnbRunCellBaseAction.runCell(ipnbFilePanel, false);
144 else if (keyCode == KeyEvent.VK_ENTER && InputEvent.SHIFT_DOWN_MASK == e.getModifiersEx()) {
145 IpnbRunCellBaseAction.runCell(ipnbFilePanel, true);
147 else if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN || keyCode == KeyEvent.VK_PAGE_DOWN ||
148 keyCode == KeyEvent.VK_PAGE_UP) {
149 updateVisibleArea(keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_PAGE_UP);
155 contentComponent.addMouseListener(new MouseAdapter() {
157 public void mousePressed(MouseEvent e) {
158 if (InputEvent.CTRL_DOWN_MASK == e.getModifiersEx()) return;
159 final Container ipnbFilePanel = myParent.getParent();
160 if (ipnbFilePanel instanceof IpnbFilePanel) {
161 ((IpnbFilePanel)ipnbFilePanel).setSelectedCell(myParent, true);
162 myParent.switchToEditing();
164 UIUtil.requestFocus(contentComponent);
168 panel.add(component);
169 contentComponent.addHierarchyListener(new HierarchyListener() {
171 public void hierarchyChanged(HierarchyEvent e) {
172 final Container parent = myParent.getParent();
173 if (parent != null) {
174 final int height = myEditor.getLineHeight() * Math.max(myEditor.getDocument().getLineCount(), 1) + 10;
175 contentComponent.setPreferredSize(new Dimension(parent.getWidth() - 300, height));
176 panel.setPreferredSize(new Dimension(parent.getWidth() - 300, height));
180 contentComponent.addHierarchyBoundsListener(new HierarchyBoundsAdapter() {
182 public void ancestorResized(HierarchyEvent e) {
183 final Container parent = myParent.getParent();
184 final Component component = e.getChanged();
185 if (parent != null && component instanceof IpnbFilePanel) {
186 final int height = myEditor.getLineHeight() * Math.max(myEditor.getDocument().getLineCount(), 1) + 10;
187 contentComponent.setPreferredSize(new Dimension(parent.getWidth() - 300, height));
188 panel.setPreferredSize(new Dimension(parent.getWidth() - 300, height));