TEditor 80% complete
[fanfix.git] / src / jexer / TEditorWindow.java
CommitLineData
71a389c9
KL
1/*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2017 Kevin Lamonte
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
31import java.io.File;
32import java.io.IOException;
33import java.util.Scanner;
34
35import jexer.TApplication;
36import jexer.TEditorWidget;
37import jexer.THScroller;
38import jexer.TScrollableWindow;
39import jexer.TVScroller;
40import jexer.TWidget;
41import jexer.bits.CellAttributes;
42import jexer.bits.GraphicsChars;
43import jexer.event.TCommandEvent;
44import jexer.event.TMouseEvent;
45import jexer.event.TResizeEvent;
46import static jexer.TCommand.*;
47import static jexer.TKeypress.*;
48
49/**
50 * TEditorWindow is a basic text file editor.
51 */
52public class TEditorWindow extends TScrollableWindow {
53
54 /**
55 * Hang onto my TEditor so I can resize it with the window.
56 */
57 private TEditorWidget editField;
58
59 /**
60 * The fully-qualified name of the file being edited.
61 */
62 private String filename = "";
63
64 /**
65 * Setup other fields after the editor is created.
66 */
67 private void setupAfterEditor() {
68 hScroller = new THScroller(this, 17, getHeight() - 2, getWidth() - 20);
69 vScroller = new TVScroller(this, getWidth() - 2, 0, getHeight() - 2);
70 setMinimumWindowWidth(25);
71 setMinimumWindowHeight(10);
72 setTopValue(1);
73 setBottomValue(editField.getMaximumRowNumber());
74 setLeftValue(1);
75 setRightValue(editField.getMaximumColumnNumber());
76
77 statusBar = newStatusBar("Editor");
78 statusBar.addShortcutKeypress(kbF1, cmHelp, "Help");
79 statusBar.addShortcutKeypress(kbF2, cmSave, "Save");
80 statusBar.addShortcutKeypress(kbF3, cmOpen, "Open");
81 statusBar.addShortcutKeypress(kbF10, cmMenu, "Menu");
82 }
83
84 /**
85 * Public constructor sets window title.
86 *
87 * @param parent the main application
88 * @param title the window title
89 */
90 public TEditorWindow(final TApplication parent, final String title) {
91
92 super(parent, title, 0, 0, parent.getScreen().getWidth(),
93 parent.getScreen().getHeight() - 2, RESIZABLE);
94
95 editField = addEditor("", 0, 0, getWidth() - 2, getHeight() - 2);
96 setupAfterEditor();
97 }
98
99 /**
100 * Public constructor sets window title and contents.
101 *
102 * @param parent the main application
103 * @param title the window title, usually a filename
104 * @param contents the data for the editing window, usually the file data
105 */
106 public TEditorWindow(final TApplication parent, final String title,
107 final String contents) {
108
109 super(parent, title, 0, 0, parent.getScreen().getWidth(),
110 parent.getScreen().getHeight() - 2, RESIZABLE);
111
112 filename = title;
113 editField = addEditor(contents, 0, 0, getWidth() - 2, getHeight() - 2);
114 setupAfterEditor();
115 }
116
117 /**
118 * Public constructor.
119 *
120 * @param parent the main application
121 */
122 public TEditorWindow(final TApplication parent) {
123 this(parent, "New Text Document");
124 }
125
126 /**
127 * Draw the window.
128 */
129 @Override
130 public void draw() {
131 // Draw as normal.
132 super.draw();
133
134 // Add the row:col on the bottom row
135 CellAttributes borderColor = getBorder();
136 String location = String.format(" %d:%d ",
137 editField.getEditingRowNumber(),
138 editField.getEditingColumnNumber());
139 int colon = location.indexOf(':');
140 putStringXY(10 - colon, getHeight() - 1, location, borderColor);
141
142 if (editField.isDirty()) {
143 putCharXY(2, getHeight() - 1, GraphicsChars.OCTOSTAR, borderColor);
144 }
145 }
146
147 /**
148 * Check if a mouse press/release/motion event coordinate is over the
149 * editor.
150 *
151 * @param mouse a mouse-based event
152 * @return whether or not the mouse is on the emulator
153 */
154 private final boolean mouseOnEditor(final TMouseEvent mouse) {
155 if ((mouse.getAbsoluteX() >= getAbsoluteX() + 1)
156 && (mouse.getAbsoluteX() < getAbsoluteX() + getWidth() - 1)
157 && (mouse.getAbsoluteY() >= getAbsoluteY() + 1)
158 && (mouse.getAbsoluteY() < getAbsoluteY() + getHeight() - 1)
159 ) {
160 return true;
161 }
162 return false;
163 }
164
165 /**
166 * Handle mouse press events.
167 *
168 * @param mouse mouse button press event
169 */
170 @Override
171 public void onMouseDown(final TMouseEvent mouse) {
172 if (mouseOnEditor(mouse)) {
173 editField.onMouseDown(mouse);
174 setBottomValue(editField.getMaximumRowNumber());
175 setVerticalValue(editField.getEditingRowNumber());
176 setRightValue(editField.getMaximumColumnNumber());
177 setHorizontalValue(editField.getEditingColumnNumber());
178 } else {
179 // Let the scrollbars get the event
180 super.onMouseDown(mouse);
181
182 if (mouse.isMouseWheelUp() || mouse.isMouseWheelDown()) {
183 editField.setEditingRowNumber(getVerticalValue());
184 }
185 // TODO: horizontal scrolling
186 }
187 }
188
189 /**
190 * Handle window/screen resize events.
191 *
192 * @param event resize event
193 */
194 @Override
195 public void onResize(final TResizeEvent event) {
196 if (event.getType() == TResizeEvent.Type.WIDGET) {
197 // Resize the text field
198 TResizeEvent editSize = new TResizeEvent(TResizeEvent.Type.WIDGET,
199 event.getWidth() - 2, event.getHeight() - 2);
200 editField.onResize(editSize);
201
202 // Have TScrollableWindow handle the scrollbars
203 super.onResize(event);
204 return;
205 }
206
207 // Pass to children instead
208 for (TWidget widget: getChildren()) {
209 widget.onResize(event);
210 }
211 }
212
213 /**
214 * Method that subclasses can override to handle posted command events.
215 *
216 * @param command command event
217 */
218 @Override
219 public void onCommand(final TCommandEvent command) {
220 if (command.equals(cmOpen)) {
221 try {
222 String filename = fileOpenBox(".");
223 if (filename != null) {
224 try {
225 File file = new File(filename);
226 StringBuilder fileContents = new StringBuilder();
227 Scanner scanner = new Scanner(file);
228 String EOL = System.getProperty("line.separator");
229
230 try {
231 while (scanner.hasNextLine()) {
232 fileContents.append(scanner.nextLine() + EOL);
233 }
234 new TEditorWindow(getApplication(), filename,
235 fileContents.toString());
236 } finally {
237 scanner.close();
238 }
239 } catch (IOException e) {
240 // TODO: make this a message box
241 e.printStackTrace();
242 }
243 }
244 } catch (IOException e) {
245 // TODO: make this a message box
246 e.printStackTrace();
247 }
248 return;
249 }
250
251 if (command.equals(cmSave)) {
252 if (filename.length() > 0) {
253 try {
254 editField.saveToFilename(filename);
255 } catch (IOException e) {
256 // TODO: make this a message box
257 e.printStackTrace();
258 }
259 }
260 return;
261 }
262
263 // Didn't handle it, let children get it instead
264 super.onCommand(command);
265 }
266
267}