Commit | Line | Data |
---|---|---|
a3b510ab NR |
1 | /* |
2 | * This file is part of lanterna (http://code.google.com/p/lanterna/). | |
3 | * | |
4 | * lanterna is free software: you can redistribute it and/or modify | |
5 | * it under the terms of the GNU Lesser General Public License as published by | |
6 | * the Free Software Foundation, either version 3 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU Lesser General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU Lesser General Public License | |
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | * | |
17 | * Copyright (C) 2010-2015 Martin | |
18 | */ | |
19 | package com.googlecode.lanterna.terminal; | |
20 | ||
21 | import com.googlecode.lanterna.TerminalSize; | |
22 | import com.googlecode.lanterna.terminal.ansi.CygwinTerminal; | |
23 | import com.googlecode.lanterna.terminal.ansi.UnixTerminal; | |
24 | import com.googlecode.lanterna.terminal.swing.*; | |
25 | ||
26 | import java.awt.*; | |
27 | import java.io.IOException; | |
28 | import java.io.InputStream; | |
29 | import java.io.OutputStream; | |
30 | import java.nio.charset.Charset; | |
31 | ||
32 | /** | |
33 | * This TerminalFactory implementation uses a simple auto-detection mechanism for figuring out which terminal | |
34 | * implementation to create based on characteristics of the system the program is running on. | |
35 | * <p> | |
36 | * Note that for all systems with a graphical environment present, the SwingTerminalFrame will be chosen. You can | |
37 | * suppress this by calling setForceTextTerminal(true) on this factory. | |
38 | * @author martin | |
39 | */ | |
40 | public final class DefaultTerminalFactory implements TerminalFactory { | |
41 | private static final OutputStream DEFAULT_OUTPUT_STREAM = System.out; | |
42 | private static final InputStream DEFAULT_INPUT_STREAM = System.in; | |
43 | private static final Charset DEFAULT_CHARSET = Charset.forName(System.getProperty("file.encoding")); | |
44 | ||
45 | private final OutputStream outputStream; | |
46 | private final InputStream inputStream; | |
47 | private final Charset charset; | |
48 | ||
49 | private TerminalSize initialTerminalSize; | |
50 | private boolean forceTextTerminal; | |
51 | private boolean forceAWTOverSwing; | |
52 | private String title; | |
53 | private boolean autoOpenTerminalFrame; | |
54 | private TerminalEmulatorAutoCloseTrigger autoCloseTrigger; | |
55 | private TerminalEmulatorColorConfiguration colorConfiguration; | |
56 | private TerminalEmulatorDeviceConfiguration deviceConfiguration; | |
57 | private AWTTerminalFontConfiguration fontConfiguration; | |
58 | private MouseCaptureMode mouseCaptureMode; | |
59 | ||
60 | /** | |
61 | * Creates a new DefaultTerminalFactory with all properties set to their defaults | |
62 | */ | |
63 | public DefaultTerminalFactory() { | |
64 | this(DEFAULT_OUTPUT_STREAM, DEFAULT_INPUT_STREAM, DEFAULT_CHARSET); | |
65 | } | |
66 | ||
67 | /** | |
68 | * Creates a new DefaultTerminalFactory with I/O and character set options customisable. | |
69 | * @param outputStream Output stream to use for text-based Terminal implementations | |
70 | * @param inputStream Input stream to use for text-based Terminal implementations | |
71 | * @param charset Character set to assume the client is using | |
72 | */ | |
73 | @SuppressWarnings({"SameParameterValue", "WeakerAccess"}) | |
74 | public DefaultTerminalFactory(OutputStream outputStream, InputStream inputStream, Charset charset) { | |
75 | this.outputStream = outputStream; | |
76 | this.inputStream = inputStream; | |
77 | this.charset = charset; | |
78 | ||
79 | this.forceTextTerminal = false; | |
80 | this.autoOpenTerminalFrame = true; | |
81 | this.title = null; | |
82 | this.autoCloseTrigger = TerminalEmulatorAutoCloseTrigger.CloseOnExitPrivateMode; | |
83 | this.mouseCaptureMode = null; | |
84 | ||
85 | //SwingTerminal will replace these null values for the default implementation if they are unchanged | |
86 | this.colorConfiguration = null; | |
87 | this.deviceConfiguration = null; | |
88 | this.fontConfiguration = null; | |
89 | } | |
90 | ||
91 | @Override | |
92 | public Terminal createTerminal() throws IOException { | |
93 | if (GraphicsEnvironment.isHeadless() || forceTextTerminal || System.console() != null) { | |
94 | if(isOperatingSystemWindows()) { | |
95 | return createCygwinTerminal(outputStream, inputStream, charset); | |
96 | } | |
97 | else { | |
98 | return createUnixTerminal(outputStream, inputStream, charset); | |
99 | } | |
100 | } | |
101 | else { | |
102 | return createTerminalEmulator(); | |
103 | } | |
104 | } | |
105 | ||
106 | /** | |
107 | * Creates a new terminal emulator window which will be either Swing-based or AWT-based depending on what is | |
108 | * available on the system | |
109 | * @return New terminal emulator exposed as a {@link Terminal} interface | |
110 | */ | |
111 | public Terminal createTerminalEmulator() { | |
112 | Window window; | |
113 | if(!forceAWTOverSwing && hasSwing()) { | |
114 | window = createSwingTerminal(); | |
115 | } | |
116 | else { | |
117 | window = createAWTTerminal(); | |
118 | } | |
119 | ||
120 | if(autoOpenTerminalFrame) { | |
121 | window.setVisible(true); | |
122 | } | |
123 | return (Terminal)window; | |
124 | } | |
125 | ||
126 | public AWTTerminalFrame createAWTTerminal() { | |
127 | return new AWTTerminalFrame( | |
128 | title, | |
129 | initialTerminalSize, | |
130 | deviceConfiguration, | |
131 | fontConfiguration, | |
132 | colorConfiguration, | |
133 | autoCloseTrigger); | |
134 | } | |
135 | ||
136 | public SwingTerminalFrame createSwingTerminal() { | |
137 | return new SwingTerminalFrame( | |
138 | title, | |
139 | initialTerminalSize, | |
140 | deviceConfiguration, | |
141 | fontConfiguration instanceof SwingTerminalFontConfiguration ? (SwingTerminalFontConfiguration)fontConfiguration : null, | |
142 | colorConfiguration, | |
143 | autoCloseTrigger); | |
144 | } | |
145 | ||
146 | private boolean hasSwing() { | |
147 | try { | |
148 | Class.forName("javax.swing.JComponent"); | |
149 | return true; | |
150 | } | |
151 | catch(Exception ignore) { | |
152 | return false; | |
153 | } | |
154 | } | |
155 | ||
156 | /** | |
157 | * Sets a hint to the TerminalFactory of what size to use when creating the terminal. Most terminals are not created | |
158 | * on request but for example the SwingTerminal and SwingTerminalFrame are and this value will be passed down on | |
159 | * creation. | |
160 | * @param initialTerminalSize Size (in rows and columns) of the newly created terminal | |
161 | * @return Reference to itself, so multiple .set-calls can be chained | |
162 | */ | |
163 | public DefaultTerminalFactory setInitialTerminalSize(TerminalSize initialTerminalSize) { | |
164 | this.initialTerminalSize = initialTerminalSize; | |
165 | return this; | |
166 | } | |
167 | ||
168 | /** | |
169 | * Controls whether a SwingTerminalFrame shall always be created if the system is one with a graphical environment | |
170 | * @param forceTextTerminal If true, will always create a text-based Terminal | |
171 | * @return Reference to itself, so multiple .set-calls can be chained | |
172 | */ | |
173 | public DefaultTerminalFactory setForceTextTerminal(boolean forceTextTerminal) { | |
174 | this.forceTextTerminal = forceTextTerminal; | |
175 | return this; | |
176 | } | |
177 | ||
178 | /** | |
179 | * Normally when a graphical terminal emulator is created by the factory, it will create a | |
180 | * {@link SwingTerminalFrame} unless Swing is not present in the system. Setting this property to {@code true} will | |
181 | * make it create an {@link AWTTerminalFrame} even if Swing is present | |
182 | * @param forceAWTOverSwing If {@code true}, will always create an {@link AWTTerminalFrame} over a | |
183 | * {@link SwingTerminalFrame} if asked to create a graphical terminal emulator | |
184 | * @return Reference to itself, so multiple .set-calls can be chained | |
185 | */ | |
186 | public DefaultTerminalFactory setForceAWTOverSwing(boolean forceAWTOverSwing) { | |
187 | this.forceAWTOverSwing = forceAWTOverSwing; | |
188 | return this; | |
189 | } | |
190 | ||
191 | /** | |
192 | * Controls whether a SwingTerminalFrame shall be automatically shown (.setVisible(true)) immediately after | |
193 | * creation. If {@code false}, you will manually need to call {@code .setVisible(true)} on the JFrame to actually | |
194 | * see the terminal window. Default for this value is {@code true}. | |
195 | * @param autoOpenTerminalFrame Automatically open SwingTerminalFrame after creation | |
196 | */ | |
197 | public void setAutoOpenTerminalEmulatorWindow(boolean autoOpenTerminalFrame) { | |
198 | this.autoOpenTerminalFrame = autoOpenTerminalFrame; | |
199 | } | |
200 | ||
201 | /** | |
202 | * Sets the title to use on created SwingTerminalFrames created by this factory | |
203 | * @param title Title to use on created SwingTerminalFrames created by this factory | |
204 | * @return Reference to itself, so multiple .set-calls can be chained | |
205 | */ | |
206 | public DefaultTerminalFactory setTerminalEmulatorTitle(String title) { | |
207 | this.title = title; | |
208 | return this; | |
209 | } | |
210 | ||
211 | /** | |
212 | * Sets the auto-close trigger to use on created SwingTerminalFrames created by this factory | |
213 | * @param autoCloseTrigger Auto-close trigger to use on created SwingTerminalFrames created by this factory | |
214 | * @return Reference to itself, so multiple .set-calls can be chained | |
215 | */ | |
216 | public DefaultTerminalFactory setTerminalEmulatorFrameAutoCloseTrigger(TerminalEmulatorAutoCloseTrigger autoCloseTrigger) { | |
217 | this.autoCloseTrigger = autoCloseTrigger; | |
218 | return this; | |
219 | } | |
220 | ||
221 | /** | |
222 | * Sets the color configuration to use on created SwingTerminalFrames created by this factory | |
223 | * @param colorConfiguration Color configuration to use on created SwingTerminalFrames created by this factory | |
224 | * @return Reference to itself, so multiple .set-calls can be chained | |
225 | */ | |
226 | public DefaultTerminalFactory setTerminalEmulatorColorConfiguration(TerminalEmulatorColorConfiguration colorConfiguration) { | |
227 | this.colorConfiguration = colorConfiguration; | |
228 | return this; | |
229 | } | |
230 | ||
231 | /** | |
232 | * Sets the device configuration to use on created SwingTerminalFrames created by this factory | |
233 | * @param deviceConfiguration Device configuration to use on created SwingTerminalFrames created by this factory | |
234 | * @return Reference to itself, so multiple .set-calls can be chained | |
235 | */ | |
236 | public DefaultTerminalFactory setTerminalEmulatorDeviceConfiguration(TerminalEmulatorDeviceConfiguration deviceConfiguration) { | |
237 | this.deviceConfiguration = deviceConfiguration; | |
238 | return this; | |
239 | } | |
240 | ||
241 | /** | |
242 | * Sets the font configuration to use on created SwingTerminalFrames created by this factory | |
243 | * @param fontConfiguration Font configuration to use on created SwingTerminalFrames created by this factory | |
244 | * @return Reference to itself, so multiple .set-calls can be chained | |
245 | */ | |
246 | public DefaultTerminalFactory setTerminalEmulatorFontConfiguration(AWTTerminalFontConfiguration fontConfiguration) { | |
247 | this.fontConfiguration = fontConfiguration; | |
248 | return this; | |
249 | } | |
250 | ||
251 | /** | |
252 | * Sets the mouse capture mode the terminal should use. Please note that this is an extension which isn't widely | |
253 | * supported! | |
254 | * @param mouseCaptureMode Capture mode for mouse interactions | |
255 | * @return Itself | |
256 | */ | |
257 | public DefaultTerminalFactory setMouseCaptureMode(MouseCaptureMode mouseCaptureMode) { | |
258 | this.mouseCaptureMode = mouseCaptureMode; | |
259 | return this; | |
260 | } | |
261 | ||
262 | private Terminal createCygwinTerminal(OutputStream outputStream, InputStream inputStream, Charset charset) throws IOException { | |
263 | return new CygwinTerminal(inputStream, outputStream, charset); | |
264 | } | |
265 | ||
266 | private Terminal createUnixTerminal(OutputStream outputStream, InputStream inputStream, Charset charset) throws IOException { | |
267 | UnixTerminal unixTerminal = new UnixTerminal(inputStream, outputStream, charset); | |
268 | if(mouseCaptureMode != null) { | |
269 | unixTerminal.setMouseCaptureMode(mouseCaptureMode); | |
270 | } | |
271 | return unixTerminal; | |
272 | } | |
273 | ||
274 | /** | |
275 | * Detects whether the running platform is Windows* by looking at the | |
276 | * operating system name system property | |
277 | */ | |
278 | private static boolean isOperatingSystemWindows() { | |
279 | return System.getProperty("os.name", "").toLowerCase().startsWith("windows"); | |
280 | } | |
281 | } |