1. /*
  2. * @(#)DefaultEditorKit.java 1.67 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.text;
  8. import java.io.*;
  9. import java.awt.*;
  10. import java.awt.event.ActionEvent;
  11. import java.text.*;
  12. import javax.swing.Action;
  13. import javax.swing.KeyStroke;
  14. import javax.swing.SwingConstants;
  15. import javax.swing.UIManager;
  16. /**
  17. * This is the set of things needed by a text component
  18. * to be a reasonably functioning editor for some <em>type</em>
  19. * of text document. This implementation provides a default
  20. * implementation which treats text as plain text and
  21. * provides a minimal set of actions for a simple editor.
  22. * <p>
  23. * <dl>
  24. * <dt><b><font size=+1>Newlines</font></b>
  25. * <dd>
  26. * There are two properties which deal with newlines. The
  27. * system property, <code>line.separator</code>, is defined to be
  28. * platform-dependent, either "\n", "\r", or "\r\n". There is also
  29. * a property defined in <code>DefaultEditorKit</code>, called
  30. * <a href=#EndOfLineStringProperty><code>EndOfLineStringProperty</code></a>,
  31. * which is defined automatically when a document is loaded, to be
  32. * the first occurrence of any of the newline characters.
  33. * When a document is loaded, <code>EndOfLineStringProperty</code>
  34. * is set appropriately, and when the document is written back out, the
  35. * <code>EndOfLineStringProperty</code> is used. But while the document
  36. * is in memory, the "\n" character is used to define a
  37. * newline, regardless of how the newline is defined when
  38. * the document is on disk. Therefore, for searching purposes,
  39. * "\n" should always be used. When a new document is created,
  40. * and the <code>EndOfLineStringProperty</code> has not been defined,
  41. * it will use the System property when writing out the
  42. * document.
  43. * <p>Note that <code>EndOfLineStringProperty</code> is set
  44. * on the <code>Document</code> using the <code>get/setProperty</code>
  45. * methods. Subclasses may override this behavior.
  46. *
  47. * </dl>
  48. *
  49. * @author Timothy Prinzing
  50. * @version 1.67 12/19/03
  51. */
  52. public class DefaultEditorKit extends EditorKit {
  53. /**
  54. * default constructor for DefaultEditorKit
  55. */
  56. public DefaultEditorKit() {
  57. }
  58. /**
  59. * Gets the MIME type of the data that this
  60. * kit represents support for. The default
  61. * is <code>text/plain</code>.
  62. *
  63. * @return the type
  64. */
  65. public String getContentType() {
  66. return "text/plain";
  67. }
  68. /**
  69. * Fetches a factory that is suitable for producing
  70. * views of any models that are produced by this
  71. * kit. The default is to have the UI produce the
  72. * factory, so this method has no implementation.
  73. *
  74. * @return the view factory
  75. */
  76. public ViewFactory getViewFactory() {
  77. return null;
  78. }
  79. /**
  80. * Fetches the set of commands that can be used
  81. * on a text component that is using a model and
  82. * view produced by this kit.
  83. *
  84. * @return the command list
  85. */
  86. public Action[] getActions() {
  87. return defaultActions;
  88. }
  89. /**
  90. * Fetches a caret that can navigate through views
  91. * produced by the associated ViewFactory.
  92. *
  93. * @return the caret
  94. */
  95. public Caret createCaret() {
  96. return null;
  97. }
  98. /**
  99. * Creates an uninitialized text storage model (PlainDocument)
  100. * that is appropriate for this type of editor.
  101. *
  102. * @return the model
  103. */
  104. public Document createDefaultDocument() {
  105. return new PlainDocument();
  106. }
  107. /**
  108. * Inserts content from the given stream which is expected
  109. * to be in a format appropriate for this kind of content
  110. * handler.
  111. *
  112. * @param in The stream to read from
  113. * @param doc The destination for the insertion.
  114. * @param pos The location in the document to place the
  115. * content >= 0.
  116. * @exception IOException on any I/O error
  117. * @exception BadLocationException if pos represents an invalid
  118. * location within the document.
  119. */
  120. public void read(InputStream in, Document doc, int pos)
  121. throws IOException, BadLocationException {
  122. read(new InputStreamReader(in), doc, pos);
  123. }
  124. /**
  125. * Writes content from a document to the given stream
  126. * in a format appropriate for this kind of content handler.
  127. *
  128. * @param out The stream to write to
  129. * @param doc The source for the write.
  130. * @param pos The location in the document to fetch the
  131. * content >= 0.
  132. * @param len The amount to write out >= 0.
  133. * @exception IOException on any I/O error
  134. * @exception BadLocationException if pos represents an invalid
  135. * location within the document.
  136. */
  137. public void write(OutputStream out, Document doc, int pos, int len)
  138. throws IOException, BadLocationException {
  139. OutputStreamWriter osw = new OutputStreamWriter(out);
  140. write(osw, doc, pos, len);
  141. osw.flush();
  142. }
  143. /**
  144. * Gets the input attributes for the pane. This method exists for
  145. * the benefit of StyledEditorKit so that the read method will
  146. * pick up the correct attributes to apply to inserted text.
  147. * This class's implementation simply returns null.
  148. *
  149. * @return null
  150. */
  151. MutableAttributeSet getInputAttributes() {
  152. return null;
  153. }
  154. /**
  155. * Inserts content from the given stream, which will be
  156. * treated as plain text.
  157. *
  158. * @param in The stream to read from
  159. * @param doc The destination for the insertion.
  160. * @param pos The location in the document to place the
  161. * content >= 0.
  162. * @exception IOException on any I/O error
  163. * @exception BadLocationException if pos represents an invalid
  164. * location within the document.
  165. */
  166. public void read(Reader in, Document doc, int pos)
  167. throws IOException, BadLocationException {
  168. char[] buff = new char[4096];
  169. int nch;
  170. boolean lastWasCR = false;
  171. boolean isCRLF = false;
  172. boolean isCR = false;
  173. int last;
  174. boolean wasEmpty = (doc.getLength() == 0);
  175. AttributeSet attr = getInputAttributes();
  176. // Read in a block at a time, mapping \r\n to \n, as well as single
  177. // \r's to \n's. If a \r\n is encountered, \r\n will be set as the
  178. // newline string for the document, if \r is encountered it will
  179. // be set as the newline character, otherwise the newline property
  180. // for the document will be removed.
  181. while ((nch = in.read(buff, 0, buff.length)) != -1) {
  182. last = 0;
  183. for(int counter = 0; counter < nch; counter++) {
  184. switch(buff[counter]) {
  185. case '\r':
  186. if (lastWasCR) {
  187. isCR = true;
  188. if (counter == 0) {
  189. doc.insertString(pos, "\n", attr);
  190. pos++;
  191. }
  192. else {
  193. buff[counter - 1] = '\n';
  194. }
  195. }
  196. else {
  197. lastWasCR = true;
  198. }
  199. break;
  200. case '\n':
  201. if (lastWasCR) {
  202. if (counter > (last + 1)) {
  203. doc.insertString(pos, new String(buff, last,
  204. counter - last - 1), attr);
  205. pos += (counter - last - 1);
  206. }
  207. // else nothing to do, can skip \r, next write will
  208. // write \n
  209. lastWasCR = false;
  210. last = counter;
  211. isCRLF = true;
  212. }
  213. break;
  214. default:
  215. if (lastWasCR) {
  216. isCR = true;
  217. if (counter == 0) {
  218. doc.insertString(pos, "\n", attr);
  219. pos++;
  220. }
  221. else {
  222. buff[counter - 1] = '\n';
  223. }
  224. lastWasCR = false;
  225. }
  226. break;
  227. }
  228. }
  229. if (last < nch) {
  230. if(lastWasCR) {
  231. if (last < (nch - 1)) {
  232. doc.insertString(pos, new String(buff, last,
  233. nch - last - 1), attr);
  234. pos += (nch - last - 1);
  235. }
  236. }
  237. else {
  238. doc.insertString(pos, new String(buff, last,
  239. nch - last), attr);
  240. pos += (nch - last);
  241. }
  242. }
  243. }
  244. if (lastWasCR) {
  245. doc.insertString(pos, "\n", attr);
  246. isCR = true;
  247. }
  248. if (wasEmpty) {
  249. if (isCRLF) {
  250. doc.putProperty(EndOfLineStringProperty, "\r\n");
  251. }
  252. else if (isCR) {
  253. doc.putProperty(EndOfLineStringProperty, "\r");
  254. }
  255. else {
  256. doc.putProperty(EndOfLineStringProperty, "\n");
  257. }
  258. }
  259. }
  260. /**
  261. * Writes content from a document to the given stream
  262. * as plain text.
  263. *
  264. * @param out The stream to write to
  265. * @param doc The source for the write.
  266. * @param pos The location in the document to fetch the
  267. * content from >= 0.
  268. * @param len The amount to write out >= 0.
  269. * @exception IOException on any I/O error
  270. * @exception BadLocationException if pos is not within 0 and
  271. * the length of the document.
  272. */
  273. public void write(Writer out, Document doc, int pos, int len)
  274. throws IOException, BadLocationException {
  275. if ((pos < 0) || ((pos + len) > doc.getLength())) {
  276. throw new BadLocationException("DefaultEditorKit.write", pos);
  277. }
  278. Segment data = new Segment();
  279. int nleft = len;
  280. int offs = pos;
  281. Object endOfLineProperty = doc.getProperty(EndOfLineStringProperty);
  282. if (endOfLineProperty == null) {
  283. try {
  284. endOfLineProperty = System.getProperty("line.separator");
  285. } catch (SecurityException se) { }
  286. }
  287. String endOfLine;
  288. if (endOfLineProperty instanceof String) {
  289. endOfLine = (String)endOfLineProperty;
  290. }
  291. else {
  292. endOfLine = null;
  293. }
  294. if (endOfLineProperty != null && !endOfLine.equals("\n")) {
  295. // There is an end of line string that isn't \n, have to iterate
  296. // through and find all \n's and translate to end of line string.
  297. while (nleft > 0) {
  298. int n = Math.min(nleft, 4096);
  299. doc.getText(offs, n, data);
  300. int last = data.offset;
  301. char[] array = data.array;
  302. int maxCounter = last + data.count;
  303. for (int counter = last; counter < maxCounter; counter++) {
  304. if (array[counter] == '\n') {
  305. if (counter > last) {
  306. out.write(array, last, counter - last);
  307. }
  308. out.write(endOfLine);
  309. last = counter + 1;
  310. }
  311. }
  312. if (maxCounter > last) {
  313. out.write(array, last, maxCounter - last);
  314. }
  315. offs += n;
  316. nleft -= n;
  317. }
  318. }
  319. else {
  320. // Just write out text, will already have \n, no mapping to
  321. // do.
  322. while (nleft > 0) {
  323. int n = Math.min(nleft, 4096);
  324. doc.getText(offs, n, data);
  325. out.write(data.array, data.offset, data.count);
  326. offs += n;
  327. nleft -= n;
  328. }
  329. }
  330. out.flush();
  331. }
  332. /**
  333. * When reading a document if a CRLF is encountered a property
  334. * with this name is added and the value will be "\r\n".
  335. */
  336. public static final String EndOfLineStringProperty = "__EndOfLine__";
  337. // --- names of well-known actions ---------------------------
  338. /**
  339. * Name of the action to place content into the associated
  340. * document. If there is a selection, it is removed before
  341. * the new content is added.
  342. * @see #getActions
  343. */
  344. public static final String insertContentAction = "insert-content";
  345. /**
  346. * Name of the action to place a line/paragraph break into
  347. * the document. If there is a selection, it is removed before
  348. * the break is added.
  349. * @see #getActions
  350. */
  351. public static final String insertBreakAction = "insert-break";
  352. /**
  353. * Name of the action to place a tab character into
  354. * the document. If there is a selection, it is removed before
  355. * the tab is added.
  356. * @see #getActions
  357. */
  358. public static final String insertTabAction = "insert-tab";
  359. /**
  360. * Name of the action to delete the character of content that
  361. * precedes the current caret position.
  362. * @see #getActions
  363. */
  364. public static final String deletePrevCharAction = "delete-previous";
  365. /**
  366. * Name of the action to delete the character of content that
  367. * follows the current caret position.
  368. * @see #getActions
  369. */
  370. public static final String deleteNextCharAction = "delete-next";
  371. /**
  372. * Name of the action to set the editor into read-only
  373. * mode.
  374. * @see #getActions
  375. */
  376. public static final String readOnlyAction = "set-read-only";
  377. /**
  378. * Name of the action to set the editor into writeable
  379. * mode.
  380. * @see #getActions
  381. */
  382. public static final String writableAction = "set-writable";
  383. /**
  384. * Name of the action to cut the selected region
  385. * and place the contents into the system clipboard.
  386. * @see JTextComponent#cut
  387. * @see #getActions
  388. */
  389. public static final String cutAction = "cut-to-clipboard";
  390. /**
  391. * Name of the action to copy the selected region
  392. * and place the contents into the system clipboard.
  393. * @see JTextComponent#copy
  394. * @see #getActions
  395. */
  396. public static final String copyAction = "copy-to-clipboard";
  397. /**
  398. * Name of the action to paste the contents of the
  399. * system clipboard into the selected region, or before the
  400. * caret if nothing is selected.
  401. * @see JTextComponent#paste
  402. * @see #getActions
  403. */
  404. public static final String pasteAction = "paste-from-clipboard";
  405. /**
  406. * Name of the action to create a beep.
  407. * @see #getActions
  408. */
  409. public static final String beepAction = "beep";
  410. /**
  411. * Name of the action to page up vertically.
  412. * @see #getActions
  413. */
  414. public static final String pageUpAction = "page-up";
  415. /**
  416. * Name of the action to page down vertically.
  417. * @see #getActions
  418. */
  419. public static final String pageDownAction = "page-down";
  420. /**
  421. * Name of the action to page up vertically, and move the
  422. * selection.
  423. * @see #getActions
  424. */
  425. /*public*/ static final String selectionPageUpAction = "selection-page-up";
  426. /**
  427. * Name of the action to page down vertically, and move the
  428. * selection.
  429. * @see #getActions
  430. */
  431. /*public*/ static final String selectionPageDownAction = "selection-page-down";
  432. /**
  433. * Name of the action to page left horizontally, and move the
  434. * selection.
  435. * @see #getActions
  436. */
  437. /*public*/ static final String selectionPageLeftAction = "selection-page-left";
  438. /**
  439. * Name of the action to page right horizontally, and move the
  440. * selection.
  441. * @see #getActions
  442. */
  443. /*public*/ static final String selectionPageRightAction = "selection-page-right";
  444. /**
  445. * Name of the Action for moving the caret
  446. * logically forward one position.
  447. * @see #getActions
  448. */
  449. public static final String forwardAction = "caret-forward";
  450. /**
  451. * Name of the Action for moving the caret
  452. * logically backward one position.
  453. * @see #getActions
  454. */
  455. public static final String backwardAction = "caret-backward";
  456. /**
  457. * Name of the Action for extending the selection
  458. * by moving the caret logically forward one position.
  459. * @see #getActions
  460. */
  461. public static final String selectionForwardAction = "selection-forward";
  462. /**
  463. * Name of the Action for extending the selection
  464. * by moving the caret logically backward one position.
  465. * @see #getActions
  466. */
  467. public static final String selectionBackwardAction = "selection-backward";
  468. /**
  469. * Name of the Action for moving the caret
  470. * logically upward one position.
  471. * @see #getActions
  472. */
  473. public static final String upAction = "caret-up";
  474. /**
  475. * Name of the Action for moving the caret
  476. * logically downward one position.
  477. * @see #getActions
  478. */
  479. public static final String downAction = "caret-down";
  480. /**
  481. * Name of the Action for moving the caret
  482. * logically upward one position, extending the selection.
  483. * @see #getActions
  484. */
  485. public static final String selectionUpAction = "selection-up";
  486. /**
  487. * Name of the Action for moving the caret
  488. * logically downward one position, extending the selection.
  489. * @see #getActions
  490. */
  491. public static final String selectionDownAction = "selection-down";
  492. /**
  493. * Name of the <code>Action</code> for moving the caret
  494. * to the beginning of a word.
  495. * @see #getActions
  496. */
  497. public static final String beginWordAction = "caret-begin-word";
  498. /**
  499. * Name of the Action for moving the caret
  500. * to the end of a word.
  501. * @see #getActions
  502. */
  503. public static final String endWordAction = "caret-end-word";
  504. /**
  505. * Name of the <code>Action</code> for moving the caret
  506. * to the beginning of a word, extending the selection.
  507. * @see #getActions
  508. */
  509. public static final String selectionBeginWordAction = "selection-begin-word";
  510. /**
  511. * Name of the Action for moving the caret
  512. * to the end of a word, extending the selection.
  513. * @see #getActions
  514. */
  515. public static final String selectionEndWordAction = "selection-end-word";
  516. /**
  517. * Name of the <code>Action</code> for moving the caret to the
  518. * beginning of the previous word.
  519. * @see #getActions
  520. */
  521. public static final String previousWordAction = "caret-previous-word";
  522. /**
  523. * Name of the <code>Action</code> for moving the caret to the
  524. * beginning of the next word.
  525. * @see #getActions
  526. */
  527. public static final String nextWordAction = "caret-next-word";
  528. /**
  529. * Name of the <code>Action</code> for moving the selection to the
  530. * beginning of the previous word, extending the selection.
  531. * @see #getActions
  532. */
  533. public static final String selectionPreviousWordAction = "selection-previous-word";
  534. /**
  535. * Name of the <code>Action</code> for moving the selection to the
  536. * beginning of the next word, extending the selection.
  537. * @see #getActions
  538. */
  539. public static final String selectionNextWordAction = "selection-next-word";
  540. /**
  541. * Name of the <code>Action</code> for moving the caret
  542. * to the beginning of a line.
  543. * @see #getActions
  544. */
  545. public static final String beginLineAction = "caret-begin-line";
  546. /**
  547. * Name of the <code>Action</code> for moving the caret
  548. * to the end of a line.
  549. * @see #getActions
  550. */
  551. public static final String endLineAction = "caret-end-line";
  552. /**
  553. * Name of the <code>Action</code> for moving the caret
  554. * to the beginning of a line, extending the selection.
  555. * @see #getActions
  556. */
  557. public static final String selectionBeginLineAction = "selection-begin-line";
  558. /**
  559. * Name of the <code>Action</code> for moving the caret
  560. * to the end of a line, extending the selection.
  561. * @see #getActions
  562. */
  563. public static final String selectionEndLineAction = "selection-end-line";
  564. /**
  565. * Name of the <code>Action</code> for moving the caret
  566. * to the beginning of a paragraph.
  567. * @see #getActions
  568. */
  569. public static final String beginParagraphAction = "caret-begin-paragraph";
  570. /**
  571. * Name of the <code>Action</code> for moving the caret
  572. * to the end of a paragraph.
  573. * @see #getActions
  574. */
  575. public static final String endParagraphAction = "caret-end-paragraph";
  576. /**
  577. * Name of the <code>Action</code> for moving the caret
  578. * to the beginning of a paragraph, extending the selection.
  579. * @see #getActions
  580. */
  581. public static final String selectionBeginParagraphAction = "selection-begin-paragraph";
  582. /**
  583. * Name of the <code>Action</code> for moving the caret
  584. * to the end of a paragraph, extending the selection.
  585. * @see #getActions
  586. */
  587. public static final String selectionEndParagraphAction = "selection-end-paragraph";
  588. /**
  589. * Name of the <code>Action</code> for moving the caret
  590. * to the beginning of the document.
  591. * @see #getActions
  592. */
  593. public static final String beginAction = "caret-begin";
  594. /**
  595. * Name of the <code>Action</code> for moving the caret
  596. * to the end of the document.
  597. * @see #getActions
  598. */
  599. public static final String endAction = "caret-end";
  600. /**
  601. * Name of the <code>Action</code> for moving the caret
  602. * to the beginning of the document.
  603. * @see #getActions
  604. */
  605. public static final String selectionBeginAction = "selection-begin";
  606. /**
  607. * Name of the Action for moving the caret
  608. * to the end of the document.
  609. * @see #getActions
  610. */
  611. public static final String selectionEndAction = "selection-end";
  612. /**
  613. * Name of the Action for selecting a word around the caret.
  614. * @see #getActions
  615. */
  616. public static final String selectWordAction = "select-word";
  617. /**
  618. * Name of the Action for selecting a line around the caret.
  619. * @see #getActions
  620. */
  621. public static final String selectLineAction = "select-line";
  622. /**
  623. * Name of the Action for selecting a paragraph around the caret.
  624. * @see #getActions
  625. */
  626. public static final String selectParagraphAction = "select-paragraph";
  627. /**
  628. * Name of the Action for selecting the entire document
  629. * @see #getActions
  630. */
  631. public static final String selectAllAction = "select-all";
  632. /**
  633. * Name of the Action for removing selection
  634. * @see #getActions
  635. */
  636. /*public*/ static final String unselectAction = "unselect";
  637. /**
  638. * Name of the Action for toggling the component's orientation.
  639. * @see #getActions
  640. */
  641. /*public*/ static final String toggleComponentOrientationAction
  642. = "toggle-componentOrientation";
  643. /**
  644. * Name of the action that is executed by default if
  645. * a <em>key typed event</em> is received and there
  646. * is no keymap entry.
  647. * @see #getActions
  648. */
  649. public static final String defaultKeyTypedAction = "default-typed";
  650. // --- Action implementations ---------------------------------
  651. private static final Action[] defaultActions = {
  652. new InsertContentAction(), new DeletePrevCharAction(),
  653. new DeleteNextCharAction(), new ReadOnlyAction(),
  654. new WritableAction(), new CutAction(),
  655. new CopyAction(), new PasteAction(),
  656. new VerticalPageAction(pageUpAction, -1, false),
  657. new VerticalPageAction(pageDownAction, 1, false),
  658. new VerticalPageAction(selectionPageUpAction, -1, true),
  659. new VerticalPageAction(selectionPageDownAction, 1, true),
  660. new PageAction(selectionPageLeftAction, true, true),
  661. new PageAction(selectionPageRightAction, false, true),
  662. new InsertBreakAction(), new BeepAction(),
  663. new NextVisualPositionAction(forwardAction, false,
  664. SwingConstants.EAST),
  665. new NextVisualPositionAction(backwardAction, false,
  666. SwingConstants.WEST),
  667. new NextVisualPositionAction(selectionForwardAction, true,
  668. SwingConstants.EAST),
  669. new NextVisualPositionAction(selectionBackwardAction, true,
  670. SwingConstants.WEST),
  671. new NextVisualPositionAction(upAction, false,
  672. SwingConstants.NORTH),
  673. new NextVisualPositionAction(downAction, false,
  674. SwingConstants.SOUTH),
  675. new NextVisualPositionAction(selectionUpAction, true,
  676. SwingConstants.NORTH),
  677. new NextVisualPositionAction(selectionDownAction, true,
  678. SwingConstants.SOUTH),
  679. new BeginWordAction(beginWordAction, false),
  680. new EndWordAction(endWordAction, false),
  681. new BeginWordAction(selectionBeginWordAction, true),
  682. new EndWordAction(selectionEndWordAction, true),
  683. new PreviousWordAction(previousWordAction, false),
  684. new NextWordAction(nextWordAction, false),
  685. new PreviousWordAction(selectionPreviousWordAction, true),
  686. new NextWordAction(selectionNextWordAction, true),
  687. new BeginLineAction(beginLineAction, false),
  688. new EndLineAction(endLineAction, false),
  689. new BeginLineAction(selectionBeginLineAction, true),
  690. new EndLineAction(selectionEndLineAction, true),
  691. new BeginParagraphAction(beginParagraphAction, false),
  692. new EndParagraphAction(endParagraphAction, false),
  693. new BeginParagraphAction(selectionBeginParagraphAction, true),
  694. new EndParagraphAction(selectionEndParagraphAction, true),
  695. new BeginAction(beginAction, false),
  696. new EndAction(endAction, false),
  697. new BeginAction(selectionBeginAction, true),
  698. new EndAction(selectionEndAction, true),
  699. new DefaultKeyTypedAction(), new InsertTabAction(),
  700. new SelectWordAction(), new SelectLineAction(),
  701. new SelectParagraphAction(), new SelectAllAction(),
  702. new UnselectAction(), new ToggleComponentOrientationAction(),
  703. new DumpModelAction()
  704. };
  705. /**
  706. * The action that is executed by default if
  707. * a <em>key typed event</em> is received and there
  708. * is no keymap entry. There is a variation across
  709. * different VM's in what gets sent as a <em>key typed</em>
  710. * event, and this action tries to filter out the undesired
  711. * events. This filters the control characters and those
  712. * with the ALT modifier. It allows Control-Alt sequences
  713. * through as these form legitimate unicode characters on
  714. * some PC keyboards.
  715. * <p>
  716. * If the event doesn't get filtered, it will try to insert
  717. * content into the text editor. The content is fetched
  718. * from the command string of the ActionEvent. The text
  719. * entry is done through the <code>replaceSelection</code>
  720. * method on the target text component. This is the
  721. * action that will be fired for most text entry tasks.
  722. * <p>
  723. * <strong>Warning:</strong>
  724. * Serialized objects of this class will not be compatible with
  725. * future Swing releases. The current serialization support is
  726. * appropriate for short term storage or RMI between applications running
  727. * the same version of Swing. As of 1.4, support for long term storage
  728. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  729. * has been added to the <code>java.beans</code> package.
  730. * Please see {@link java.beans.XMLEncoder}.
  731. *
  732. * @see DefaultEditorKit#defaultKeyTypedAction
  733. * @see DefaultEditorKit#getActions
  734. * @see Keymap#setDefaultAction
  735. * @see Keymap#getDefaultAction
  736. */
  737. public static class DefaultKeyTypedAction extends TextAction {
  738. /**
  739. * Creates this object with the appropriate identifier.
  740. */
  741. public DefaultKeyTypedAction() {
  742. super(defaultKeyTypedAction);
  743. }
  744. /**
  745. * The operation to perform when this action is triggered.
  746. *
  747. * @param e the action event
  748. */
  749. public void actionPerformed(ActionEvent e) {
  750. JTextComponent target = getTextComponent(e);
  751. if ((target != null) && (e != null)) {
  752. if ((! target.isEditable()) || (! target.isEnabled())) {
  753. return;
  754. }
  755. String content = e.getActionCommand();
  756. int mod = e.getModifiers();
  757. if ((content != null) && (content.length() > 0) &&
  758. ((mod & ActionEvent.ALT_MASK) == (mod & ActionEvent.CTRL_MASK))) {
  759. char c = content.charAt(0);
  760. if ((c >= 0x20) && (c != 0x7F)) {
  761. target.replaceSelection(content);
  762. }
  763. }
  764. }
  765. }
  766. }
  767. /**
  768. * Places content into the associated document.
  769. * If there is a selection, it is removed before
  770. * the new content is added.
  771. * <p>
  772. * <strong>Warning:</strong>
  773. * Serialized objects of this class will not be compatible with
  774. * future Swing releases. The current serialization support is
  775. * appropriate for short term storage or RMI between applications running
  776. * the same version of Swing. As of 1.4, support for long term storage
  777. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  778. * has been added to the <code>java.beans</code> package.
  779. * Please see {@link java.beans.XMLEncoder}.
  780. *
  781. * @see DefaultEditorKit#insertContentAction
  782. * @see DefaultEditorKit#getActions
  783. */
  784. public static class InsertContentAction extends TextAction {
  785. /**
  786. * Creates this object with the appropriate identifier.
  787. */
  788. public InsertContentAction() {
  789. super(insertContentAction);
  790. }
  791. /**
  792. * The operation to perform when this action is triggered.
  793. *
  794. * @param e the action event
  795. */
  796. public void actionPerformed(ActionEvent e) {
  797. JTextComponent target = getTextComponent(e);
  798. if ((target != null) && (e != null)) {
  799. if ((! target.isEditable()) || (! target.isEnabled())) {
  800. UIManager.getLookAndFeel().provideErrorFeedback(target);
  801. return;
  802. }
  803. String content = e.getActionCommand();
  804. if (content != null) {
  805. target.replaceSelection(content);
  806. } else {
  807. UIManager.getLookAndFeel().provideErrorFeedback(target);
  808. }
  809. }
  810. }
  811. }
  812. /**
  813. * Places a line/paragraph break into the document.
  814. * If there is a selection, it is removed before
  815. * the break is added.
  816. * <p>
  817. * <strong>Warning:</strong>
  818. * Serialized objects of this class will not be compatible with
  819. * future Swing releases. The current serialization support is
  820. * appropriate for short term storage or RMI between applications running
  821. * the same version of Swing. As of 1.4, support for long term storage
  822. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  823. * has been added to the <code>java.beans</code> package.
  824. * Please see {@link java.beans.XMLEncoder}.
  825. *
  826. * @see DefaultEditorKit#insertBreakAction
  827. * @see DefaultEditorKit#getActions
  828. */
  829. public static class InsertBreakAction extends TextAction {
  830. /**
  831. * Creates this object with the appropriate identifier.
  832. */
  833. public InsertBreakAction() {
  834. super(insertBreakAction);
  835. }
  836. /**
  837. * The operation to perform when this action is triggered.
  838. *
  839. * @param e the action event
  840. */
  841. public void actionPerformed(ActionEvent e) {
  842. JTextComponent target = getTextComponent(e);
  843. if (target != null) {
  844. if ((! target.isEditable()) || (! target.isEnabled())) {
  845. UIManager.getLookAndFeel().provideErrorFeedback(target);
  846. return;
  847. }
  848. target.replaceSelection("\n");
  849. }
  850. }
  851. }
  852. /**
  853. * Places a tab character into the document. If there
  854. * is a selection, it is removed before the tab is added.
  855. * <p>
  856. * <strong>Warning:</strong>
  857. * Serialized objects of this class will not be compatible with
  858. * future Swing releases. The current serialization support is
  859. * appropriate for short term storage or RMI between applications running
  860. * the same version of Swing. As of 1.4, support for long term storage
  861. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  862. * has been added to the <code>java.beans</code> package.
  863. * Please see {@link java.beans.XMLEncoder}.
  864. *
  865. * @see DefaultEditorKit#insertTabAction
  866. * @see DefaultEditorKit#getActions
  867. */
  868. public static class InsertTabAction extends TextAction {
  869. /**
  870. * Creates this object with the appropriate identifier.
  871. */
  872. public InsertTabAction() {
  873. super(insertTabAction);
  874. }
  875. /**
  876. * The operation to perform when this action is triggered.
  877. *
  878. * @param e the action event
  879. */
  880. public void actionPerformed(ActionEvent e) {
  881. JTextComponent target = getTextComponent(e);
  882. if (target != null) {
  883. if ((! target.isEditable()) || (! target.isEnabled())) {
  884. UIManager.getLookAndFeel().provideErrorFeedback(target);
  885. return;
  886. }
  887. target.replaceSelection("\t");
  888. }
  889. }
  890. }
  891. /*
  892. * Deletes the character of content that precedes the
  893. * current caret position.
  894. * @see DefaultEditorKit#deletePrevCharAction
  895. * @see DefaultEditorKit#getActions
  896. */
  897. static class DeletePrevCharAction extends TextAction {
  898. /**
  899. * Creates this object with the appropriate identifier.
  900. */
  901. DeletePrevCharAction() {
  902. super(deletePrevCharAction);
  903. }
  904. /**
  905. * The operation to perform when this action is triggered.
  906. *
  907. * @param e the action event
  908. */
  909. public void actionPerformed(ActionEvent e) {
  910. JTextComponent target = getTextComponent(e);
  911. boolean beep = true;
  912. if ((target != null) && (target.isEditable())) {
  913. try {
  914. Document doc = target.getDocument();
  915. Caret caret = target.getCaret();
  916. int dot = caret.getDot();
  917. int mark = caret.getMark();
  918. if (dot != mark) {
  919. doc.remove(Math.min(dot, mark), Math.abs(dot - mark));
  920. beep = false;
  921. } else if (dot > 0) {
  922. int delChars = 1;
  923. if (dot > 1) {
  924. String dotChars = doc.getText(dot - 2, 2);
  925. char c0 = dotChars.charAt(0);
  926. char c1 = dotChars.charAt(1);
  927. if (c0 >= '\uD800' && c0 <= '\uDBFF' &&
  928. c1 >= '\uDC00' && c1 <= '\uDFFF') {
  929. delChars = 2;
  930. }
  931. }
  932. doc.remove(dot - delChars, delChars);
  933. beep = false;
  934. }
  935. } catch (BadLocationException bl) {
  936. }
  937. }
  938. if (beep) {
  939. UIManager.getLookAndFeel().provideErrorFeedback(target);
  940. }
  941. }
  942. }
  943. /*
  944. * Deletes the character of content that follows the
  945. * current caret position.
  946. * @see DefaultEditorKit#deleteNextCharAction
  947. * @see DefaultEditorKit#getActions
  948. */
  949. static class DeleteNextCharAction extends TextAction {
  950. /* Create this object with the appropriate identifier. */
  951. DeleteNextCharAction() {
  952. super(deleteNextCharAction);
  953. }
  954. /** The operation to perform when this action is triggered. */
  955. public void actionPerformed(ActionEvent e) {
  956. JTextComponent target = getTextComponent(e);
  957. boolean beep = true;
  958. if ((target != null) && (target.isEditable())) {
  959. try {
  960. Document doc = target.getDocument();
  961. Caret caret = target.getCaret();
  962. int dot = caret.getDot();
  963. int mark = caret.getMark();
  964. if (dot != mark) {
  965. doc.remove(Math.min(dot, mark), Math.abs(dot - mark));
  966. beep = false;
  967. } else if (dot < doc.getLength()) {
  968. int delChars = 1;
  969. if (dot < doc.getLength() - 1) {
  970. String dotChars = doc.getText(dot, 2);
  971. char c0 = dotChars.charAt(0);
  972. char c1 = dotChars.charAt(1);
  973. if (c0 >= '\uD800' && c0 <= '\uDBFF' &&
  974. c1 >= '\uDC00' && c1 <= '\uDFFF') {
  975. delChars = 2;
  976. }
  977. }
  978. doc.remove(dot, delChars);
  979. beep = false;
  980. }
  981. } catch (BadLocationException bl) {
  982. }
  983. }
  984. if (beep) {
  985. UIManager.getLookAndFeel().provideErrorFeedback(target);
  986. }
  987. }
  988. }
  989. /*
  990. * Sets the editor into read-only mode.
  991. * @see DefaultEditorKit#readOnlyAction
  992. * @see DefaultEditorKit#getActions
  993. */
  994. static class ReadOnlyAction extends TextAction {
  995. /* Create this object with the appropriate identifier. */
  996. ReadOnlyAction() {
  997. super(readOnlyAction);
  998. }
  999. /**
  1000. * The operation to perform when this action is triggered.
  1001. *
  1002. * @param e the action event
  1003. */
  1004. public void actionPerformed(ActionEvent e) {
  1005. JTextComponent target = getTextComponent(e);
  1006. if (target != null) {
  1007. target.setEditable(false);
  1008. }
  1009. }
  1010. }
  1011. /*
  1012. * Sets the editor into writeable mode.
  1013. * @see DefaultEditorKit#writableAction
  1014. * @see DefaultEditorKit#getActions
  1015. */
  1016. static class WritableAction extends TextAction {
  1017. /* Create this object with the appropriate identifier. */
  1018. WritableAction() {
  1019. super(writableAction);
  1020. }
  1021. /**
  1022. * The operation to perform when this action is triggered.
  1023. *
  1024. * @param e the action event
  1025. */
  1026. public void actionPerformed(ActionEvent e) {
  1027. JTextComponent target = getTextComponent(e);
  1028. if (target != null) {
  1029. target.setEditable(true);
  1030. }
  1031. }
  1032. }
  1033. /**
  1034. * Cuts the selected region and place its contents
  1035. * into the system clipboard.
  1036. * <p>
  1037. * <strong>Warning:</strong>
  1038. * Serialized objects of this class will not be compatible with
  1039. * future Swing releases. The current serialization support is
  1040. * appropriate for short term storage or RMI between applications running
  1041. * the same version of Swing. As of 1.4, support for long term storage
  1042. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  1043. * has been added to the <code>java.beans</code> package.
  1044. * Please see {@link java.beans.XMLEncoder}.
  1045. *
  1046. * @see DefaultEditorKit#cutAction
  1047. * @see DefaultEditorKit#getActions
  1048. */
  1049. public static class CutAction extends TextAction {
  1050. /** Create this object with the appropriate identifier. */
  1051. public CutAction() {
  1052. super(cutAction);
  1053. }
  1054. /**
  1055. * The operation to perform when this action is triggered.
  1056. *
  1057. * @param e the action event
  1058. */
  1059. public void actionPerformed(ActionEvent e) {
  1060. JTextComponent target = getTextComponent(e);
  1061. if (target != null) {
  1062. target.cut();
  1063. }
  1064. }
  1065. }
  1066. /**
  1067. * Copies the selected region and place its contents
  1068. * into the system clipboard.
  1069. * <p>
  1070. * <strong>Warning:</strong>
  1071. * Serialized objects of this class will not be compatible with
  1072. * future Swing releases. The current serialization support is
  1073. * appropriate for short term storage or RMI between applications running
  1074. * the same version of Swing. As of 1.4, support for long term storage
  1075. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  1076. * has been added to the <code>java.beans</code> package.
  1077. * Please see {@link java.beans.XMLEncoder}.
  1078. *
  1079. * @see DefaultEditorKit#copyAction
  1080. * @see DefaultEditorKit#getActions
  1081. */
  1082. public static class CopyAction extends TextAction {
  1083. /** Create this object with the appropriate identifier. */
  1084. public CopyAction() {
  1085. super(copyAction);
  1086. }
  1087. /**
  1088. * The operation to perform when this action is triggered.
  1089. *
  1090. * @param e the action event
  1091. */
  1092. public void actionPerformed(ActionEvent e) {
  1093. JTextComponent target = getTextComponent(e);
  1094. if (target != null) {
  1095. target.copy();
  1096. }
  1097. }
  1098. }
  1099. /**
  1100. * Pastes the contents of the system clipboard into the
  1101. * selected region, or before the caret if nothing is
  1102. * selected.
  1103. * <p>
  1104. * <strong>Warning:</strong>
  1105. * Serialized objects of this class will not be compatible with
  1106. * future Swing releases. The current serialization support is
  1107. * appropriate for short term storage or RMI between applications running
  1108. * the same version of Swing. As of 1.4, support for long term storage
  1109. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  1110. * has been added to the <code>java.beans</code> package.
  1111. * Please see {@link java.beans.XMLEncoder}.
  1112. *
  1113. * @see DefaultEditorKit#pasteAction
  1114. * @see DefaultEditorKit#getActions
  1115. */
  1116. public static class PasteAction extends TextAction {
  1117. /** Create this object with the appropriate identifier. */
  1118. public PasteAction() {
  1119. super(pasteAction);
  1120. }
  1121. /**
  1122. * The operation to perform when this action is triggered.
  1123. *
  1124. * @param e the action event
  1125. */
  1126. public void actionPerformed(ActionEvent e) {
  1127. JTextComponent target = getTextComponent(e);
  1128. if (target != null) {
  1129. target.paste();
  1130. }
  1131. }
  1132. }
  1133. /**
  1134. * Creates a beep.
  1135. * <p>
  1136. * <strong>Warning:</strong>
  1137. * Serialized objects of this class will not be compatible with
  1138. * future Swing releases. The current serialization support is
  1139. * appropriate for short term storage or RMI between applications running
  1140. * the same version of Swing. As of 1.4, support for long term storage
  1141. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  1142. * has been added to the <code>java.beans</code> package.
  1143. * Please see {@link java.beans.XMLEncoder}.
  1144. *
  1145. * @see DefaultEditorKit#beepAction
  1146. * @see DefaultEditorKit#getActions
  1147. */
  1148. public static class BeepAction extends TextAction {
  1149. /** Create this object with the appropriate identifier. */
  1150. public BeepAction() {
  1151. super(beepAction);
  1152. }
  1153. /**
  1154. * The operation to perform when this action is triggered.
  1155. *
  1156. * @param e the action event
  1157. */
  1158. public void actionPerformed(ActionEvent e) {
  1159. JTextComponent target = getTextComponent(e);
  1160. UIManager.getLookAndFeel().provideErrorFeedback(target);
  1161. }
  1162. }
  1163. /**
  1164. * Scrolls up/down vertically. The select version of this action extends
  1165. * the selection, instead of simply moving the caret.
  1166. *
  1167. * @see DefaultEditorKit#pageUpAction
  1168. * @see DefaultEditorKit#selectPageUpAction
  1169. * @see DefaultEditorKit#getActions
  1170. */
  1171. static class VerticalPageAction extends TextAction {
  1172. /** Create this object with the appropriate identifier. */
  1173. public VerticalPageAction(String nm, int direction, boolean select) {
  1174. super(nm);
  1175. this.select = select;
  1176. this.direction = direction;
  1177. }
  1178. /** The operation to perform when this action is triggered. */
  1179. public void actionPerformed(ActionEvent e) {
  1180. JTextComponent target = getTextComponent(e);
  1181. if (target != null) {
  1182. Rectangle visible = target.getVisibleRect();
  1183. Rectangle newVis = new Rectangle(visible);
  1184. int selectedIndex = target.getCaretPosition();
  1185. int scrollAmount = target.getScrollableBlockIncrement(
  1186. visible, SwingConstants.VERTICAL, direction);
  1187. int initialY = visible.y;
  1188. Caret caret = target.getCaret();
  1189. Point magicPosition = caret.getMagicCaretPosition();
  1190. int yOffset;
  1191. if (selectedIndex != -1) {
  1192. try {
  1193. Rectangle dotBounds = target.modelToView(
  1194. selectedIndex);
  1195. int x = (magicPosition != null) ? magicPosition.x :
  1196. dotBounds.x;
  1197. // fix for 4697612
  1198. int h = dotBounds.height;
  1199. yOffset = direction *
  1200. (int)Math.ceil(scrollAmount / (double)h) * h;
  1201. newVis.y = constrainY(target, initialY + yOffset, yOffset);
  1202. int newIndex;
  1203. if (visible.contains(dotBounds.x, dotBounds.y)) {
  1204. // Dot is currently visible, base the new
  1205. // location off the old, or
  1206. newIndex = target.viewToModel(
  1207. new Point(x, constrainY(target,
  1208. dotBounds.y + yOffset, 0)));
  1209. }
  1210. else {
  1211. // Dot isn't visible, choose the top or the bottom
  1212. // for the new location.
  1213. if (direction == -1) {
  1214. newIndex = target.viewToModel(new Point(
  1215. x, newVis.y));
  1216. }
  1217. else {
  1218. newIndex = target.viewToModel(new Point(
  1219. x, newVis.y + visible.height));
  1220. }
  1221. }
  1222. newIndex = constrainOffset(target, newIndex);
  1223. if (newIndex != selectedIndex) {
  1224. // Make sure the new visible location contains
  1225. // the location of dot, otherwise Caret will
  1226. // cause an additional scroll.
  1227. adjustScrollIfNecessary(target, newVis, initialY,
  1228. newIndex);
  1229. if (select) {
  1230. target.moveCaretPosition(newIndex);
  1231. }
  1232. else {
  1233. target.setCaretPosition(newIndex);
  1234. }
  1235. }
  1236. } catch (BadLocationException ble) { }
  1237. } else {
  1238. yOffset = direction * scrollAmount;
  1239. newVis.y = constrainY(target, initialY + yOffset, yOffset);
  1240. }
  1241. if (magicPosition != null) {
  1242. caret.setMagicCaretPosition(magicPosition);
  1243. }
  1244. target.scrollRectToVisible(newVis);
  1245. }
  1246. }
  1247. /**
  1248. * Makes sure <code>y</code> is a valid location in
  1249. * <code>target</code>.
  1250. */
  1251. private int constrainY(JTextComponent target, int y, int vis) {
  1252. if (y < 0) {
  1253. y = 0;
  1254. }
  1255. else if (y + vis > target.getHeight()) {
  1256. y = Math.max(0, target.getHeight() - vis);
  1257. }
  1258. return y;
  1259. }
  1260. /**
  1261. * Ensures that <code>offset</code> is a valid offset into the
  1262. * model for <code>text</code>.
  1263. */
  1264. private int constrainOffset(JTextComponent text, int offset) {
  1265. Document doc = text.getDocument();
  1266. if ((offset != 0) && (offset > doc.getLength())) {
  1267. offset = doc.getLength();
  1268. }
  1269. if (offset < 0) {
  1270. offset = 0;
  1271. }
  1272. return offset;
  1273. }
  1274. /**
  1275. * Adjusts the rectangle that indicates the location to scroll to
  1276. * after selecting <code>index</code>.
  1277. */
  1278. private void adjustScrollIfNecessary(JTextComponent text,
  1279. Rectangle visible, int initialY,
  1280. int index) {
  1281. try {
  1282. Rectangle dotBounds = text.modelToView(index);
  1283. if (dotBounds.y < visible.y ||
  1284. (dotBounds.y > (visible.y + visible.height)) ||
  1285. (dotBounds.y + dotBounds.height) >
  1286. (visible.y + visible.height)) {
  1287. int y;
  1288. if (dotBounds.y < visible.y) {
  1289. y = dotBounds.y;
  1290. }
  1291. else {
  1292. y = dotBounds.y + dotBounds.height - visible.height;
  1293. }
  1294. if ((direction == -1 && y < initialY) ||
  1295. (direction == 1 && y > initialY)) {
  1296. // Only adjust if won't cause scrolling upward.
  1297. visible.y = y;
  1298. }
  1299. }
  1300. } catch (BadLocationException ble) {}
  1301. }
  1302. /**
  1303. * Adjusts the Rectangle to contain the bounds of the character at
  1304. * <code>index</code> in response to a page up.
  1305. */
  1306. private boolean select;
  1307. /**
  1308. * Direction to scroll, 1 is down, -1 is up.
  1309. */
  1310. private int direction;
  1311. }
  1312. /**
  1313. * Pages one view to the left or right.
  1314. */
  1315. static class PageAction extends TextAction {
  1316. /** Create this object with the appropriate identifier. */
  1317. public PageAction(String nm, boolean left, boolean select) {
  1318. super(nm);
  1319. this.select = select;
  1320. this.left = left;
  1321. }
  1322. /** The operation to perform when this action is triggered. */
  1323. public void actionPerformed(ActionEvent e) {
  1324. JTextComponent target = getTextComponent(e);
  1325. if (target != null) {
  1326. int selectedIndex;
  1327. Rectangle visible = new Rectangle();
  1328. target.computeVisibleRect(visible);
  1329. if (left) {
  1330. visible.x = Math.max(0, visible.x - visible.width);
  1331. }
  1332. else {
  1333. visible.x += visible.width;
  1334. }
  1335. selectedIndex = target.getCaretPosition();
  1336. if(selectedIndex != -1) {
  1337. if (left) {
  1338. selectedIndex = target.viewToModel
  1339. (new Point(visible.x, visible.y));
  1340. }
  1341. else {
  1342. selectedIndex = target.viewToModel
  1343. (new Point(visible.x + visible.width - 1,
  1344. visible.y + visible.height - 1));
  1345. }
  1346. Document doc = target.getDocument();
  1347. if ((selectedIndex != 0) &&
  1348. (selectedIndex > (doc.getLength()-1))) {
  1349. selectedIndex = doc.getLength()-1;
  1350. }
  1351. else if(selectedIndex < 0) {
  1352. selectedIndex = 0;
  1353. }
  1354. if (select)
  1355. target.moveCaretPosition(selectedIndex);
  1356. else
  1357. target.setCaretPosition(selectedIndex);
  1358. }
  1359. }
  1360. }
  1361. private boolean select;
  1362. private boolean left;
  1363. }
  1364. static class DumpModelAction extends TextAction {
  1365. DumpModelAction() {
  1366. super("dump-model");
  1367. }
  1368. public void actionPerformed(ActionEvent e) {
  1369. JTextComponent target = getTextComponent(e);
  1370. if (target != null) {
  1371. Document d = target.getDocument();
  1372. if (d instanceof AbstractDocument) {
  1373. ((AbstractDocument) d).dump(System.err);
  1374. }
  1375. }
  1376. }
  1377. }
  1378. /*
  1379. * Action to move the selection by way of the
  1380. * getNextVisualPositionFrom method. Constructor indicates direction
  1381. * to use.
  1382. */
  1383. static class NextVisualPositionAction extends TextAction {
  1384. /**
  1385. * Create this action with the appropriate identifier.
  1386. * @param nm the name of the action, Action.NAME.
  1387. * @param select whether to extend the selection when
  1388. * changing the caret position.
  1389. */
  1390. NextVisualPositionAction(String nm, boolean select, int direction) {
  1391. super(nm);
  1392. this.select = select;
  1393. this.direction = direction;
  1394. }
  1395. /** The operation to perform when this action is triggered. */
  1396. public void actionPerformed(ActionEvent e) {
  1397. JTextComponent target = getTextComponent(e);
  1398. if (target != null) {
  1399. Caret caret = target.getCaret();
  1400. DefaultCaret bidiCaret = (caret instanceof DefaultCaret) ?
  1401. (DefaultCaret)caret : null;
  1402. int dot = caret.getDot();
  1403. Position.Bias[] bias = new Position.Bias[1];
  1404. Point magicPosition = caret.getMagicCaretPosition();
  1405. try {
  1406. if(magicPosition == null &&
  1407. (direction == SwingConstants.NORTH ||
  1408. direction == SwingConstants.SOUTH)) {
  1409. Rectangle r = (bidiCaret != null) ?
  1410. target.getUI().modelToView(target, dot,
  1411. bidiCaret.getDotBias()) :
  1412. target.modelToView(dot);
  1413. magicPosition = new Point(r.x, r.y);
  1414. }
  1415. NavigationFilter filter = target.getNavigationFilter();
  1416. if (filter != null) {
  1417. dot = filter.getNextVisualPositionFrom
  1418. (target, dot, (bidiCaret != null) ?
  1419. bidiCaret.getDotBias() :
  1420. Position.Bias.Forward, direction, bias);
  1421. }
  1422. else {
  1423. dot = target.getUI().getNextVisualPositionFrom
  1424. (target, dot, (bidiCaret != null) ?
  1425. bidiCaret.getDotBias() :
  1426. Position.Bias.Forward, direction, bias);
  1427. }
  1428. if(bias[0] == null) {
  1429. bias[0] = Position.Bias.Forward;
  1430. }
  1431. if(bidiCaret != null) {
  1432. if (select) {
  1433. bidiCaret.moveDot(dot, bias[0]);
  1434. } else {
  1435. bidiCaret.setDot(dot, bias[0]);
  1436. }
  1437. }
  1438. else {
  1439. if (select) {
  1440. caret.moveDot(dot);
  1441. } else {
  1442. caret.setDot(dot);
  1443. }
  1444. }
  1445. if(magicPosition != null &&
  1446. (direction == SwingConstants.NORTH ||
  1447. direction == SwingConstants.SOUTH)) {
  1448. target.getCaret().setMagicCaretPosition(magicPosition);
  1449. }
  1450. } catch (BadLocationException ex) {
  1451. }
  1452. }
  1453. }
  1454. private boolean select;
  1455. private int direction;
  1456. }
  1457. /*
  1458. * Position the caret to the beginning of the word.
  1459. * @see DefaultEditorKit#beginWordAction
  1460. * @see DefaultEditorKit#selectBeginWordAction
  1461. * @see DefaultEditorKit#getActions
  1462. */
  1463. static class BeginWordAction extends TextAction {
  1464. /**
  1465. * Create this action with the appropriate identifier.
  1466. * @param nm the name of the action, Action.NAME.
  1467. * @param select whether to extend the selection when
  1468. * changing the caret position.
  1469. */
  1470. BeginWordAction(String nm, boolean select) {
  1471. super(nm);
  1472. this.select = select;
  1473. }
  1474. /** The operation to perform when this action is triggered. */
  1475. public void actionPerformed(ActionEvent e) {
  1476. JTextComponent target = getTextComponent(e);
  1477. if (target != null) {
  1478. try {
  1479. int offs = target.getCaretPosition();
  1480. int begOffs = Utilities.getWordStart(target, offs);
  1481. if (select) {
  1482. target.moveCaretPosition(begOffs);
  1483. } else {
  1484. target.setCaretPosition(begOffs);
  1485. }
  1486. } catch (BadLocationException bl) {
  1487. UIManager.getLookAndFeel().provideErrorFeedback(target);
  1488. }
  1489. }
  1490. }
  1491. private boolean select;
  1492. }
  1493. /*
  1494. * Position the caret to the end of the word.
  1495. * @see DefaultEditorKit#endWordAction
  1496. * @see DefaultEditorKit#selectEndWordAction
  1497. * @see DefaultEditorKit#getActions
  1498. */
  1499. static class EndWordAction extends TextAction {
  1500. /**
  1501. * Create this action with the appropriate identifier.
  1502. * @param nm the name of the action, Action.NAME.
  1503. * @param select whether to extend the selection when
  1504. * changing the caret position.
  1505. */
  1506. EndWordAction(String nm, boolean select) {
  1507. super(nm);
  1508. this.select = select;
  1509. }
  1510. /** The operation to perform when this action is triggered. */
  1511. public void actionPerformed(ActionEvent e) {
  1512. JTextComponent target = getTextComponent(e);
  1513. if (target != null) {
  1514. try {
  1515. int offs = target.getCaretPosition();
  1516. int endOffs = Utilities.getWordEnd(target, offs);
  1517. if (select) {
  1518. target.moveCaretPosition(endOffs);
  1519. } else {
  1520. target.setCaretPosition(endOffs);
  1521. }
  1522. } catch (BadLocationException bl) {
  1523. UIManager.getLookAndFeel().provideErrorFeedback(target);
  1524. }
  1525. }
  1526. }
  1527. private boolean select;
  1528. }
  1529. /*
  1530. * Position the caret to the beginning of the previous word.
  1531. * @see DefaultEditorKit#previousWordAction
  1532. * @see DefaultEditorKit#selectPreviousWordAction
  1533. * @see DefaultEditorKit#getActions
  1534. */
  1535. static class PreviousWordAction extends TextAction {
  1536. /**
  1537. * Create this action with the appropriate identifier.
  1538. * @param nm the name of the action, Action.NAME.
  1539. * @param select whether to extend the selection when
  1540. * changing the caret position.
  1541. */
  1542. PreviousWordAction(String nm, boolean select) {
  1543. super(nm);
  1544. this.select = select;
  1545. }
  1546. /** The operation to perform when this action is triggered. */
  1547. public void actionPerformed(ActionEvent e) {
  1548. JTextComponent target = getTextComponent(e);
  1549. if (target != null) {
  1550. int offs = target.getCaretPosition();
  1551. boolean failed = false;
  1552. try {
  1553. Element curPara =
  1554. Utilities.getParagraphElement(target, offs);
  1555. offs = Utilities.getPreviousWord(target, offs);
  1556. if(offs < curPara.getStartOffset()) {
  1557. // we should first move to the end of the
  1558. // previous paragraph (bug #4278839)
  1559. offs = Utilities.getParagraphElement(target, offs).
  1560. getEndOffset() - 1;
  1561. }
  1562. } catch (BadLocationException bl) {
  1563. if (offs != 0) {
  1564. offs = 0;
  1565. }
  1566. else {
  1567. failed = true;
  1568. }
  1569. }
  1570. if (!failed) {
  1571. if (select) {
  1572. target.moveCaretPosition(offs);
  1573. } else {
  1574. target.setCaretPosition(offs);
  1575. }
  1576. }
  1577. else {
  1578. UIManager.getLookAndFeel().provideErrorFeedback(target);
  1579. }
  1580. }
  1581. }
  1582. private boolean select;
  1583. }
  1584. /*
  1585. * Position the caret to the next of the word.
  1586. * @see DefaultEditorKit#nextWordAction
  1587. * @see DefaultEditorKit#selectNextWordAction
  1588. * @see DefaultEditorKit#getActions
  1589. */
  1590. static class NextWordAction extends TextAction {
  1591. /**
  1592. * Create this action with the appropriate identifier.
  1593. * @param nm the name of the action, Action.NAME.
  1594. * @param select whether to extend the selection when
  1595. * changing the caret position.
  1596. */
  1597. NextWordAction(String nm, boolean select) {
  1598. super(nm);
  1599. this.select = select;
  1600. }
  1601. /** The operation to perform when this action is triggered. */
  1602. public void actionPerformed(ActionEvent e) {
  1603. JTextComponent target = getTextComponent(e);
  1604. if (target != null) {
  1605. int offs = target.getCaretPosition();
  1606. boolean failed = false;
  1607. int oldOffs = offs;
  1608. Element curPara =
  1609. Utilities.getParagraphElement(target, offs);
  1610. try {
  1611. offs = Utilities.getNextWord(target, offs);
  1612. if(offs >= curPara.getEndOffset() &&
  1613. oldOffs != curPara.getEndOffset() - 1) {
  1614. // we should first move to the end of current
  1615. // paragraph (bug #4278839)
  1616. offs = curPara.getEndOffset() - 1;
  1617. }
  1618. } catch (BadLocationException bl) {
  1619. int end = target.getDocument().getLength();
  1620. if (offs != end) {
  1621. if(oldOffs != curPara.getEndOffset() - 1) {
  1622. offs = curPara.getEndOffset() - 1;
  1623. } else {
  1624. offs = end;
  1625. }
  1626. }
  1627. else {
  1628. failed = true;
  1629. }
  1630. }
  1631. if (!failed) {
  1632. if (select) {
  1633. target.moveCaretPosition(offs);
  1634. } else {
  1635. target.setCaretPosition(offs);
  1636. }
  1637. }
  1638. else {
  1639. UIManager.getLookAndFeel().provideErrorFeedback(target);
  1640. }
  1641. }
  1642. }
  1643. private boolean select;
  1644. }
  1645. /*
  1646. * Position the caret to the beginning of the line.
  1647. * @see DefaultEditorKit#beginLineAction
  1648. * @see DefaultEditorKit#selectBeginLineAction
  1649. * @see DefaultEditorKit#getActions
  1650. */
  1651. static class BeginLineAction extends TextAction {
  1652. /**
  1653. * Create this action with the appropriate identifier.
  1654. * @param nm the name of the action, Action.NAME.
  1655. * @param select whether to extend the selection when
  1656. * changing the caret position.
  1657. */
  1658. BeginLineAction(String nm, boolean select) {
  1659. super(nm);
  1660. this.select = select;
  1661. }
  1662. /** The operation to perform when this action is triggered. */
  1663. public void actionPerformed(ActionEvent e) {
  1664. JTextComponent target = getTextComponent(e);
  1665. if (target != null) {
  1666. try {
  1667. int offs = target.getCaretPosition();
  1668. int begOffs = Utilities.getRowStart(target, offs);
  1669. if (select) {
  1670. target.moveCaretPosition(begOffs);
  1671. } else {
  1672. target.setCaretPosition(begOffs);
  1673. }
  1674. } catch (BadLocationException bl) {
  1675. UIManager.getLookAndFeel().provideErrorFeedback(target);
  1676. }
  1677. }
  1678. }
  1679. private boolean select;
  1680. }
  1681. /*
  1682. * Position the caret to the end of the line.
  1683. * @see DefaultEditorKit#endLineAction
  1684. * @see DefaultEditorKit#selectEndLineAction
  1685. * @see DefaultEditorKit#getActions
  1686. */
  1687. static class EndLineAction extends TextAction {
  1688. /**
  1689. * Create this action with the appropriate identifier.
  1690. * @param nm the name of the action, Action.NAME.
  1691. * @param select whether to extend the selection when
  1692. * changing the caret position.
  1693. */
  1694. EndLineAction(String nm, boolean select) {
  1695. super(nm);
  1696. this.select = select;
  1697. }
  1698. /** The operation to perform when this action is triggered. */
  1699. public void actionPerformed(ActionEvent e) {
  1700. JTextComponent target = getTextComponent(e);
  1701. if (target != null) {
  1702. try {
  1703. int offs = target.getCaretPosition();
  1704. int endOffs = Utilities.getRowEnd(target, offs);
  1705. if (select) {
  1706. target.moveCaretPosition(endOffs);
  1707. } else {
  1708. target.setCaretPosition(endOffs);
  1709. }
  1710. } catch (BadLocationException bl) {
  1711. UIManager.getLookAndFeel().provideErrorFeedback(target);
  1712. }
  1713. }
  1714. }
  1715. private boolean select;
  1716. }
  1717. /*
  1718. * Position the caret to the beginning of the paragraph.
  1719. * @see DefaultEditorKit#beginParagraphAction
  1720. * @see DefaultEditorKit#selectBeginParagraphAction
  1721. * @see DefaultEditorKit#getActions
  1722. */
  1723. static class BeginParagraphAction extends TextAction {
  1724. /**
  1725. * Create this action with the appropriate identifier.
  1726. * @param nm the name of the action, Action.NAME.
  1727. * @param select whether to extend the selection when
  1728. * changing the caret position.
  1729. */
  1730. BeginParagraphAction(String nm, boolean select) {
  1731. super(nm);
  1732. this.select = select;
  1733. }
  1734. /** The operation to perform when this action is triggered. */
  1735. public void actionPerformed(ActionEvent e) {
  1736. JTextComponent target = getTextComponent(e);
  1737. if (target != null) {
  1738. int offs = target.getCaretPosition();
  1739. Element elem = Utilities.getParagraphElement(target, offs);
  1740. offs = elem.getStartOffset();
  1741. if (select) {
  1742. target.moveCaretPosition(offs);
  1743. } else {
  1744. target.setCaretPosition(offs);
  1745. }
  1746. }
  1747. }
  1748. private boolean select;
  1749. }
  1750. /*
  1751. * Position the caret to the end of the paragraph.
  1752. * @see DefaultEditorKit#endParagraphAction
  1753. * @see DefaultEditorKit#selectEndParagraphAction
  1754. * @see DefaultEditorKit#getActions
  1755. */
  1756. static class EndParagraphAction extends TextAction {
  1757. /**
  1758. * Create this action with the appropriate identifier.
  1759. * @param nm the name of the action, Action.NAME.
  1760. * @param select whether to extend the selection when
  1761. * changing the caret position.
  1762. */
  1763. EndParagraphAction(String nm, boolean select) {
  1764. super(nm);
  1765. this.select = select;
  1766. }
  1767. /** The operation to perform when this action is triggered. */
  1768. public void actionPerformed(ActionEvent e) {
  1769. JTextComponent target = getTextComponent(e);
  1770. if (target != null) {
  1771. int offs = target.getCaretPosition();
  1772. Element elem = Utilities.getParagraphElement(target, offs);
  1773. offs = Math.min(target.getDocument().getLength(),
  1774. elem.getEndOffset());
  1775. if (select) {
  1776. target.moveCaretPosition(offs);
  1777. } else {
  1778. target.setCaretPosition(offs);
  1779. }
  1780. }
  1781. }
  1782. private boolean select;
  1783. }
  1784. /*
  1785. * Move the caret to the beginning of the document.
  1786. * @see DefaultEditorKit#beginAction
  1787. * @see DefaultEditorKit#getActions
  1788. */
  1789. static class BeginAction extends TextAction {
  1790. /* Create this object with the appropriate identifier. */
  1791. BeginAction(String nm, boolean select) {
  1792. super(nm);
  1793. this.select = select;
  1794. }
  1795. /** The operation to perform when this action is triggered. */
  1796. public void actionPerformed(ActionEvent e) {
  1797. JTextComponent target = getTextComponent(e);
  1798. if (target != null) {
  1799. if (select) {
  1800. target.moveCaretPosition(0);
  1801. } else {
  1802. target.setCaretPosition(0);
  1803. }
  1804. }
  1805. }
  1806. private boolean select;
  1807. }
  1808. /*
  1809. * Move the caret to the end of the document.
  1810. * @see DefaultEditorKit#endAction
  1811. * @see DefaultEditorKit#getActions
  1812. */
  1813. static class EndAction extends TextAction {
  1814. /* Create this object with the appropriate identifier. */
  1815. EndAction(String nm, boolean select) {
  1816. super(nm);
  1817. this.select = select;
  1818. }
  1819. /** The operation to perform when this action is triggered. */
  1820. public void actionPerformed(ActionEvent e) {
  1821. JTextComponent target = getTextComponent(e);
  1822. if (target != null) {
  1823. Document doc = target.getDocument();
  1824. int dot = doc.getLength();
  1825. if (select) {
  1826. target.moveCaretPosition(dot);
  1827. } else {
  1828. target.setCaretPosition(dot);
  1829. }
  1830. }
  1831. }
  1832. private boolean select;
  1833. }
  1834. /*
  1835. * Select the word around the caret
  1836. * @see DefaultEditorKit#endAction
  1837. * @see DefaultEditorKit#getActions
  1838. */
  1839. static class SelectWordAction extends TextAction {
  1840. /**
  1841. * Create this action with the appropriate identifier.
  1842. * @param nm the name of the action, Action.NAME.
  1843. * @param select whether to extend the selection when
  1844. * changing the caret position.
  1845. */
  1846. SelectWordAction() {
  1847. super(selectWordAction);
  1848. start = new BeginWordAction("pigdog", false);
  1849. end = new EndWordAction("pigdog", true);
  1850. }
  1851. /** The operation to perform when this action is triggered. */
  1852. public void actionPerformed(ActionEvent e) {
  1853. start.actionPerformed(e);
  1854. end.actionPerformed(e);
  1855. }
  1856. private Action start;
  1857. private Action end;
  1858. }
  1859. /*
  1860. * Select the line around the caret
  1861. * @see DefaultEditorKit#endAction
  1862. * @see DefaultEditorKit#getActions
  1863. */
  1864. static class SelectLineAction extends TextAction {
  1865. /**
  1866. * Create this action with the appropriate identifier.
  1867. * @param nm the name of the action, Action.NAME.
  1868. * @param select whether to extend the selection when
  1869. * changing the caret position.
  1870. */
  1871. SelectLineAction() {
  1872. super(selectLineAction);
  1873. start = new BeginLineAction("pigdog", false);
  1874. end = new EndLineAction("pigdog", true);
  1875. }
  1876. /** The operation to perform when this action is triggered. */
  1877. public void actionPerformed(ActionEvent e) {
  1878. start.actionPerformed(e);
  1879. end.actionPerformed(e);
  1880. }
  1881. private Action start;
  1882. private Action end;
  1883. }
  1884. /*
  1885. * Select the paragraph around the caret
  1886. * @see DefaultEditorKit#endAction
  1887. * @see DefaultEditorKit#getActions
  1888. */
  1889. static class SelectParagraphAction extends TextAction {
  1890. /**
  1891. * Create this action with the appropriate identifier.
  1892. * @param nm the name of the action, Action.NAME.
  1893. * @param select whether to extend the selection when
  1894. * changing the caret position.
  1895. */
  1896. SelectParagraphAction() {
  1897. super(selectParagraphAction);
  1898. start = new BeginParagraphAction("pigdog", false);
  1899. end = new EndParagraphAction("pigdog", true);
  1900. }
  1901. /** The operation to perform when this action is triggered. */
  1902. public void actionPerformed(ActionEvent e) {
  1903. start.actionPerformed(e);
  1904. end.actionPerformed(e);
  1905. }
  1906. private Action start;
  1907. private Action end;
  1908. }
  1909. /*
  1910. * Select the entire document
  1911. * @see DefaultEditorKit#endAction
  1912. * @see DefaultEditorKit#getActions
  1913. */
  1914. static class SelectAllAction extends TextAction {
  1915. /**
  1916. * Create this action with the appropriate identifier.
  1917. * @param nm the name of the action, Action.NAME.
  1918. * @param select whether to extend the selection when
  1919. * changing the caret position.
  1920. */
  1921. SelectAllAction() {
  1922. super(selectAllAction);
  1923. }
  1924. /** The operation to perform when this action is triggered. */
  1925. public void actionPerformed(ActionEvent e) {
  1926. JTextComponent target = getTextComponent(e);
  1927. if (target != null) {
  1928. Document doc = target.getDocument();
  1929. target.setCaretPosition(0);
  1930. target.moveCaretPosition(doc.getLength());
  1931. }
  1932. }
  1933. }
  1934. /*
  1935. * Remove the selection, if any.
  1936. * @see DefaultEditorKit#unselectAction
  1937. * @see DefaultEditorKit#getActions
  1938. */
  1939. static class UnselectAction extends TextAction {
  1940. /**
  1941. * Create this action with the appropriate identifier.
  1942. */
  1943. UnselectAction() {
  1944. super(unselectAction);
  1945. }
  1946. /** The operation to perform when this action is triggered. */
  1947. public void actionPerformed(ActionEvent e) {
  1948. JTextComponent target = getTextComponent(e);
  1949. if (target != null) {
  1950. target.setCaretPosition(target.getCaretPosition());
  1951. }
  1952. }
  1953. }
  1954. /*
  1955. * Toggles the ComponentOrientation of the text component.
  1956. * @see DefaultEditorKit#toggleComponentOrientationAction
  1957. * @see DefaultEditorKit#getActions
  1958. */
  1959. static class ToggleComponentOrientationAction extends TextAction {
  1960. /**
  1961. * Create this action with the appropriate identifier.
  1962. */
  1963. ToggleComponentOrientationAction() {
  1964. super(toggleComponentOrientationAction);
  1965. }
  1966. /** The operation to perform when this action is triggered. */
  1967. public void actionPerformed(ActionEvent e) {
  1968. JTextComponent target = getTextComponent(e);
  1969. if (target != null) {
  1970. ComponentOrientation last = target.getComponentOrientation();
  1971. ComponentOrientation next;
  1972. if( last == ComponentOrientation.RIGHT_TO_LEFT )
  1973. next = ComponentOrientation.LEFT_TO_RIGHT;
  1974. else
  1975. next = ComponentOrientation.RIGHT_TO_LEFT;
  1976. target.setComponentOrientation(next);
  1977. target.repaint();
  1978. }
  1979. }
  1980. }
  1981. }