wrap up TODOs
[fanfix.git] / src / jexer / TEditorWidget.java
CommitLineData
12b55d76
KL
1/*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
a69ed767 6 * Copyright (C) 2019 Kevin Lamonte
12b55d76
KL
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29package jexer;
30
71a389c9
KL
31import java.io.IOException;
32
12b55d76 33import jexer.bits.CellAttributes;
101bc589 34import jexer.event.TCommandEvent;
12b55d76
KL
35import jexer.event.TKeypressEvent;
36import jexer.event.TMouseEvent;
e8a11f98 37import jexer.event.TResizeEvent;
12b55d76
KL
38import jexer.teditor.Document;
39import jexer.teditor.Line;
40import jexer.teditor.Word;
101bc589 41import static jexer.TCommand.*;
12b55d76
KL
42import static jexer.TKeypress.*;
43
44/**
45 * TEditorWidget displays an editable text document. It is unaware of
46 * scrolling behavior, but can respond to mouse and keyboard events.
47 */
101bc589 48public class TEditorWidget extends TWidget implements EditMenuUser {
12b55d76 49
615a0d99
KL
50 // ------------------------------------------------------------------------
51 // Constants --------------------------------------------------------------
52 // ------------------------------------------------------------------------
53
b1a8acec
KL
54 /**
55 * The number of lines to scroll on mouse wheel up/down.
56 */
57 private static final int wheelScrollSize = 3;
58
615a0d99
KL
59 // ------------------------------------------------------------------------
60 // Variables --------------------------------------------------------------
61 // ------------------------------------------------------------------------
62
12b55d76
KL
63 /**
64 * The document being edited.
65 */
66 private Document document;
67
e8a11f98
KL
68 /**
69 * The default color for the TEditor class.
70 */
71 private CellAttributes defaultColor = null;
72
73 /**
74 * The topmost line number in the visible area. 0-based.
75 */
76 private int topLine = 0;
77
78 /**
79 * The leftmost column number in the visible area. 0-based.
80 */
81 private int leftColumn = 0;
82
101bc589
KL
83 /**
84 * If true, selection is a rectangle.
85 */
86 private boolean selectionRectangle = false;
87
88 /**
89 * If true, the mouse is dragging a selection.
90 */
91 private boolean inSelection = false;
92
93 /**
94 * Selection starting column.
95 */
96 private int selectionColumn0;
97
98 /**
99 * Selection starting line.
100 */
101 private int selectionLine0;
102
103 /**
104 * Selection ending column.
105 */
106 private int selectionColumn1;
107
108 /**
109 * Selection ending line.
110 */
111 private int selectionLine1;
112
615a0d99
KL
113 // ------------------------------------------------------------------------
114 // Constructors -----------------------------------------------------------
115 // ------------------------------------------------------------------------
116
12b55d76
KL
117 /**
118 * Public constructor.
119 *
120 * @param parent parent widget
121 * @param text text on the screen
122 * @param x column relative to parent
123 * @param y row relative to parent
124 * @param width width of text area
125 * @param height height of text area
126 */
127 public TEditorWidget(final TWidget parent, final String text, final int x,
128 final int y, final int width, final int height) {
129
130 // Set parent and window
131 super(parent, x, y, width, height);
132
133 setCursorVisible(true);
e8a11f98
KL
134
135 defaultColor = getTheme().getColor("teditor");
136 document = new Document(text, defaultColor);
12b55d76
KL
137 }
138
615a0d99 139 // ------------------------------------------------------------------------
101bc589 140 // Event handlers ---------------------------------------------------------
615a0d99
KL
141 // ------------------------------------------------------------------------
142
12b55d76
KL
143 /**
144 * Handle mouse press events.
145 *
146 * @param mouse mouse button press event
147 */
148 @Override
149 public void onMouseDown(final TMouseEvent mouse) {
150 if (mouse.isMouseWheelUp()) {
b1a8acec
KL
151 for (int i = 0; i < wheelScrollSize; i++) {
152 if (topLine > 0) {
153 topLine--;
154 alignDocument(false);
155 }
e8a11f98 156 }
12b55d76
KL
157 return;
158 }
159 if (mouse.isMouseWheelDown()) {
b1a8acec
KL
160 for (int i = 0; i < wheelScrollSize; i++) {
161 if (topLine < document.getLineCount() - 1) {
162 topLine++;
163 alignDocument(true);
164 }
e8a11f98 165 }
12b55d76
KL
166 return;
167 }
168
e8a11f98 169 if (mouse.isMouse1()) {
101bc589
KL
170 // Selection.
171 if (inSelection) {
172 selectionColumn1 = leftColumn + mouse.getX();
173 selectionLine1 = topLine + mouse.getY();
174 } else if (mouse.isShift() || mouse.isCtrl()) {
175 inSelection = true;
176 selectionColumn0 = leftColumn + mouse.getX();
177 selectionLine0 = topLine + mouse.getY();
178 selectionColumn1 = selectionColumn0;
179 selectionLine1 = selectionLine0;
180 selectionRectangle = mouse.isAlt() | mouse.isCtrl();
181 }
182
183 // Set the row and column
184 int newLine = topLine + mouse.getY();
185 int newX = leftColumn + mouse.getX();
186 if (newLine > document.getLineCount() - 1) {
187 // Go to the end
188 document.setLineNumber(document.getLineCount() - 1);
189 document.end();
190 if (newLine > document.getLineCount() - 1) {
191 setCursorY(document.getLineCount() - 1 - topLine);
192 } else {
193 setCursorY(mouse.getY());
194 }
195 alignCursor();
196 if (inSelection) {
197 selectionColumn1 = document.getCursor();
198 selectionLine1 = document.getLineNumber();
199 selectionRectangle = mouse.isCtrl();
200 }
201 return;
202 }
203
204 document.setLineNumber(newLine);
205 setCursorY(mouse.getY());
206 if (newX >= document.getCurrentLine().getDisplayLength()) {
207 document.end();
208 alignCursor();
209 } else {
210 document.setCursor(newX);
211 setCursorX(mouse.getX());
212 }
213 if (inSelection) {
214 selectionColumn1 = document.getCursor();
215 selectionLine1 = document.getLineNumber();
216 selectionRectangle = mouse.isCtrl();
217 }
218 return;
219 } else {
220 inSelection = false;
221 }
222
223 // Pass to children
224 super.onMouseDown(mouse);
225 }
226
227 /**
228 * Handle mouse motion events.
229 *
230 * @param mouse mouse motion event
231 */
232 @Override
233 public void onMouseMotion(final TMouseEvent mouse) {
234
235 if (mouse.isMouse1()) {
236 // Selection.
237 if (inSelection) {
238 selectionColumn1 = leftColumn + mouse.getX();
239 selectionLine1 = topLine + mouse.getY();
240 } else if (mouse.isShift() || mouse.isCtrl()) {
241 inSelection = true;
242 selectionColumn0 = leftColumn + mouse.getX();
243 selectionLine0 = topLine + mouse.getY();
244 selectionColumn1 = selectionColumn0;
245 selectionLine1 = selectionLine0;
246 selectionRectangle = mouse.isAlt() | mouse.isCtrl();
247 }
248
e8a11f98
KL
249 // Set the row and column
250 int newLine = topLine + mouse.getY();
251 int newX = leftColumn + mouse.getX();
df602ccf 252 if (newLine > document.getLineCount() - 1) {
e8a11f98
KL
253 // Go to the end
254 document.setLineNumber(document.getLineCount() - 1);
255 document.end();
df602ccf
KL
256 if (newLine > document.getLineCount() - 1) {
257 setCursorY(document.getLineCount() - 1 - topLine);
e8a11f98 258 } else {
df602ccf 259 setCursorY(mouse.getY());
e8a11f98
KL
260 }
261 alignCursor();
101bc589
KL
262 if (inSelection) {
263 selectionColumn1 = document.getCursor();
264 selectionLine1 = document.getLineNumber();
265 selectionRectangle = mouse.isCtrl();
266 }
e8a11f98
KL
267 return;
268 }
269
270 document.setLineNumber(newLine);
271 setCursorY(mouse.getY());
4297b49b 272 if (newX >= document.getCurrentLine().getDisplayLength()) {
e8a11f98
KL
273 document.end();
274 alignCursor();
275 } else {
df602ccf 276 document.setCursor(newX);
e8a11f98
KL
277 setCursorX(mouse.getX());
278 }
101bc589
KL
279 if (inSelection) {
280 selectionColumn1 = document.getCursor();
281 selectionLine1 = document.getLineNumber();
282 selectionRectangle = mouse.isCtrl();
283 }
e8a11f98 284 return;
101bc589
KL
285 } else {
286 inSelection = false;
e8a11f98 287 }
12b55d76
KL
288
289 // Pass to children
290 super.onMouseDown(mouse);
291 }
292
101bc589
KL
293 /**
294 * Handle mouse release events.
295 *
296 * @param mouse mouse button release event
297 */
298 @Override
299 public void onMouseUp(final TMouseEvent mouse) {
300 inSelection = false;
301
302 // Pass to children
303 super.onMouseDown(mouse);
304 }
305
12b55d76
KL
306 /**
307 * Handle keystrokes.
308 *
309 * @param keypress keystroke event
310 */
311 @Override
312 public void onKeypress(final TKeypressEvent keypress) {
101bc589
KL
313 if (keypress.getKey().isShift() || keypress.getKey().isCtrl()) {
314 // Selection.
315 if (!inSelection) {
316 inSelection = true;
317 selectionColumn0 = document.getCursor();
318 selectionLine0 = document.getLineNumber();
319 selectionColumn1 = selectionColumn0;
320 selectionLine1 = selectionLine0;
321 selectionRectangle = keypress.getKey().isCtrl();
322 }
323 } else {
324 inSelection = false;
325 }
326
327 if (keypress.equals(kbLeft)
328 || keypress.equals(kbShiftLeft)
329 ) {
df602ccf
KL
330 document.left();
331 alignTopLine(false);
101bc589
KL
332 } else if (keypress.equals(kbRight)
333 || keypress.equals(kbShiftRight)
334 ) {
df602ccf
KL
335 document.right();
336 alignTopLine(true);
e23989a4
KL
337 } else if (keypress.equals(kbAltLeft)
338 || keypress.equals(kbCtrlLeft)
339 ) {
340 document.backwardsWord();
341 alignTopLine(false);
342 } else if (keypress.equals(kbAltRight)
343 || keypress.equals(kbCtrlRight)
344 ) {
345 document.forwardsWord();
346 alignTopLine(true);
101bc589
KL
347 } else if (keypress.equals(kbUp)
348 || keypress.equals(kbShiftUp)
349 ) {
71a389c9
KL
350 document.up();
351 alignTopLine(false);
101bc589
KL
352 } else if (keypress.equals(kbDown)
353 || keypress.equals(kbShiftDown)
354 ) {
71a389c9
KL
355 document.down();
356 alignTopLine(true);
12b55d76 357 } else if (keypress.equals(kbPgUp)) {
71a389c9
KL
358 document.up(getHeight() - 1);
359 alignTopLine(false);
12b55d76 360 } else if (keypress.equals(kbPgDn)) {
71a389c9
KL
361 document.down(getHeight() - 1);
362 alignTopLine(true);
12b55d76 363 } else if (keypress.equals(kbHome)) {
e8a11f98
KL
364 if (document.home()) {
365 leftColumn = 0;
366 if (leftColumn < 0) {
367 leftColumn = 0;
368 }
369 setCursorX(0);
370 }
12b55d76 371 } else if (keypress.equals(kbEnd)) {
e8a11f98
KL
372 if (document.end()) {
373 alignCursor();
374 }
12b55d76
KL
375 } else if (keypress.equals(kbCtrlHome)) {
376 document.setLineNumber(0);
377 document.home();
e8a11f98
KL
378 topLine = 0;
379 leftColumn = 0;
380 setCursorX(0);
381 setCursorY(0);
12b55d76
KL
382 } else if (keypress.equals(kbCtrlEnd)) {
383 document.setLineNumber(document.getLineCount() - 1);
384 document.end();
71a389c9 385 alignTopLine(false);
12b55d76
KL
386 } else if (keypress.equals(kbIns)) {
387 document.setOverwrite(!document.getOverwrite());
388 } else if (keypress.equals(kbDel)) {
389 document.del();
71a389c9 390 alignCursor();
39e86397
KL
391 } else if (keypress.equals(kbBackspace)
392 || keypress.equals(kbBackspaceDel)
393 ) {
12b55d76 394 document.backspace();
df602ccf
KL
395 alignTopLine(false);
396 } else if (keypress.equals(kbTab)) {
101bc589 397 // Add spaces until we hit modulo 8.
df602ccf
KL
398 for (int i = document.getCursor(); (i + 1) % 8 != 0; i++) {
399 document.addChar(' ');
400 }
e8a11f98 401 alignCursor();
71a389c9 402 } else if (keypress.equals(kbEnter)) {
df602ccf
KL
403 document.enter();
404 alignTopLine(true);
12b55d76
KL
405 } else if (!keypress.getKey().isFnKey()
406 && !keypress.getKey().isAlt()
407 && !keypress.getKey().isCtrl()
408 ) {
409 // Plain old keystroke, process it
2d3f60d8 410 document.addChar(keypress.getKey().getChar());
71a389c9 411 alignCursor();
12b55d76
KL
412 } else {
413 // Pass other keys (tab etc.) on to TWidget
414 super.onKeypress(keypress);
415 }
101bc589
KL
416
417 if (inSelection) {
418 selectionColumn1 = document.getCursor();
419 selectionLine1 = document.getLineNumber();
420 selectionRectangle = keypress.getKey().isCtrl();
421 }
12b55d76
KL
422 }
423
e8a11f98
KL
424 /**
425 * Method that subclasses can override to handle window/screen resize
426 * events.
427 *
428 * @param resize resize event
429 */
430 @Override
431 public void onResize(final TResizeEvent resize) {
432 // Change my width/height, and pull the cursor in as needed.
433 if (resize.getType() == TResizeEvent.Type.WIDGET) {
434 setWidth(resize.getWidth());
435 setHeight(resize.getHeight());
436 // See if the cursor is now outside the window, and if so move
437 // things.
438 if (getCursorX() >= getWidth()) {
439 leftColumn += getCursorX() - (getWidth() - 1);
440 setCursorX(getWidth() - 1);
441 }
442 if (getCursorY() >= getHeight()) {
443 topLine += getCursorY() - (getHeight() - 1);
444 setCursorY(getHeight() - 1);
445 }
446 } else {
447 // Let superclass handle it
448 super.onResize(resize);
449 }
450 }
451
101bc589
KL
452 /**
453 * Handle posted command events.
454 *
455 * @param command command event
456 */
457 @Override
458 public void onCommand(final TCommandEvent command) {
459 if (command.equals(cmCut)) {
460 // Copy text to clipboard, and then remove it.
461
462 // TODO
463
464 deleteSelection();
465 return;
466 }
467
468 if (command.equals(cmCopy)) {
469 // Copy text to clipboard.
470
471 // TODO
472
473 return;
474 }
475
476 if (command.equals(cmPaste)) {
477 // Delete selected text, then paste text from clipboard.
478 deleteSelection();
479
480 String text = getClipboard().pasteText();
481 if (text != null) {
482 for (int i = 0; i < text.length(); ) {
483 int ch = text.codePointAt(i);
484 onKeypress(new TKeypressEvent(false, 0, ch, false, false,
485 false));
486 i += Character.charCount(ch);
487 }
488 }
489 return;
490 }
491
492 if (command.equals(cmClear)) {
493 // Remove text.
494 deleteSelection();
495 return;
496 }
497
498 }
499
500 // ------------------------------------------------------------------------
501 // TWidget ----------------------------------------------------------------
502 // ------------------------------------------------------------------------
503
504 /**
505 * Draw the text box.
506 */
507 @Override
508 public void draw() {
509 for (int i = 0; i < getHeight(); i++) {
510 // Background line
511 getScreen().hLineXY(0, i, getWidth(), ' ', defaultColor);
512
513 // Now draw document's line
514 if (topLine + i < document.getLineCount()) {
515 Line line = document.getLine(topLine + i);
516 int x = 0;
517 for (Word word: line.getWords()) {
518 // For now, we are cheating: draw outside the left region
519 // if needed and let screen do the clipping.
520 getScreen().putStringXY(x - leftColumn, i, word.getText(),
521 word.getColor());
522 x += word.getDisplayLength();
523 if (x - leftColumn > getWidth()) {
524 break;
525 }
526 }
527 }
528
529 // TODO: highlight selected region
530 }
531 }
532
615a0d99
KL
533 // ------------------------------------------------------------------------
534 // TEditorWidget ----------------------------------------------------------
535 // ------------------------------------------------------------------------
536
537 /**
538 * Align visible area with document current line.
539 *
540 * @param topLineIsTop if true, make the top visible line the document
541 * current line if it was off-screen. If false, make the bottom visible
542 * line the document current line.
543 */
544 private void alignTopLine(final boolean topLineIsTop) {
545 int line = document.getLineNumber();
546
547 if ((line < topLine) || (line > topLine + getHeight() - 1)) {
548 // Need to move topLine to bring document back into view.
549 if (topLineIsTop) {
550 topLine = line - (getHeight() - 1);
551 if (topLine < 0) {
552 topLine = 0;
553 }
554 assert (topLine >= 0);
555 } else {
556 topLine = line;
557 assert (topLine >= 0);
558 }
559 }
560
561 /*
562 System.err.println("line " + line + " topLine " + topLine);
563 */
564
565 // Document is in view, let's set cursorY
566 assert (line >= topLine);
567 setCursorY(line - topLine);
568 alignCursor();
569 }
570
571 /**
572 * Align document current line with visible area.
573 *
574 * @param topLineIsTop if true, make the top visible line the document
575 * current line if it was off-screen. If false, make the bottom visible
576 * line the document current line.
577 */
578 private void alignDocument(final boolean topLineIsTop) {
579 int line = document.getLineNumber();
580 int cursor = document.getCursor();
581
582 if ((line < topLine) || (line > topLine + getHeight() - 1)) {
583 // Need to move document to ensure it fits view.
584 if (topLineIsTop) {
585 document.setLineNumber(topLine);
586 } else {
587 document.setLineNumber(topLine + (getHeight() - 1));
588 }
589 if (cursor < document.getCurrentLine().getDisplayLength()) {
590 document.setCursor(cursor);
591 }
592 }
593
594 /*
595 System.err.println("getLineNumber() " + document.getLineNumber() +
596 " topLine " + topLine);
597 */
598
599 // Document is in view, let's set cursorY
600 setCursorY(document.getLineNumber() - topLine);
601 alignCursor();
602 }
603
604 /**
605 * Align visible cursor with document cursor.
606 */
607 private void alignCursor() {
608 int width = getWidth();
609
610 int desiredX = document.getCursor() - leftColumn;
611 if (desiredX < 0) {
612 // We need to push the screen to the left.
613 leftColumn = document.getCursor();
614 } else if (desiredX > width - 1) {
615 // We need to push the screen to the right.
616 leftColumn = document.getCursor() - (width - 1);
617 }
618
619 /*
620 System.err.println("document cursor " + document.getCursor() +
621 " leftColumn " + leftColumn);
622 */
623
624
625 setCursorX(document.getCursor() - leftColumn);
626 }
627
71a389c9
KL
628 /**
629 * Get the number of lines in the underlying Document.
630 *
631 * @return the number of lines
632 */
633 public int getLineCount() {
634 return document.getLineCount();
635 }
636
b6faeac0
KL
637 /**
638 * Get the current visible top row number. 1-based.
639 *
640 * @return the visible top row number. Row 1 is the first row.
641 */
642 public int getVisibleRowNumber() {
643 return topLine + 1;
644 }
645
646 /**
647 * Set the current visible row number. 1-based.
648 *
649 * @param row the new visible row number. Row 1 is the first row.
650 */
651 public void setVisibleRowNumber(final int row) {
652 assert (row > 0);
653 if ((row > 0) && (row < document.getLineCount())) {
654 topLine = row - 1;
655 alignDocument(true);
656 }
657 }
658
71a389c9
KL
659 /**
660 * Get the current editing row number. 1-based.
661 *
662 * @return the editing row number. Row 1 is the first row.
663 */
664 public int getEditingRowNumber() {
665 return document.getLineNumber() + 1;
666 }
667
668 /**
669 * Set the current editing row number. 1-based.
670 *
671 * @param row the new editing row number. Row 1 is the first row.
672 */
673 public void setEditingRowNumber(final int row) {
fe0770f9
KL
674 assert (row > 0);
675 if ((row > 0) && (row < document.getLineCount())) {
676 document.setLineNumber(row - 1);
677 alignTopLine(true);
678 }
71a389c9
KL
679 }
680
1bc08f18
KL
681 /**
682 * Set the current visible column number. 1-based.
683 *
684 * @return the visible column number. Column 1 is the first column.
685 */
686 public int getVisibleColumnNumber() {
687 return leftColumn + 1;
688 }
689
690 /**
691 * Set the current visible column number. 1-based.
692 *
693 * @param column the new visible column number. Column 1 is the first
694 * column.
695 */
696 public void setVisibleColumnNumber(final int column) {
697 assert (column > 0);
698 if ((column > 0) && (column < document.getLineLengthMax())) {
699 leftColumn = column - 1;
700 alignDocument(true);
701 }
702 }
703
71a389c9
KL
704 /**
705 * Get the current editing column number. 1-based.
706 *
707 * @return the editing column number. Column 1 is the first column.
708 */
709 public int getEditingColumnNumber() {
710 return document.getCursor() + 1;
711 }
712
713 /**
714 * Set the current editing column number. 1-based.
715 *
716 * @param column the new editing column number. Column 1 is the first
717 * column.
718 */
719 public void setEditingColumnNumber(final int column) {
fe0770f9
KL
720 if ((column > 0) && (column < document.getLineLength())) {
721 document.setCursor(column - 1);
722 alignCursor();
723 }
71a389c9
KL
724 }
725
726 /**
727 * Get the maximum possible row number. 1-based.
728 *
729 * @return the maximum row number. Row 1 is the first row.
730 */
731 public int getMaximumRowNumber() {
732 return document.getLineCount() + 1;
733 }
734
735 /**
736 * Get the maximum possible column number. 1-based.
737 *
738 * @return the maximum column number. Column 1 is the first column.
739 */
740 public int getMaximumColumnNumber() {
741 return document.getLineLengthMax() + 1;
742 }
743
744 /**
745 * Get the dirty value.
746 *
747 * @return true if the buffer is dirty
748 */
749 public boolean isDirty() {
750 return document.isDirty();
751 }
752
753 /**
754 * Save contents to file.
755 *
756 * @param filename file to save to
757 * @throws IOException if a java.io operation throws
758 */
759 public void saveToFilename(final String filename) throws IOException {
760 document.saveToFilename(filename);
761 }
762
101bc589
KL
763 /**
764 * Delete text within the selection bounds.
765 */
766 private void deleteSelection() {
767 if (inSelection == false) {
768 return;
769 }
770
771 // TODO
772 }
773
774 // ------------------------------------------------------------------------
775 // EditMenuUser -----------------------------------------------------------
776 // ------------------------------------------------------------------------
777
778 /**
779 * Check if the cut menu item should be enabled.
780 *
781 * @return true if the cut menu item should be enabled
782 */
783 public boolean isEditMenuCut() {
784 return true;
785 }
786
787 /**
788 * Check if the copy menu item should be enabled.
789 *
790 * @return true if the copy menu item should be enabled
791 */
792 public boolean isEditMenuCopy() {
793 return true;
794 }
795
796 /**
797 * Check if the paste menu item should be enabled.
798 *
799 * @return true if the paste menu item should be enabled
800 */
801 public boolean isEditMenuPaste() {
802 return true;
803 }
804
805 /**
806 * Check if the clear menu item should be enabled.
807 *
808 * @return true if the clear menu item should be enabled
809 */
810 public boolean isEditMenuClear() {
811 return true;
812 }
813
12b55d76 814}