PageRenderTime 59ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/sshterm/emulation/TerminalPanel.java

https://github.com/rpernavas/sshtools
Java | 1277 lines | 855 code | 246 blank | 176 comment | 192 complexity | 61a61e323488680eb28b43d1cd029775 MD5 | raw file
  1. /*
  2. * Sshtools - SSHTerm
  3. *
  4. * The contents of this package have been derived from the Java
  5. * Telnet/SSH Applet from http://javassh.org. The files have been
  6. * modified and are supplied under the terms of the original license.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Library General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public
  18. * License along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. package com.sshtools.sshterm.emulation;
  22. import java.awt.*;
  23. import java.awt.event.AdjustmentEvent;
  24. import java.awt.event.AdjustmentListener;
  25. import java.awt.event.FocusEvent;
  26. import java.awt.event.FocusListener;
  27. import java.awt.event.KeyEvent;
  28. import java.awt.event.KeyListener;
  29. import java.awt.event.MouseEvent;
  30. import java.awt.event.MouseListener;
  31. import java.awt.event.MouseMotionListener;
  32. import java.awt.print.PageFormat;
  33. import java.awt.print.Printable;
  34. import java.awt.print.PrinterException;
  35. import javax.swing.JComponent;
  36. import javax.swing.JScrollBar;
  37. public class TerminalPanel
  38. extends JComponent
  39. implements VDUDisplay,
  40. KeyListener, MouseListener, MouseMotionListener, Printable {
  41. private final static int debug = 0;
  42. private final static long VDU_EVENTS = AWTEvent.KEY_EVENT_MASK
  43. | AWTEvent.FOCUS_EVENT_MASK | AWTEvent.ACTION_EVENT_MASK
  44. | AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK
  45. | 0x20000 /* We want mouse wheel support and 1.3 runtime and compile compatibility - so this mask unfortunately needs to be hard code*/
  46. ;
  47. public final static int RESIZE_NONE = 0;
  48. public final static int RESIZE_FONT = 1;
  49. public final static int RESIZE_SCREEN = 2;
  50. public final static int COLOR_BOLD = 8;
  51. public final static int COLOR_INVERT = 9;
  52. /*
  53. * definitions of standards for the display unit
  54. */
  55. private final static int COLOR_FG_STD = 7;
  56. private final static int COLOR_BG_STD = 0;
  57. private VDUBuffer buffer;
  58. private Insets insets;
  59. /*
  60. * size of the border
  61. */
  62. private boolean raised;
  63. /*
  64. * indicator if the border is raised
  65. */
  66. private Font normalFont;
  67. /*
  68. * normal font
  69. */
  70. private FontMetrics fm;
  71. /*
  72. * current font metrics
  73. */
  74. private int charWidth;
  75. /*
  76. * current width of a char
  77. */
  78. private int charHeight;
  79. /*
  80. * current height of a char
  81. */
  82. private int charDescent;
  83. /*
  84. * base line descent
  85. */
  86. private int resizeStrategy;
  87. /*
  88. * current resizing strategy
  89. */
  90. private Point selectBegin;
  91. /*
  92. * current resizing strategy
  93. */
  94. private Point selectEnd;
  95. /*
  96. * selection coordinates
  97. */
  98. private String selection;
  99. /*
  100. * contains the selected text
  101. */
  102. protected JScrollBar scrollBar;
  103. private SoftFont sf = new SoftFont();
  104. private boolean colorPrinting = false;
  105. /*
  106. * print display in color
  107. */
  108. private Image backingStore = null;
  109. private boolean antialias;
  110. private Color[] color = {
  111. Color.black,
  112. // Background
  113. Color.red, Color.green, Color.yellow, Color.blue, Color.magenta,
  114. Color.cyan, Color.white,
  115. // Foreground
  116. null,
  117. // bold color
  118. null,
  119. };
  120. private Color cursorColorFG = null;
  121. private Color cursorColorBG = null;
  122. // lightweight component event handling
  123. private MouseListener mouseListener;
  124. private MouseMotionListener mouseMotionListener;
  125. //private MouseWheelListener mouseWheelListener;
  126. private KeyListener keyListener;
  127. FocusListener focusListener;
  128. public TerminalPanel(VDUBuffer buffer, Font font) {
  129. setVDUBuffer(buffer);
  130. addKeyListener(this);
  131. // Escape events seem to get missed, there is probably a better way
  132. // of doing this
  133. /*
  134. final KeyStroke ks = KeyStroke.getKeyStroke (KeyEvent.VK_ESCAPE, 0);
  135. ActionListener escLis = new ActionListener() {
  136. public void actionPerformed(ActionEvent actionEvent) {
  137. KeyEvent evt = new KeyEvent(
  138. TerminalPanel.this, KeyEvent.KEY_PRESSED,
  139. System.currentTimeMillis(), ks.getModifiers(),
  140. ks.getKeyCode(), ks.getKeyChar());
  141. keyPressed(evt);
  142. }
  143. };
  144. registerKeyboardAction(escLis, ks, WHEN_IN_FOCUSED_WINDOW);
  145. */
  146. /*
  147. * we have to make sure the tab key stays within the component
  148. */
  149. String version = System.getProperty("java.version");
  150. if (version.startsWith("1.4")) {
  151. try {
  152. Class[] params = new Class[] {
  153. boolean.class};
  154. TerminalPanel.class.getMethod("setFocusable", params).invoke(this,
  155. new Object[] {new Boolean(true)});
  156. TerminalPanel.class.getMethod("setFocusTraversalKeysEnabled",
  157. params).invoke(this,
  158. new Object[] {new Boolean(false)});
  159. }
  160. catch (Exception e) {
  161. System.err.println(
  162. "vt320: unable to reset focus handling for java version "
  163. + version);
  164. e.printStackTrace();
  165. }
  166. }
  167. // lightweight component handling
  168. enableEvents(VDU_EVENTS);
  169. // set the standard resize strategy
  170. setResizeStrategy(RESIZE_FONT);
  171. // set the normal font to use
  172. setFont(font);
  173. setForeground(Color.white);
  174. setBackground(Color.black);
  175. cursorColorFG = color[COLOR_FG_STD];
  176. cursorColorBG = color[COLOR_BG_STD];
  177. clearSelection();
  178. addMouseListener(this);
  179. addMouseMotionListener(this);
  180. selection = null;
  181. }
  182. public TerminalPanel(VDUBuffer buffer) {
  183. this(buffer, new Font("Monospaced", Font.PLAIN, 11));
  184. }
  185. private Color brighten(Color clr) {
  186. int r;
  187. int g;
  188. int b;
  189. r = (int) min(clr.getRed() * 1.2, 255.0);
  190. g = (int) min(clr.getGreen() * 1.2, 255.0);
  191. b = (int) min(clr.getBlue() * 1.2, 255.0);
  192. return new Color(r, g, b);
  193. }
  194. private Color darken(Color clr) {
  195. int r;
  196. int g;
  197. int b;
  198. r = (int) max(clr.getRed() * 0.8, 0.0);
  199. g = (int) max(clr.getGreen() * 0.8, 0.0);
  200. b = (int) max(clr.getBlue() * 0.8, 0.0);
  201. return new Color(r, g, b);
  202. }
  203. protected double max(double f1, double f2) {
  204. return (f1 < f2) ? f2 : f1;
  205. }
  206. protected double min(double f1, double f2) {
  207. return (f1 < f2) ? f1 : f2;
  208. }
  209. public void setAntialias(boolean antialias) {
  210. this.antialias = antialias;
  211. repaint();
  212. }
  213. public boolean isAntialias() {
  214. return antialias;
  215. }
  216. public void setVDUBuffer(VDUBuffer buffer) {
  217. this.buffer = buffer;
  218. buffer.setDisplay(this);
  219. }
  220. public VDUBuffer getVDUBuffer() {
  221. return buffer;
  222. }
  223. public void setColorSet(Color[] colorset) {
  224. System.arraycopy(colorset, 0, color, 0, 10);
  225. buffer.update[0] = true;
  226. redraw();
  227. }
  228. public Color[] getColorSet() {
  229. return color;
  230. }
  231. public void setFont(Font font) {
  232. super.setFont(normalFont = font);
  233. fm = getFontMetrics(font);
  234. if (fm != null) {
  235. charWidth = fm.charWidth('@');
  236. charHeight = fm.getHeight();
  237. charDescent = fm.getDescent();
  238. }
  239. if (buffer.update != null) {
  240. buffer.update[0] = true;
  241. }
  242. redraw();
  243. }
  244. public void setResizeStrategy(int strategy) {
  245. resizeStrategy = strategy;
  246. if (debug > 0) {
  247. System.out.println("VDU: Setting resize strategy to " + strategy);
  248. }
  249. setBounds(getBounds());
  250. }
  251. public void setBorder(int thickness, boolean raised) {
  252. if (thickness == 0) {
  253. insets = null;
  254. }
  255. else {
  256. insets = new Insets(thickness + 1, thickness + 1, thickness + 1,
  257. thickness + 1);
  258. }
  259. this.raised = raised;
  260. }
  261. public void setScrollbar(JScrollBar scrollBar) {
  262. if (scrollBar == null) {
  263. return;
  264. }
  265. this.scrollBar = scrollBar;
  266. this.scrollBar.setValues(buffer.windowBase, buffer.height, 0,
  267. buffer.bufSize - buffer.height - 1);
  268. this.scrollBar.addAdjustmentListener(new AdjustmentListener() {
  269. public void adjustmentValueChanged(AdjustmentEvent evt) {
  270. buffer.setWindowBase(evt.getValue());
  271. }
  272. });
  273. }
  274. public void redraw() {
  275. if (backingStore != null) {
  276. redraw(backingStore.getGraphics());
  277. repaint();
  278. }
  279. }
  280. protected void redraw(Graphics g1) {
  281. if (debug > 0) {
  282. System.err.println("redraw()");
  283. }
  284. Graphics2D g = (Graphics2D) g1;
  285. // Antialiasing
  286. if (isAntialias()) {
  287. g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
  288. RenderingHints.VALUE_ANTIALIAS_ON);
  289. }
  290. int xoffset = (super.getSize().width - (buffer.width * charWidth)) / 2;
  291. int yoffset = (super.getSize().height - (buffer.height * charHeight)) / 2;
  292. int selectStartLine = selectBegin.y - buffer.windowBase;
  293. int selectEndLine = selectEnd.y - buffer.windowBase;
  294. // Color fg = darken(color[COLOR_FG_STD]);
  295. // Color bg = darken(color[COLOR_BG_STD]);
  296. Color fg = color[COLOR_FG_STD];
  297. Color bg = color[COLOR_BG_STD];
  298. g.setFont(normalFont);
  299. /*
  300. * for debug only
  301. * if (update[0]) {
  302. * System.err.println("Redrawing all");
  303. * } else {
  304. * for (int l = 1; l < size.height+1; l++) {
  305. * if (update[l]) {
  306. * for (int c = 0; c < size.height-l;c++) {
  307. * if (!update[c+l]) {
  308. * System.err.println("Redrawing "+(l-1)+" - "+(l+c-2));
  309. * l=l+c;
  310. * break;
  311. * }
  312. * }
  313. * }
  314. * }
  315. * }
  316. */
  317. for (int l = 0; l < buffer.height; l++) {
  318. if (!buffer.update[0] && !buffer.update[l + 1]) {
  319. continue;
  320. }
  321. buffer.update[l + 1] = false;
  322. if (debug > 2) {
  323. System.err.println("redraw(): line " + l);
  324. }
  325. for (int c = 0; c < buffer.width; c++) {
  326. int addr = 0;
  327. int currAttr = buffer.charAttributes[buffer.windowBase + l][c];
  328. fg = getForeground();
  329. bg = getBackground();
  330. // fg = darken(getForeground());
  331. // bg = darken(getBackground());
  332. if ( (currAttr & buffer.COLOR_FG) != 0) {
  333. fg = darken(color[ ( (currAttr & buffer.COLOR_FG) >> 4) - 1]);
  334. }
  335. if ( (currAttr & buffer.COLOR_BG) != 0) {
  336. bg = darken(darken(color[ ( (currAttr & buffer.COLOR_BG) >> 8)
  337. - 1]));
  338. }
  339. if ( (currAttr & VDUBuffer.BOLD) != 0) {
  340. g.setFont(new Font(normalFont.getName(), Font.BOLD,
  341. normalFont.getSize()));
  342. // does not work with IE6: g.setFont(normalFont.deriveFont(Font.BOLD));
  343. if (null != color[COLOR_BOLD]) {
  344. fg = color[COLOR_BOLD];
  345. }
  346. /*
  347. * if(fg.equals(Color.black)) {
  348. * fg = Color.gray;
  349. * } else {
  350. * fg = brighten(fg);
  351. * / bg = bg.brighter(); -- make some programs ugly
  352. * }
  353. */
  354. }
  355. else {
  356. g.setFont(normalFont);
  357. }
  358. if ( (currAttr & VDUBuffer.LOW) != 0) {
  359. fg = darken(fg);
  360. }
  361. if ( (currAttr & VDUBuffer.INVERT) != 0) {
  362. if (null == color[COLOR_INVERT]) {
  363. Color swapc = bg;
  364. bg = fg;
  365. fg = swapc;
  366. }
  367. else {
  368. if (null == color[COLOR_BOLD]) {
  369. fg = bg;
  370. }
  371. else {
  372. fg = color[COLOR_BOLD];
  373. }
  374. bg = color[COLOR_INVERT];
  375. }
  376. }
  377. if (sf.inSoftFont(buffer.charArray[buffer.windowBase + l][c])) {
  378. g.setColor(bg);
  379. g.fillRect( (c * charWidth) + xoffset,
  380. (l * charHeight) + yoffset, charWidth, charHeight);
  381. g.setColor(fg);
  382. sf.drawChar(g, buffer.charArray[buffer.windowBase + l][c],
  383. xoffset + (c * charWidth), (l * charHeight) + yoffset,
  384. charWidth, charHeight);
  385. if ( (currAttr & VDUBuffer.UNDERLINE) != 0) {
  386. g.drawLine( (c * charWidth) + xoffset,
  387. ( (l + 1) * charHeight) - (charDescent / 2)
  388. + yoffset, (c * charWidth) + charWidth + xoffset,
  389. ( (l + 1) * charHeight) - (charDescent / 2)
  390. + yoffset);
  391. }
  392. continue;
  393. }
  394. // determine the maximum of characters we can print in one go
  395. while ( ( (c + addr) < buffer.width)
  396. && ( (buffer.charArray[buffer.windowBase + l][c + addr] < ' ')
  397. || (buffer.charAttributes[buffer.windowBase + l][c
  398. + addr] == currAttr))
  399. && !sf.inSoftFont(
  400. buffer.charArray[buffer.windowBase + l][c + addr])) {
  401. if (buffer.charArray[buffer.windowBase + l][c + addr] < ' ') {
  402. buffer.charArray[buffer.windowBase + l][c + addr] = ' ';
  403. buffer.charAttributes[buffer.windowBase + l][c + addr] = 0;
  404. continue;
  405. }
  406. addr++;
  407. }
  408. // clear the part of the screen we want to change (fill rectangle)
  409. g.setColor(bg);
  410. g.fillRect( (c * charWidth) + xoffset,
  411. (l * charHeight) + yoffset, addr * charWidth, charHeight);
  412. g.setColor(fg);
  413. // draw the characters
  414. g.drawChars(buffer.charArray[buffer.windowBase + l], c, addr,
  415. (c * charWidth) + xoffset,
  416. ( (l + 1) * charHeight) - charDescent + yoffset);
  417. if ( (currAttr & VDUBuffer.UNDERLINE) != 0) {
  418. g.drawLine( (c * charWidth) + xoffset,
  419. ( (l + 1) * charHeight) - (charDescent / 2) + yoffset,
  420. (c * charWidth) + (addr * charWidth) + xoffset,
  421. ( (l + 1) * charHeight) - (charDescent / 2) + yoffset);
  422. }
  423. c += (addr - 1);
  424. }
  425. // selection code, highlites line or part of it when it was
  426. // selected previously
  427. if ( (l >= selectStartLine) && (l <= selectEndLine)) {
  428. int selectStartColumn = ( (l == selectStartLine) ? selectBegin.x
  429. : 0);
  430. int selectEndColumn = ( (l == selectEndLine)
  431. ?
  432. // (l == selectStartLine ? selectEnd.x - selectStartColumn :
  433. ( (l == selectStartLine) ? selectEnd.x :
  434. selectEnd.x)
  435. : buffer.width);
  436. if (selectStartColumn != selectEndColumn) {
  437. if (debug > 0) {
  438. System.err.println("select(" + selectStartColumn + "-"
  439. + selectEndColumn + ")");
  440. }
  441. g.setXORMode(bg);
  442. g.fillRect( (selectStartColumn * charWidth) + xoffset,
  443. (l * charHeight) + yoffset,
  444. (selectEndColumn - selectStartColumn) * charWidth,
  445. charHeight);
  446. g.setPaintMode();
  447. }
  448. }
  449. }
  450. // draw cursor
  451. if (buffer.showcursor
  452. && ( ( (buffer.screenBase + buffer.cursorY) >= buffer.windowBase)
  453. && ( (buffer.screenBase + buffer.cursorY) < (buffer.windowBase
  454. + buffer.height)))) {
  455. g.setColor(cursorColorFG);
  456. g.setXORMode(cursorColorBG);
  457. g.fillRect( (buffer.cursorX * charWidth) + xoffset,
  458. ( ( (buffer.cursorY + buffer.screenBase) - buffer.windowBase) *
  459. charHeight)
  460. + yoffset, charWidth, charHeight);
  461. g.setPaintMode();
  462. g.setColor(color[COLOR_FG_STD]);
  463. }
  464. // draw border
  465. if (insets != null) {
  466. g.setColor(getBackground());
  467. xoffset--;
  468. yoffset--;
  469. for (int i = insets.top - 1; i >= 0; i--) {
  470. g.draw3DRect(xoffset - i, yoffset - i,
  471. (charWidth * buffer.width) + 1 + (i * 2),
  472. (charHeight * buffer.height) + 1 + (i * 2), raised);
  473. }
  474. }
  475. buffer.update[0] = false;
  476. }
  477. public void paint(Graphics g1) {
  478. Graphics2D g = (Graphics2D) g1;
  479. // Antialiasing
  480. if (isAntialias()) {
  481. g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
  482. RenderingHints.VALUE_ANTIALIAS_ON);
  483. }
  484. if (backingStore == null) {
  485. Dimension size = super.getSize();
  486. backingStore = createImage(size.width, size.height);
  487. buffer.update[0] = true;
  488. redraw();
  489. Graphics g2 = backingStore.getGraphics();
  490. g2.setColor(getBackground());
  491. g2.fillRect(0, 0, super.getSize().width, super.getSize().height);
  492. }
  493. if (debug > 1) {
  494. System.err.println("Clip region: " + g.getClipBounds());
  495. }
  496. g.drawImage(backingStore, 0, 0, this);
  497. }
  498. /*
  499. * public int print(Graphics g, PageFormat pf, int pi) throws PrinterException {
  500. * if(pi >= 1) {
  501. * return Printable.NO_SUCH_PAGE;
  502. * }
  503. * paint(g);
  504. * return Printable.PAGE_EXISTS;
  505. * }
  506. */
  507. public void setColorPrinting(boolean colorPrint) {
  508. colorPrinting = colorPrint;
  509. }
  510. public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws
  511. PrinterException {
  512. print(graphics);
  513. return (pageIndex == 0) ? Printable.PAGE_EXISTS : NO_SUCH_PAGE;
  514. }
  515. public void print(Graphics g) {
  516. if (debug > 0) {
  517. System.err.println("DEBUG: print()");
  518. }
  519. for (int i = 0; i <= buffer.height; i++) {
  520. buffer.update[i] = true;
  521. }
  522. Color fg = null;
  523. Color bg = null;
  524. Color[] colorSave = null;
  525. if (!colorPrinting) {
  526. fg = getForeground();
  527. bg = getBackground();
  528. setForeground(Color.black);
  529. setBackground(Color.white);
  530. colorSave = color;
  531. color = new Color[] {
  532. Color.black, Color.black, Color.black, Color.black,
  533. Color.black, Color.black, Color.black, Color.white, null,
  534. null,
  535. };
  536. }
  537. redraw(g);
  538. if (!colorPrinting) {
  539. color = colorSave;
  540. setForeground(fg);
  541. setBackground(bg);
  542. }
  543. }
  544. public Point mouseGetPos(Point evtpt) {
  545. Point mousepos;
  546. mousepos = new Point(0, 0);
  547. int xoffset = (super.getSize().width - (buffer.width * charWidth)) / 2;
  548. int yoffset = (super.getSize().height - (buffer.height * charHeight)) / 2;
  549. mousepos.x = (evtpt.x - xoffset) / charWidth;
  550. if (mousepos.x < 0) {
  551. mousepos.x = 0;
  552. }
  553. if (mousepos.x >= buffer.width) {
  554. mousepos.x = buffer.width - 1;
  555. }
  556. mousepos.y = (evtpt.y - yoffset) / charHeight;
  557. if (mousepos.y < 0) {
  558. mousepos.y = 0;
  559. }
  560. if (mousepos.y >= buffer.height) {
  561. mousepos.y = buffer.height - 1;
  562. }
  563. return mousepos;
  564. }
  565. public void setCursorColors(Color fg, Color bg) {
  566. if (fg == null) {
  567. cursorColorFG = color[COLOR_FG_STD];
  568. }
  569. else {
  570. cursorColorFG = fg;
  571. }
  572. if (bg == null) {
  573. cursorColorBG = color[COLOR_BG_STD];
  574. }
  575. else {
  576. cursorColorBG = bg;
  577. }
  578. repaint();
  579. }
  580. public void setBounds(int x, int y, int w, int h) {
  581. if (debug > 0) {
  582. System.err.println("VDU: setBounds(" + x + "," + y + "," + w + ","
  583. + h + ")");
  584. }
  585. super.setBounds(x, y, w, h);
  586. // ignore zero bounds
  587. if ( (x == 00) && (y == 0) && (w == 0) && (h == 0)) {
  588. return;
  589. }
  590. if (insets != null) {
  591. w -= (insets.left + insets.right);
  592. h -= (insets.top + insets.bottom);
  593. }
  594. if (debug > 0) {
  595. System.err.println("VDU: looking for better match for "
  596. + normalFont);
  597. }
  598. Font tmpFont = normalFont;
  599. String fontName = tmpFont.getName();
  600. int fontStyle = tmpFont.getStyle();
  601. fm = getFontMetrics(normalFont);
  602. if (fm != null) {
  603. charWidth = fm.charWidth('@');
  604. charHeight = fm.getHeight();
  605. }
  606. switch (resizeStrategy) {
  607. case RESIZE_SCREEN:
  608. if (debug > 0) {
  609. System.err.println("VDU: resizing screen");
  610. }
  611. // buffer.setScreenSize(w / charWidth, buffer.height = h / charHeight);
  612. buffer.setScreenSize(w / charWidth, h / charHeight);
  613. break;
  614. case RESIZE_FONT:
  615. if (debug > 0) {
  616. System.err.println("VDU: resizing font");
  617. }
  618. int height = h / buffer.height;
  619. int width = w / buffer.width;
  620. fm = getFontMetrics(normalFont = new Font(fontName, fontStyle,
  621. charHeight));
  622. // adapt current font size (from small up to best fit)
  623. if ( (fm.getHeight() < height) || (fm.charWidth('@') < width)) {
  624. do {
  625. fm = getFontMetrics(normalFont = new Font(fontName,
  626. fontStyle, ++charHeight));
  627. }
  628. while ( (fm.getHeight() < height)
  629. || (fm.charWidth('@') < width));
  630. }
  631. // now check if we got a font that is too large
  632. if ( (fm.getHeight() > height) || (fm.charWidth('@') > width)) {
  633. do {
  634. fm = getFontMetrics(normalFont = new Font(fontName,
  635. fontStyle, --charHeight));
  636. }
  637. while ( (charHeight > 1)
  638. && ( (fm.getHeight() > height)
  639. || (fm.charWidth('@') > width)));
  640. }
  641. if (charHeight <= 1) {
  642. System.err.println(
  643. "VDU: error during resize, resetting to default");
  644. normalFont = new Font(fontName, fontStyle, 10);
  645. System.err.println("VDU: disabling font/screen resize");
  646. }
  647. setFont(normalFont);
  648. fm = getFontMetrics(normalFont);
  649. charWidth = fm.charWidth('@');
  650. charHeight = fm.getHeight();
  651. charDescent = fm.getDescent();
  652. break;
  653. case RESIZE_NONE:
  654. if (debug > 0) {
  655. System.err.println("VDU: not resizing");
  656. }
  657. default:
  658. break;
  659. }
  660. if (debug > 0) {
  661. System.err.println("VDU: charWidth=" + charWidth + ", "
  662. + "charHeight=" + charHeight + ", " + "charDescent="
  663. + charDescent);
  664. }
  665. // delete the double buffer image and mark all lines
  666. // backingStore = null;
  667. // buffer.markLine(0, buffer.height);
  668. Dimension size = super.getSize();
  669. if (size.width <= 0) {
  670. size.width = 1;
  671. }
  672. if (size.height <= 0) {
  673. size.height = 1;
  674. }
  675. backingStore = createImage(size.width, size.height);
  676. if (backingStore != null) {
  677. Graphics g = backingStore.getGraphics();
  678. g.setColor(getBackground());
  679. g.fillRect(0, 0, size.width, size.height);
  680. buffer.update[0] = true;
  681. redraw();
  682. }
  683. }
  684. public void refresh() {
  685. backingStore = null;
  686. repaint();
  687. }
  688. public Dimension getSize() {
  689. int xborder = 0;
  690. int yborder = 0;
  691. if (insets != null) {
  692. xborder = insets.left + insets.right;
  693. yborder = insets.top + insets.bottom;
  694. }
  695. return new Dimension( (buffer.width * charWidth) + xborder,
  696. (buffer.height * charHeight) + yborder);
  697. }
  698. public Dimension getPreferredSize() {
  699. return getSize();
  700. }
  701. public Insets getInsets() {
  702. return insets;
  703. }
  704. public void clearSelection() {
  705. selectBegin = new Point(0, 0);
  706. selectEnd = new Point(0, 0);
  707. selection = null;
  708. }
  709. public String getSelection() {
  710. return selection;
  711. }
  712. public JScrollBar getScrollBar() {
  713. return scrollBar;
  714. }
  715. private boolean buttonCheck(int modifiers, int mask) {
  716. return (modifiers & mask) == mask;
  717. }
  718. public void mouseMoved(MouseEvent evt) {
  719. /*
  720. * nothing yet we do here
  721. */
  722. }
  723. private void selectWord(int x, int y) {
  724. int xoffset = (super.getSize().width - (buffer.width * charWidth)) / 2;
  725. int yoffset = (super.getSize().height - (buffer.height * charHeight)) / 2;
  726. x = (x - xoffset) / charWidth;
  727. y = ( (y - yoffset) / charHeight) + buffer.windowBase;
  728. char[] l = buffer.charArray[y];
  729. int i = x;
  730. for (; (i >= 0) && (l[i] != ' '); i--) {
  731. ;
  732. }
  733. if (i != x) {
  734. selectBegin.y = y;
  735. selectBegin.x = i + 1;
  736. selectEnd.y = y;
  737. int j = x;
  738. for (; (j < l.length) && (l[j] != ' '); j++) {
  739. ;
  740. }
  741. selectEnd.x = j;
  742. buildSelectionText();
  743. buffer.update[0] = true;
  744. redraw();
  745. }
  746. }
  747. private void selectLine(int x, int y) {
  748. int xoffset = (super.getSize().width - (buffer.width * charWidth)) / 2;
  749. int yoffset = (super.getSize().height - (buffer.height * charHeight)) / 2;
  750. x = (x - xoffset) / charWidth;
  751. y = ( (y - yoffset) / charHeight) + buffer.windowBase;
  752. char[] l = buffer.charArray[y];
  753. int i = 0;
  754. for (; (i < l.length) && (l[i] == ' '); i++) {
  755. ;
  756. }
  757. if (i < l.length) {
  758. int j = l.length - 1;
  759. selectBegin.y = y;
  760. selectEnd.y = y;
  761. selectBegin.x = i;
  762. for (; (j >= 0) && (l[j] == ' '); j--) {
  763. ;
  764. }
  765. selectEnd.x = j + 1;
  766. buildSelectionText();
  767. buffer.update[0] = true;
  768. redraw();
  769. }
  770. }
  771. public void mouseDragged(MouseEvent evt) {
  772. if (buttonCheck(evt.getModifiers(), MouseEvent.BUTTON1_MASK)
  773. || ( // Windows NT/95 etc: returns 0, which is a bug
  774. evt.getModifiers() == 0)) {
  775. int xoffset = (super.getSize().width - (buffer.width * charWidth)) / 2;
  776. int yoffset = (super.getSize().height
  777. - (buffer.height * charHeight)) / 2;
  778. int x = (evt.getX() - xoffset) / charWidth;
  779. int y = ( (evt.getY() - yoffset) / charHeight) + buffer.windowBase;
  780. int oldx = selectEnd.x;
  781. int oldy = selectEnd.y;
  782. if ( ( (x <= selectBegin.x) && (y <= selectBegin.y) && (x >= 0))) {
  783. selectBegin.x = x;
  784. selectBegin.y = y;
  785. }
  786. else {
  787. if ( (x <= buffer.width) && (x >= 0)) {
  788. selectEnd.x = x;
  789. }
  790. selectEnd.y = y;
  791. }
  792. if ( (oldx != x) || (oldy != y)) {
  793. buffer.update[0] = true;
  794. if (debug > 0) {
  795. System.err.println("select([" + selectBegin.x + ","
  796. + selectBegin.y + "]," + "[" + selectEnd.x + ","
  797. + selectEnd.y + "])");
  798. }
  799. redraw();
  800. }
  801. }
  802. }
  803. public void mouseClicked(MouseEvent evt) {
  804. if (evt.getClickCount() == 2) {
  805. selectWord(evt.getX(), evt.getY());
  806. }
  807. else if (evt.getClickCount() == 3) {
  808. selectLine(evt.getX(), evt.getY());
  809. }
  810. else {
  811. requestFocus();
  812. }
  813. /*
  814. * nothing yet we do here
  815. */
  816. }
  817. public void mouseEntered(MouseEvent evt) {
  818. /*
  819. * nothing yet we do here
  820. */
  821. }
  822. public void mouseExited(MouseEvent evt) {
  823. /*
  824. * nothing yet we do here
  825. */
  826. }
  827. public void mousePressed(MouseEvent evt) {
  828. requestFocus();
  829. int xoffset = (super.getSize().width - (buffer.width * charWidth)) / 2;
  830. int yoffset = (super.getSize().height - (buffer.height * charHeight)) / 2;
  831. if (buffer instanceof VDUInput) {
  832. ( (VDUInput) buffer).mousePressed(xoffset, yoffset,
  833. evt.getModifiers());
  834. }
  835. // looks like we get no modifiers here ... ... We do? -Marcus
  836. if (buttonCheck(evt.getModifiers(), MouseEvent.BUTTON1_MASK)) {
  837. selectBegin.x = (evt.getX() - xoffset) / charWidth;
  838. selectBegin.y = ( (evt.getY() - yoffset) / charHeight)
  839. + buffer.windowBase;
  840. selectEnd.x = selectBegin.x;
  841. selectEnd.y = selectBegin.y;
  842. }
  843. }
  844. public void mouseReleased(MouseEvent evt) {
  845. int xoffset = (super.getSize().width - (buffer.width * charWidth)) / 2;
  846. int yoffset = (super.getSize().height - (buffer.height * charHeight)) / 2;
  847. if (buffer instanceof VDUInput) {
  848. ( (VDUInput) buffer).mousePressed(xoffset, yoffset,
  849. evt.getModifiers());
  850. }
  851. if (buttonCheck(evt.getModifiers(), MouseEvent.BUTTON1_MASK)) {
  852. mouseDragged(evt);
  853. if ( (selectBegin.x == selectEnd.x)
  854. && (selectBegin.y == selectEnd.y)) {
  855. buffer.update[0] = true;
  856. redraw();
  857. return;
  858. }
  859. // fix end.x and end.y, they can get over the border
  860. if (selectEnd.x < 0) {
  861. selectEnd.x = 0;
  862. }
  863. if (selectEnd.y < 0) {
  864. selectEnd.y = 0;
  865. }
  866. if (selectEnd.y >= buffer.charArray.length) {
  867. selectEnd.y = buffer.charArray.length - 1;
  868. }
  869. if (selectEnd.x > buffer.charArray[0].length) {
  870. selectEnd.x = buffer.charArray[0].length;
  871. }
  872. buildSelectionText();
  873. }
  874. }
  875. private void buildSelectionText() {
  876. selection = "";
  877. for (int l = selectBegin.y; l <= selectEnd.y; l++) {
  878. int start;
  879. int end;
  880. start = ( (l == selectBegin.y) ? (start = selectBegin.x) : 0);
  881. end = ( (l == selectEnd.y) ? (end = selectEnd.x)
  882. : buffer.charArray[l].length);
  883. // Trim all spaces from end of line, like xterm does.
  884. selection += ("-"
  885. + (new String(buffer.charArray[l])).substring(start, end)).
  886. trim()
  887. .substring(1);
  888. if (end == buffer.charArray[l].length) {
  889. selection += "\n";
  890. }
  891. }
  892. }
  893. public void keyTyped(KeyEvent e) {
  894. if (buffer != null) {
  895. ( (VDUInput) buffer).keyTyped(e.getKeyCode(), e.getKeyChar(),
  896. getModifiers(e));
  897. }
  898. }
  899. public void keyPressed(KeyEvent e) {
  900. if (buffer != null) {
  901. ( (VDUInput) buffer).keyPressed(e.getKeyCode(), e.getKeyChar(),
  902. getModifiers(e));
  903. }
  904. }
  905. public void keyReleased(KeyEvent e) {
  906. // ignore
  907. }
  908. public void addMouseListener(MouseListener listener) {
  909. mouseListener = AWTEventMulticaster.add(mouseListener, listener);
  910. enableEvents(AWTEvent.MOUSE_EVENT_MASK);
  911. }
  912. public void removeMouseListener(MouseListener listener) {
  913. mouseListener = AWTEventMulticaster.remove(mouseListener, listener);
  914. }
  915. public void addMouseMotionListener(MouseMotionListener listener) {
  916. mouseMotionListener = AWTEventMulticaster.add(mouseMotionListener,
  917. listener);
  918. enableEvents(AWTEvent.MOUSE_EVENT_MASK);
  919. }
  920. public void removeMouseMotionListener(MouseMotionListener listener) {
  921. mouseMotionListener = AWTEventMulticaster.remove(mouseMotionListener,
  922. listener);
  923. }
  924. /*public void addMouseWheelListener(MouseWheelListener listener) {
  925. mouseWheelListener = AWTEventMulticaster.add(mouseWheelListener,
  926. listener);
  927. enableEvents(AWTEvent.MOUSE_WHEEL_EVENT_MASK);
  928. }*/
  929. /*public void removeMouseWheelListener(MouseWheelListener listener) {
  930. mouseWheelListener = AWTEventMulticaster.remove(mouseWheelListener,
  931. listener);
  932. }*/
  933. public void processMouseEvent(MouseEvent evt) {
  934. // handle simple mouse events
  935. if (mouseListener != null) {
  936. switch (evt.getID()) {
  937. case MouseEvent.MOUSE_CLICKED:
  938. mouseListener.mouseClicked(evt);
  939. break;
  940. case MouseEvent.MOUSE_ENTERED:
  941. mouseListener.mouseEntered(evt);
  942. break;
  943. case MouseEvent.MOUSE_EXITED:
  944. mouseListener.mouseExited(evt);
  945. break;
  946. case MouseEvent.MOUSE_PRESSED:
  947. mouseListener.mousePressed(evt);
  948. break;
  949. case MouseEvent.MOUSE_RELEASED:
  950. mouseListener.mouseReleased(evt);
  951. break;
  952. }
  953. }
  954. super.processMouseEvent(evt);
  955. }
  956. public void processMouseMotionEvent(MouseEvent evt) {
  957. // handle mouse motion events
  958. if (mouseMotionListener != null) {
  959. switch (evt.getID()) {
  960. case MouseEvent.MOUSE_DRAGGED:
  961. mouseMotionListener.mouseDragged(evt);
  962. break;
  963. case MouseEvent.MOUSE_MOVED:
  964. mouseMotionListener.mouseMoved(evt);
  965. break;
  966. }
  967. }
  968. super.processMouseMotionEvent(evt);
  969. }
  970. /*public void processMouseWheelEvent(MouseWheelEvent evt) {
  971. if (mouseWheelListener != null) {
  972. mouseWheelListener.mouseWheelMoved(evt);
  973. }
  974. super.processMouseWheelEvent(evt);
  975. }*/
  976. public void addKeyListener(KeyListener listener) {
  977. keyListener = AWTEventMulticaster.add(keyListener, listener);
  978. enableEvents(AWTEvent.KEY_EVENT_MASK);
  979. }
  980. public void removeKeyListener(KeyListener listener) {
  981. keyListener = AWTEventMulticaster.remove(keyListener, listener);
  982. }
  983. public void processKeyEvent(KeyEvent evt) {
  984. if (keyListener != null) {
  985. switch (evt.getID()) {
  986. case KeyEvent.KEY_PRESSED:
  987. keyListener.keyPressed(evt);
  988. break;
  989. case KeyEvent.KEY_RELEASED:
  990. keyListener.keyReleased(evt);
  991. break;
  992. case KeyEvent.KEY_TYPED:
  993. keyListener.keyTyped(evt);
  994. break;
  995. }
  996. }
  997. // consume TAB keys if they originate from our component
  998. if ( (evt.getKeyCode() == KeyEvent.VK_TAB) && (evt.getSource() == this)) {
  999. evt.consume();
  1000. }
  1001. super.processKeyEvent(evt);
  1002. }
  1003. public void addFocusListener(FocusListener listener) {
  1004. focusListener = AWTEventMulticaster.add(focusListener, listener);
  1005. }
  1006. public void removeFocusListener(FocusListener listener) {
  1007. focusListener = AWTEventMulticaster.remove(focusListener, listener);
  1008. }
  1009. public void processFocusEvent(FocusEvent evt) {
  1010. if (debug > 0) {
  1011. System.out.println("VDU: focuse event " + evt);
  1012. }
  1013. if (focusListener != null) {
  1014. switch (evt.getID()) {
  1015. case FocusEvent.FOCUS_GAINED:
  1016. focusListener.focusGained(evt);
  1017. break;
  1018. case FocusEvent.FOCUS_LOST:
  1019. focusListener.focusLost(evt);
  1020. break;
  1021. }
  1022. }
  1023. super.processFocusEvent(evt);
  1024. }
  1025. private int getModifiers(KeyEvent e) {
  1026. return (e.isControlDown() ? VDUInput.KEY_CONTROL : 0)
  1027. | (e.isShiftDown() ? VDUInput.KEY_SHIFT : 0)
  1028. | (e.isAltDown() ? VDUInput.KEY_ALT : 0)
  1029. | (e.isActionKey() ? VDUInput.KEY_ACTION : 0);
  1030. }
  1031. }