1 /*
2 * SSHTools - Java SSH2 API
3 *
4 * Copyright (C) 2002-2003 Lee David Painter and Contributors.
5 *
6 * Contributions made by:
7 *
8 * Brett Smith
9 * Richard Pernavas
10 * Erwin Bolwidt
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 */
26 /**
27 * SSHTools - Java SSH API The contents of this package has been derived from
28 * the TelnetD library available from http://sourceforge.net/projects/telnetd
29 * The original license of the source code is as follows: TelnetD library
30 * (embeddable telnet daemon) Copyright (C) 2000 Dieter Wimberger This library
31 * is free software; you can either redistribute it and/or modify it under the
32 * terms of the GNU Lesser General Public License version 2.1,1999 as
33 * published by the Free Software Foundation (see copy received along with the
34 * library), or under the terms of the BSD-style license received along with
35 * this library.
36 */
37 package com.sshtools.daemon.terminal;
38
39 import java.io;
40
41
42 /**
43 *
44 *
45 * @author $author$
46 * @version $Revision: 1.12 $
47 */
48 public class Editline {
49 //Aggregations (inner class!)
50 private Buffer buf;
51
52 //Members
53 private TerminalIO myIO;
54 private int Cursor = 0;
55 private boolean InsertMode = true;
56 private int lastSize = 0;
57 private boolean hardwrapped = false;
58 private char lastread;
59 private int lastcurspos = 0;
60 private boolean maskInput = false;
61 private char mask = '*';
62
63 /**
64 * Creates a new Editline object.
65 *
66 * @param io
67 */
68 public Editline(TerminalIO io) {
69 myIO = io;
70
71 //allways full length
72 buf = new Buffer(myIO.getColumns() - 1);
73 Cursor = 0;
74 InsertMode = true;
75 }
76
77 //constructor
78 public int size() {
79 return buf.size();
80 }
81
82 //getSize
83 public String getValue() {
84 return buf.toString();
85 }
86
87 //getValue
88 public void setValue(String str)
89 throws BufferOverflowException, IOException {
90 storeSize();
91
92 //buffer
93 buf.clear();
94
95 //cursor
96 Cursor = 0;
97
98 //screen
99 myIO.moveLeft(lastSize);
100 myIO.eraseToEndOfLine();
101 append(str);
102 }
103
104 //setValue
105 public void maskInput(boolean maskInput) {
106 this.maskInput = maskInput;
107 }
108
109 /**
110 *
111 *
112 * @param mask
113 */
114 public void setMask(char mask) {
115 this.mask = mask;
116 }
117
118 /**
119 *
120 *
121 * @throws IOException
122 */
123 public void clear() throws IOException {
124 storeSize();
125
126 //Buffer
127 buf.clear();
128
129 //Cursor
130 Cursor = 0;
131
132 //Screen
133 draw();
134 }
135
136 //clear
137 public String getSoftwrap() throws IndexOutOfBoundsException, IOException {
138 //Wrap from Buffer
139 String content = buf.toString();
140 int idx = content.lastIndexOf(" ");
141
142 if (idx == -1) {
143 content = "";
144 } else {
145 //System.out.println("Line:softwrap:lastspace:"+idx);
146 content = content.substring(idx + 1, content.length());
147
148 //System.out.println("Line:softwrap:wraplength:"+content.length());
149 //Cursor
150 //remeber relative cursor pos
151 Cursor = size();
152 Cursor = Cursor - content.length();
153
154 //buffer
155 for (int i = 0; i < content.length(); i++) {
156 buf.removeCharAt(Cursor);
157 }
158
159 //screen
160 myIO.moveLeft(content.length());
161 myIO.eraseToEndOfLine();
162
163 //System.out.println("Line:softwrap:buffercontent:"+buf.toString());
164 }
165
166 return content + getLastRead();
167 }
168
169 //getSoftWrap
170 public String getHardwrap() throws IndexOutOfBoundsException, IOException {
171 //Buffer
172 String content = buf.toString();
173 content = content.substring(Cursor, content.length());
174
175 //System.out.println("buffer:tostring:"+buf.toString()+":");
176 //System.out.println("buffer:size:"+buf.size());
177 int lastsize = buf.size();
178
179 for (int i = Cursor; i < lastsize; i++) {
180 buf.removeCharAt(Cursor);
181
182 //System.out.println("buffer:removing char #"+i);
183 }
184
185 //System.out.println("buffer:tostring:"+buf.toString()+":");
186 //cursor stays
187 //screen
188 myIO.eraseToEndOfLine();
189
190 return content;
191 }
192
193 //getHardWrap
194 private void setCharAt(int pos, char ch)
195 throws IndexOutOfBoundsException, IOException {
196 //buffer
197 buf.setCharAt(pos, ch);
198
199 //cursor
200 //implements overwrite mode no change
201 //screen
202 draw();
203 }
204
205 //setCharAt
206 private void insertCharAt(int pos, char ch)
207 throws BufferOverflowException, IndexOutOfBoundsException, IOException {
208 storeSize();
209
210 //buffer
211 buf.ensureSpace(1);
212 buf.insertCharAt(pos, ch);
213
214 //cursor adjustment (so that it stays in "same" pos)
215 if (Cursor >= pos) {
216 Cursor++;
217 }
218
219 //screen
220 draw();
221 }
222
223 //insertCharAt
224 private void removeCharAt(int pos)
225 throws IndexOutOfBoundsException, IOException {
226 storeSize();
227
228 //buffer
229 buf.removeCharAt(pos);
230
231 //cursor
232 if (Cursor > pos) {
233 Cursor--;
234 }
235
236 //screen
237 draw();
238 }
239
240 //removeChatAt
241 private void insertStringAt(int pos, String str)
242 throws BufferOverflowException, IndexOutOfBoundsException, IOException {
243 storeSize();
244
245 //buffer
246 buf.ensureSpace(str.length());
247
248 for (int i = 0; i < str.length(); i++) {
249 buf.insertCharAt(pos, str.charAt(i));
250
251 //Cursor
252 Cursor++;
253 }
254
255 //screen
256 draw();
257 }
258
259 //insertStringAt
260 public void append(char ch) throws BufferOverflowException, IOException {
261 storeSize();
262
263 //buffer
264 buf.ensureSpace(1);
265 buf.append(ch);
266
267 //cursor
268 Cursor++;
269
270 //screen
271 if (!maskInput) {
272 myIO.write(ch);
273 } else {
274 myIO.write(mask);
275 }
276 }
277
278 //append(char)
279 public void append(String str) throws BufferOverflowException, IOException {
280 storeSize();
281
282 //buffer
283 buf.ensureSpace(str.length());
284
285 for (int i = 0; i < str.length(); i++) {
286 buf.append(str.charAt(i));
287
288 //Cursor
289 Cursor++;
290 }
291
292 //screen
293 if (!maskInput) {
294 myIO.write(str);
295 } else {
296 for (int i = 0; i < str.length(); i++) {
297 myIO.write(mask);
298 }
299 }
300 }
301
302 //append(String)
303 public int getCursorPosition() {
304 return Cursor;
305 }
306
307 //getCursorPosition
308 public void setCursorPosition(int pos) {
309 if (buf.size() < pos) {
310 Cursor = buf.size();
311 } else {
312 Cursor = pos;
313 }
314
315 //System.out.println("Editline:cursor:"+Cursor);
316 }
317
318 //setCursorPosition
319 private char getLastRead() {
320 return lastread;
321 }
322
323 //getLastRead
324 private void setLastRead(char ch) {
325 lastread = ch;
326 }
327
328 //setLastRead
329 public boolean isInInsertMode() {
330 return InsertMode;
331 }
332
333 //isInInsertMode
334 public void setInsertMode(boolean b) {
335 InsertMode = b;
336 }
337
338 //setInsertMode
339 public boolean isHardwrapped() {
340 return hardwrapped;
341 }
342
343 //isHardwrapped
344 public void setHardwrapped(boolean b) {
345 hardwrapped = b;
346 }
347
348 //setHardwrapped
349 public int run() {
350 try {
351 int in = 0;
352
353 do {
354 //get next key
355 in = myIO.read();
356
357 //store cursorpos
358 lastcurspos = Cursor;
359
360 switch (in) {
361 case TerminalIO.LEFT:
362
363 if (!moveLeft()) {
364 return in;
365 }
366
367 break;
368
369 case TerminalIO.RIGHT:
370
371 if (!moveRight()) {
372 return in;
373 }
374
375 break;
376
377 case TerminalIO.BACKSPACE:
378
379 try {
380 if (Cursor == 0) {
381 return in;
382 } else {
383 removeCharAt(Cursor - 1);
384 }
385 } catch (IndexOutOfBoundsException ioobex) {
386 myIO.bell();
387 }
388
389 break;
390
391 case TerminalIO.DELETE:
392
393 try {
394 removeCharAt(Cursor);
395 } catch (IndexOutOfBoundsException ioobex) {
396 myIO.bell();
397 }
398
399 break;
400
401 case TerminalIO.ENTER:
402 case TerminalIO.UP:
403 case TerminalIO.DOWN:
404 case TerminalIO.TABULATOR:
405 return in;
406
407 default:
408
409 try {
410 handleCharInput(in);
411 } catch (BufferOverflowException boex) {
412 setLastRead((char) in);
413
414 return in;
415 }
416 }
417
418 myIO.flush();
419 } while (true);
420 } catch (IOException ioe) {
421 return TerminalIO.IOERROR;
422 }
423 }
424
425 //run
426 public void draw() throws IOException {
427 myIO.moveLeft(lastcurspos);
428 myIO.eraseToEndOfLine();
429
430 if (!maskInput) {
431 myIO.write(buf.toString());
432 } else {
433 for (int i = 0; i < buf.size(); i++) {
434 myIO.write(mask);
435 }
436 }
437
438 //adjust screen cursor hmm
439 if (Cursor < buf.size()) {
440 myIO.moveLeft(buf.size() - Cursor);
441 }
442 }
443
444 private boolean moveRight() throws IOException {
445 //cursor
446 if (Cursor < buf.size()) {
447 Cursor++;
448
449 //screen
450 myIO.moveRight(1);
451
452 return true;
453 } else {
454 return false;
455 }
456 }
457
458 private boolean moveLeft() throws IOException {
459 //cursor
460 if (Cursor > 0) {
461 Cursor--;
462
463 //screen
464 myIO.moveLeft(1);
465
466 return true;
467 } else {
468 return false;
469 }
470 }
471
472 private boolean isCursorAtEnd() {
473 return (Cursor == buf.size());
474 }
475
476 private void handleCharInput(int ch)
477 throws BufferOverflowException, IOException {
478 if (isCursorAtEnd()) {
479 append((char) ch);
480 } else {
481 if (isInInsertMode()) {
482 try {
483 insertCharAt(Cursor, (char) ch);
484 } catch (BufferOverflowException ex) {
485 //ignore buffer overflow on insert
486 myIO.bell();
487 }
488 } else {
489 setCharAt(Cursor, (char) ch);
490 }
491 }
492 }
493
494 private void storeSize() {
495 lastSize = buf.size();
496 }
497
498 class Buffer extends CharBuffer {
499 public Buffer(int size) {
500 super(size);
501 }
502 }
503 }