| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.sun.star.script.framework.provider.beanshell; |
| |
| import javax.swing.JTextArea; |
| import javax.swing.JScrollPane; |
| import javax.swing.JComponent; |
| import javax.swing.event.DocumentListener; |
| import javax.swing.event.DocumentEvent; |
| |
| import java.awt.Graphics; |
| import java.awt.Color; |
| import java.awt.Font; |
| import java.awt.FontMetrics; |
| import java.awt.Polygon; |
| import java.awt.Rectangle; |
| import java.awt.Dimension; |
| |
| public class PlainSourceView extends JScrollPane |
| implements ScriptSourceView, DocumentListener { |
| |
| private ScriptSourceModel model; |
| private JTextArea ta; |
| private GlyphGutter gg; |
| private int linecount; |
| private boolean isModified = false; |
| |
| public PlainSourceView(ScriptSourceModel model) { |
| this.model = model; |
| initUI(); |
| model.setView(this); |
| } |
| |
| public void clear() { |
| ta.setText(""); |
| } |
| |
| public void update() { |
| /* Remove ourselves as a DocumentListener while loading the source |
| so we don't get a storm of DocumentEvents during loading */ |
| ta.getDocument().removeDocumentListener(this); |
| |
| if (isModified == false) |
| { |
| int pos = ta.getCaretPosition(); |
| ta.setText(model.getText()); |
| try { |
| ta.setCaretPosition(pos); |
| } |
| catch (IllegalArgumentException iae) { |
| // do nothing and allow JTextArea to set it's own position |
| } |
| } |
| |
| // scroll to currentPosition of the model |
| try { |
| int line = ta.getLineStartOffset(model.getCurrentPosition()); |
| Rectangle rect = ta.modelToView(line); |
| ta.scrollRectToVisible(rect); |
| } |
| catch (Exception e) { |
| // couldn't scroll to line, do nothing |
| } |
| |
| gg.repaint(); |
| |
| // Add back the listener |
| ta.getDocument().addDocumentListener(this); |
| } |
| |
| public boolean isModified() { |
| return isModified; |
| } |
| |
| public void setModified(boolean value) { |
| isModified = value; |
| } |
| |
| private void initUI() { |
| ta = new JTextArea(); |
| ta.setRows(15); |
| ta.setColumns(40); |
| ta.setLineWrap(false); |
| ta.insert(model.getText(), 0); |
| linecount = ta.getLineCount(); |
| |
| gg = new GlyphGutter(this); |
| |
| setViewportView(ta); |
| setRowHeaderView(gg); |
| |
| ta.getDocument().addDocumentListener(this); |
| } |
| |
| /* Implementation of DocumentListener interface */ |
| public void insertUpdate(DocumentEvent e) { |
| doChanged(e); |
| } |
| |
| public void removeUpdate(DocumentEvent e) { |
| doChanged(e); |
| } |
| |
| public void changedUpdate(DocumentEvent e) { |
| doChanged(e); |
| } |
| |
| /* If the number of lines in the JTextArea has changed then update the |
| GlyphGutter */ |
| public void doChanged(DocumentEvent e) { |
| isModified = true; |
| |
| if (linecount != ta.getLineCount()) { |
| gg.update(); |
| linecount = ta.getLineCount(); |
| } |
| } |
| |
| public String getText() { |
| return ta.getText(); |
| } |
| |
| public JTextArea getTextArea() { |
| return ta; |
| } |
| |
| public int getCurrentPosition() { |
| return model.getCurrentPosition(); |
| } |
| } |
| |
| class GlyphGutter extends JComponent { |
| |
| private PlainSourceView view; |
| private final String DUMMY_STRING = "99"; |
| |
| GlyphGutter(PlainSourceView view) { |
| this.view = view; |
| update(); |
| } |
| |
| public void update() { |
| JTextArea textArea = view.getTextArea(); |
| Font font = textArea.getFont(); |
| setFont(font); |
| |
| FontMetrics metrics = getFontMetrics(font); |
| int h = metrics.getHeight(); |
| int lineCount = textArea.getLineCount() + 1; |
| |
| String dummy = Integer.toString(lineCount); |
| if (dummy.length() < 2) { |
| dummy = DUMMY_STRING; |
| } |
| |
| Dimension d = new Dimension(); |
| d.width = metrics.stringWidth(dummy) + 16; |
| d.height = lineCount * h + 100; |
| setPreferredSize(d); |
| setSize(d); |
| } |
| |
| public void paintComponent(Graphics g) { |
| JTextArea textArea = view.getTextArea(); |
| |
| Font font = textArea.getFont(); |
| g.setFont(font); |
| |
| FontMetrics metrics = getFontMetrics(font); |
| Rectangle clip = g.getClipBounds(); |
| |
| g.setColor(getBackground()); |
| g.fillRect(clip.x, clip.y, clip.width, clip.height); |
| |
| int ascent = metrics.getMaxAscent(); |
| int h = metrics.getHeight(); |
| int lineCount = textArea.getLineCount() + 1; |
| |
| int startLine = clip.y / h; |
| int endLine = (clip.y + clip.height) / h + 1; |
| int width = getWidth(); |
| if (endLine > lineCount) { |
| endLine = lineCount; |
| } |
| |
| for (int i = startLine; i < endLine; i++) { |
| String text; |
| text = Integer.toString(i + 1) + " "; |
| int w = metrics.stringWidth(text); |
| int y = i * h; |
| g.setColor(Color.blue); |
| g.drawString(text, 0, y + ascent); |
| int x = width - ascent; |
| |
| // if currentPosition is not -1 then a red arrow will be drawn |
| if (i == view.getCurrentPosition()) { |
| drawArrow(g, ascent, x, y); |
| } |
| } |
| } |
| |
| private void drawArrow(Graphics g, int ascent, int x, int y) { |
| Polygon arrow = new Polygon(); |
| int dx = x; |
| y += ascent - 10; |
| int dy = y; |
| arrow.addPoint(dx, dy + 3); |
| arrow.addPoint(dx + 5, dy + 3); |
| for (x = dx + 5; x <= dx + 10; x++, y++) { |
| arrow.addPoint(x, y); |
| } |
| for (x = dx + 9; x >= dx + 5; x--, y++) { |
| arrow.addPoint(x, y); |
| } |
| arrow.addPoint(dx + 5, dy + 7); |
| arrow.addPoint(dx, dy + 7); |
| |
| g.setColor(Color.red); |
| g.fillPolygon(arrow); |
| g.setColor(Color.black); |
| g.drawPolygon(arrow); |
| } |
| } |