Исходный файл TextEdit.java (все изменения выделены):
import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.Enumeration;
import L2List; import ListException;
/** * Simple text editor. */ public class TextEdit extends Frame { // //----------------------------------------------------------- boolean pasteExecuted = false; L2List buffer; //----------------------------------------------------------- // Text text; // Text storage EditField editField; // Client area of frame window
int cursorX = 0; // Cursor position int cursorY = 0;
int windowX = 0; // Window position in text int windowY = 0;
int windowWidth = 80; // Window size in characters (dx, dy) int windowHeight = 24;
int lastCommand = 0; // The last key pressed
Font textFont = new Font("Courier", Font.PLAIN, 14); // Text font
// Font metric (we use a fixed width font!) int dx = 0; // Maximal character advance (width) int ascent = 0; // Character ascent int descent = 0; // Character descent int leading = 0; // Interline skip int dy = 0; // Font height = ascent + descent + leading int margin = 4; // Top and left margin
Color fgColor = Color.black; // Foreground color Color bgColor = Color.lightGray; // Background color
String fileName = "noname.txt"; boolean fileNameSet = false;
boolean textChanged = false;
String endOfText = "[* End of text *]"; // "End of text" line
boolean inputDisabled = false;
boolean saveText = false;
public static void main(String[] args) { TextEdit editor = new TextEdit(); if (args.length >= 1) { editor.fileName = args[0]; editor.fileNameSet = true; editor.text.load(editor.fileName); editor.setTitle(editor.fileName); } editor.setVisible(true); editor.editField.requestFocus(); }
public TextEdit() { text = new Text(); // //------------------------------------------------------------------ buffer = new L2List(); //------------------------------------------------------------------ //
editField = new EditField(); editField.setFont(textFont); setBackground(bgColor); setForeground(fgColor); add("Center", editField);
WindowAdapter wa = new WindowAdapter() { public void windowClosing(WindowEvent e) { onQuit(); } public void windowActivated(WindowEvent e) { editField.requestFocus(); } }; addWindowListener(wa);
// Add menu bar final MenuBar mb = new MenuBar(); setMenuBar(mb); final Menu fileMenu = new Menu("File"); // //------------------------------------------------------------------- final Menu editMenu = new Menu("Edit"); //------------------------------------------------------------------- // final MenuItem saveItem = new MenuItem("Save"); final MenuItem saveAsItem = new MenuItem("Save as..."); final MenuItem quitItem = new MenuItem("Quit"); // //------------------------------------------------------------------- final MenuItem copyItem = new MenuItem("Copy"); final MenuItem pasteItem = new MenuItem("Paste"); //------------------------------------------------------------------- // fileMenu.add(saveItem); fileMenu.add(saveAsItem); fileMenu.add(quitItem); // //------------------------------------------------------------------- editMenu.add(copyItem); editMenu.add(pasteItem); //------------------------------------------------------------------- // mb.add(fileMenu); // //------------------------------------------------------------------- mb.add(editMenu); //------------------------------------------------------------------- //
ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); if (command.equals("Save")) { onSave(); } else if (command.equals("Save as...")) { onSaveAs(); } else if (command.equals("Quit")) { onQuit(); // //------------------------------------------------------------------- } else if (command.equals("Copy")) { onCopy(); } else if (command.equals("Paste")) { onPaste(); //------------------------------------------------------------------- // } editField.requestFocus(); } }; fileMenu.addActionListener(al); // //------------------------------------------------------------------- editMenu.addActionListener(al); //------------------------------------------------------------------- //
//... pack(); setSize( 600, 400 );
setTitle(fileName); setBackground(bgColor); setForeground(fgColor);
KeyAdapter ka = new KeyAdapter() { public void keyPressed(KeyEvent e) { onKeyPressed(e); } };
addKeyListener(ka); editField.addKeyListener(ka);
// Processing of resize events ComponentAdapter ca = new ComponentAdapter() { public void componentResized(ComponentEvent e) { onResize(); editField.requestFocus(); }
public void componentShown(ComponentEvent e) { editField.requestFocus(); } };
editField.addComponentListener(ca); }
void onKeyPressed(KeyEvent e) { if (inputDisabled) return; //... System.out.println("KeyPressed: " + e);
int keyCode = e.getKeyCode(); char keyChar = e.getKeyChar();
// Remove old cursor. drawCursor(cursorX, cursorY, false);
if (e.isActionKey()) { // Action key //... System.out.println("Action key: " + e.getKeyText(e.getKeyCode()));
if (keyCode == KeyEvent.VK_DOWN) { onDown(); } else if (keyCode == KeyEvent.VK_UP) { onUp(); } else if (keyCode == KeyEvent.VK_LEFT) { onLeft(); } else if (keyCode == KeyEvent.VK_RIGHT) { onRight(); } else if (keyCode == KeyEvent.VK_HOME) { onHome(); } else if (keyCode == KeyEvent.VK_END) { onEnd(); } } else if ((e.getModifiers() & InputEvent.CTRL_MASK) != 0) { // Ctrl-key //... System.out.println("Ctrl+" + e.getKeyText(e.getKeyCode()));
if (keyCode == KeyEvent.VK_K) { // Ctrl+K onDeleteLine(); } else if (keyCode == KeyEvent.VK_L) { // Ctrl+K onInsertLine(); } else if (keyCode == KeyEvent.VK_S) { // Ctrl+S onSave(); } else if (keyCode == KeyEvent.VK_Q) { // Ctrl+Q onQuit(); } } else if (keyCode == KeyEvent.VK_ENTER) { //... System.out.println(e.getKeyText(e.getKeyCode())); onEnter(); } else if (keyCode == KeyEvent.VK_BACK_SPACE) { //... System.out.println(e.getKeyText(e.getKeyCode())); onBackSpace(); } else if (keyChar != KeyEvent.CHAR_UNDEFINED) { onCharTyped(keyChar); }
if (cursorX < 0) cursorX = 0; if (cursorY < 0) cursorY = 0;
// Scroll a window, if necessary if ( cursorX < windowX || cursorX > windowX + windowWidth - 1 || cursorY < windowY || cursorY > windowY + windowHeight - 1 ) { // Cursor is removed at the moment! // scrollToCursor() will draw it again. scrollToCursor(); }
drawCursor(cursorX, cursorY, true); editField.requestFocus(); }
void scrollToCursor() { // Remove cursor for a moment drawCursor(cursorX, cursorY, false);
if (cursorX < windowX) { scrollLeft(windowX - cursorX); } else if (cursorX > windowX + windowWidth - 1) { scrollRight(cursorX - (windowX + windowWidth - 1)); }
if (cursorY < windowY) { scrollUp(windowY - cursorY); } else if (cursorY > windowY + windowHeight - 1) { scrollDown(cursorY - (windowY + windowHeight - 1)); }
// Restore cursor drawCursor(cursorX, cursorY, true); }
void scrollLeft(int n) { inputDisabled = true; if (n > windowX) n = windowX; windowX -= n; if (n > windowWidth / 2) editField.repaint(); else { Graphics g = editField.getGraphics(); Rectangle r = editField.getBounds(); if (g != null) { int shift = dx * n; g.copyArea( margin, margin, windowWidth * dx - shift, (windowHeight + 1) * dy, shift, 0 ); inputDisabled = true; editField.repaint( 0, margin, shift + margin, (windowHeight + 1) * dy ); } else { editField.repaint(); } } }
void scrollRight(int n) { if (n == 0) return; inputDisabled = true; windowX += n; if (n > windowWidth / 2) editField.repaint(); else { Graphics g = editField.getGraphics(); if (g != null) { int shift = dx * n; g.copyArea( margin + shift, margin, windowWidth * dx - shift, windowHeight * dy, -shift, 0 ); inputDisabled = true; editField.repaint( margin + windowWidth * dx - shift, 0, shift, windowHeight * dy ); } else { editField.repaint(); } } }
void scrollUp(int n) { if (n == 0) return; inputDisabled = true; if (n > windowY) n = windowY; windowY -= n; if (n > windowHeight / 2) editField.repaint(); else { Graphics g = editField.getGraphics(); Rectangle r = editField.getBounds(); if (g != null) { int shift = dy * n; g.copyArea( margin, margin, windowWidth * dx, windowHeight * dy - shift, 0, shift ); inputDisabled = true; editField.repaint( margin, margin, margin + windowWidth * dx, shift ); } else { editField.repaint(); } } }
void scrollDown(int n) { inputDisabled = true; windowY += n; if (n > windowHeight / 2) editField.repaint(); else { Graphics g = editField.getGraphics(); if (g != null) { int shift = dy * n; g.copyArea( margin, margin + shift, windowWidth * dx, windowHeight * dy - shift, 0, -shift ); inputDisabled = true; editField.repaint( margin, margin + windowHeight * dy - shift, windowWidth * dx, shift ); } else { editField.repaint(); } } }
void drawCursor(Graphics g, int cx, int cy, boolean on) { if (cx >= windowX + windowWidth || cy >= windowY + windowHeight) return; if (g != null) { if (on) g.setColor(fgColor); else g.setColor(bgColor);
int x = margin + (cx - windowX) * dx; int y = margin + (cy - windowY) * dy;
g.fillRect( x, y, dx, ascent + descent );
if (on) g.setColor(bgColor); else g.setColor(fgColor);
if (cy <= text.size()) { String line; if (cy == text.size()) { line = endOfText; } else { text.setPointer(cy); line = (String) text.elementAfter(); }
if (cx < line.length()) { g.drawString( line.substring(cx, cx + 1), x, y + ascent ); } }
g.setColor(fgColor); } }
void drawCursor(int cx, int cy, boolean on) { drawCursor(editField.getGraphics(), cx, cy, on); }
void onDown(){ if (cursorY < text.size()) cursorY++; }
void onUp(){ if (cursorY > 0) cursorY--; }
void onLeft(){ if (cursorX > 0) cursorX--; }
void onRight(){ cursorX++; }
void onHome(){ cursorX = 0; }
void onEnd(){ if (cursorY < text.size()) { String line = text.getLine(cursorY); cursorX = line.length(); } else { cursorX = 0; } }
void onDeleteLine(){ if (cursorY < text.size()) { text.setPointer(cursorY); text.removeAfter(); redraw(0, cursorY, Integer.MAX_VALUE, Integer.MAX_VALUE); textChanged = true; } }
void onInsertLine(){ text.setPointer(cursorY); text.addAfter(""); redraw(0, cursorY, Integer.MAX_VALUE, Integer.MAX_VALUE); textChanged = true; }
void onEnter(){ text.setPointer(cursorY); if (cursorY >= text.size()) { text.addAfter(""); } else { String line = (String) text.elementAfter(); if (cursorX >= line.length()) { text.moveForward(); text.addAfter(""); } else { // Cut line into 2 pieces text.setElementAfter(line.substring(0, cursorX)); text.moveForward(); text.addAfter(line.substring(cursorX)); } } cursorX = 0; cursorY++; scrollToCursor(); redraw(0, cursorY - 1, Integer.MAX_VALUE, Integer.MAX_VALUE); textChanged = true; }
void onBackSpace(){ if (cursorX <= 0 || cursorY >= text.size()) return; text.setPointer(cursorY); String line = (String) text.elementAfter(); if (cursorX <= line.length()) { String l = line.substring(0, cursorX - 1) + line.substring(cursorX); text.setElementAfter(l); } cursorX--; redraw(cursorX, cursorY, Integer.MAX_VALUE, 1); textChanged = true; }
void onDelete(){ if (cursorX < 0 || cursorY >= text.size()) return; text.setPointer(cursorY); String line = (String) text.elementAfter(); if (cursorX < line.length()) { String l = line.substring(0, cursorX) + line.substring(cursorX + 1); text.setElementAfter(l); } redraw(cursorX, cursorY, Integer.MAX_VALUE, 1); textChanged = true; }
void onCharTyped(char c) { //... System.out.println("Char typed: " + c + " code: " + (int)c); if ((int)c == 0x7f) { onDelete(); return; } if (cursorY == text.size()) onInsertLine(); text.setPointer(cursorY); String line = (String) text.elementAfter(); String l; if (cursorX < line.length()) { l = line.substring(0, cursorX); l += c; l += line.substring(cursorX); } else if (cursorX == line.length()) { l = line; l += c; } else { int n = cursorX - line.length(); l = line; while (n > 0) { l += ' '; n--; } l += c; } text.setElementAfter(l); cursorX++; scrollToCursor(); redraw(cursorX - 1, cursorY, Integer.MAX_VALUE, 1); textChanged = true; }
// //----------------------------------------------------------------- void onCopy() { if (pasteExecuted) buffer.removeAll(); if (cursorY < text.size()) buffer.addAfter(text.getLine(cursorY)); pasteExecuted = false; }
void onPaste() { int i = 0; if (buffer.size() == 0) return; buffer.moveToBeg(); for (i = 0; i < buffer.size(); i++) { text.addAfter(buffer.elementAfter()); buffer.moveForward(); } textChanged = true; pasteExecuted = true; redraw(0, cursorY, Integer.MAX_VALUE, Integer.MAX_VALUE); } //----------------------------------------------------------------- //
// Redraw a rectangle in a text void redraw(int x, int y, int w, int h) { int x1 = x + w; if (w == Integer.MAX_VALUE) x1 = Integer.MAX_VALUE; int y1 = y + h; if (h == Integer.MAX_VALUE) y1 = Integer.MAX_VALUE;
int x0 = x; if (x0 < windowX) x0 = windowX; int y0 = y; if (y0 < windowY) y0 = windowY;
if (x1 > windowX + windowWidth) x1 = windowX + windowWidth; if (y1 > windowY + windowHeight) y1 = windowY + windowHeight; if (x1 <= x || y1 <= y) return;
int left = margin + (x0 - windowX) * dx; int top = margin + (y0 - windowY) * dy; int width = (x1 - x0) * dx; int height = (y1 - y0) * dy;
Rectangle r = editField.getBounds(); if (left + width > r.width) width -= (left + width - r.width); if (top + height > r.height) height -= (top + height - r.height);
editField.repaint(left, top, width, height); }
void onSave() { if (fileNameSet) { if (text.save(fileName)) textChanged = false; } else { onSaveAs(); } }
void onSaveAs() { FileDialog fd = new FileDialog( (Frame) this, "Save File", FileDialog.SAVE ); if (fileNameSet) fd.setFile(fileName); fd.setVisible(true); String file = fd.getFile(); String directory = fd.getDirectory(); if (file == null || directory == null) return;
//... System.out.println("Selected file = " + file + ", directory = " + directory);
String oldFileName = fileName; if (directory.length() > 0) { char lastChar = directory.charAt(directory.length() - 1); if (lastChar != '/' && lastChar != '\\') directory += '/'; } fileName = directory + file;
if (text.save(fileName) && (!fileNameSet || oldFileName.equals(fileName))) { textChanged = false; }
if (!fileNameSet) { fileNameSet = true; setTitle(fileName); } else fileName = oldFileName; }
void onQuit() { if (textChanged) { SaveDialog sd = new SaveDialog(this); sd.setVisible(true); // Modal dialog if (saveText) { onSave(); } saveText = false; } setVisible(false); dispose(); System.exit(0); }
void initFontMetric(Graphics g) { FontMetrics fm = g.getFontMetrics(); //... dx = fm.getMaxAdvance(); // Maximal character advance (width) dx = fm.charWidth('W'); // Maximal character advance (width) dy = fm.getHeight(); ascent = fm.getAscent(); descent = fm.getDescent(); leading = fm.getLeading(); }
class EditField extends Canvas { public void paint(Graphics g) { if (dx == 0) { initFontMetric(g); }
Rectangle r = getBounds();
g.setPaintMode();
// Clear window g.setColor(bgColor); g.fillRect(0, 0, r.width, r.height);
// Define window size windowWidth = (r.width - 2 * margin) / dx; windowHeight = (r.height - 2 * margin) / dy;
g.setColor(fgColor); int numLines = (r.height - 2 * margin) / dy;
for (int screenY = 0; screenY < numLines; screenY++) { // Draw a line int textY = windowY + screenY; String line = null;
if (textY <= text.size()) { String str; if (textY == text.size()) { str = endOfText; } else { str = text.getLine(textY); } if (windowX < str.length()) { int endIndex = str.length(); if (endIndex > windowX + windowWidth) endIndex = windowX + windowWidth; line = str.substring(windowX, endIndex); } }
if (line != null) { g.drawString( line, margin, margin + ascent + dy * screenY ); } }
drawCursor(g, cursorX, cursorY, true); inputDisabled = false; }
public void update(Graphics g) { paint(g); }
} // End of class EditField
void onResize() { Rectangle r = editField.getBounds();
if (dx != 0 && dy != 0) { // Define window size windowWidth = (r.width - margin) / dx; windowHeight = (r.height - margin) / dy;
scrollToCursor(); } editField.requestFocus(); } }
class Text extends L2List { static final int tabWidth = 8;
public Text() { super(); }
public boolean load(String fileName) { removeAll(); try { BufferedReader input = new BufferedReader( new FileReader(fileName) ); String line; while ((line = input.readLine()) != null) { String str = convertTabs(line); // Replace tabulations by spaces addBefore(str); } } catch (FileNotFoundException e) { //... System.out.println("Cannot open a file: " + e); return false; } catch (IOException e) { System.out.println("Read error: " + e); return false; }
return true; }
public boolean save(String fileName) { try { BufferedWriter output = new BufferedWriter( new FileWriter(fileName) ); Enumeration lines = elements(); while (lines.hasMoreElements()) { String str = (String) lines.nextElement(); //... System.out.println(str); output.write(str); output.newLine(); } output.flush(); } catch (Exception e) { System.out.println("Cannot write to file " + fileName + " " + e); return false; }
return true; }
public String getLine(int i) { String line = null; if (i < size()) { setPointer(i); line = (String) elementAfter(); } return line; }
private String convertTabs(String line) { StringBuffer str = new StringBuffer(256); int x = 0; int len = line.length(); int i = 0; while (i < len) { char c = line.charAt(i); if (c == '\t') { // Tabulation int spacesToAdd = tabWidth - (x % tabWidth); while (spacesToAdd > 0) { str.append(' '); x++; spacesToAdd--; } } else { // Other character str.append(c); x++; } i++; } return str.toString(); } }
class SaveDialog extends Dialog implements ActionListener { Button yes; Button no; TextEdit editor;
public SaveDialog(Frame f) { super(f, true);
editor = (TextEdit) f;
setLayout(null); setFont(new Font("Helvetica", Font.BOLD, 14)); setTitle("Save text?");
Label l = new Label("Text was changed, save it?"); int y = 30; l.setBounds(10, y, 240, 30); y += 40; add(l);
yes = new Button("Yes"); no = new Button("No"); yes.setBounds(10, y, 80, 30); no.setBounds(100, y, 80, 30); add(yes); add(no);
yes.addActionListener(this); no.addActionListener(this);
yes.requestFocus();
setSize(250, 130); }
public void actionPerformed(ActionEvent e) { Object source = e.getSource();
if (source == yes) editor.saveText = true; else if (source == no) editor.saveText = false; setVisible(false); } }