0
|
1 //
|
|
2 // Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
|
|
3 //
|
|
4 // This is free software; you can redistribute it and/or modify
|
|
5 // it under the terms of the GNU General Public License as published by
|
|
6 // the Free Software Foundation; either version 2 of the License, or
|
|
7 // (at your option) any later version.
|
|
8 //
|
|
9 // This software 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 General Public License for more details.
|
|
13 //
|
|
14 // You should have received a copy of the GNU General Public License
|
|
15 // along with this software; if not, write to the Free Software
|
|
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
17 // USA.
|
|
18 //
|
|
19
|
|
20 //
|
|
21 // Recording frame. It allows to control recording RFB sessions into
|
|
22 // FBS (FrameBuffer Stream) files.
|
|
23 //
|
|
24
|
|
25 import java.io.*;
|
|
26 import java.awt.*;
|
|
27 import java.awt.event.*;
|
|
28
|
|
29 class RecordingFrame extends Frame
|
|
30 implements WindowListener, ActionListener {
|
|
31
|
|
32 boolean recording;
|
|
33
|
|
34 TextField fnameField;
|
|
35 Button browseButton;
|
|
36
|
|
37 Label statusLabel;
|
|
38
|
|
39 Button recordButton, nextButton, closeButton;
|
|
40 VncViewer viewer;
|
|
41
|
|
42 //
|
|
43 // Check if current security manager allows to create a
|
|
44 // RecordingFrame object.
|
|
45 //
|
|
46
|
|
47 public static boolean checkSecurity() {
|
|
48 SecurityManager security = System.getSecurityManager();
|
|
49 if (security != null) {
|
|
50 try {
|
|
51 security.checkPropertyAccess("user.dir");
|
|
52 security.checkPropertyAccess("file.separator");
|
|
53 // Work around (rare) checkPropertyAccess bug
|
|
54 System.getProperty("user.dir");
|
|
55 } catch (SecurityException e) {
|
|
56 System.out.println("SecurityManager restricts session recording.");
|
|
57 return false;
|
|
58 }
|
|
59 }
|
|
60 return true;
|
|
61 }
|
|
62
|
|
63 //
|
|
64 // Constructor.
|
|
65 //
|
|
66
|
|
67 RecordingFrame(VncViewer v) {
|
|
68 super("TightVNC Session Recording");
|
|
69
|
|
70 viewer = v;
|
|
71
|
|
72 // Determine initial filename for next saved session.
|
|
73 // FIXME: Check SecurityManager.
|
|
74
|
|
75 String fname = nextNewFilename(System.getProperty("user.dir") +
|
|
76 System.getProperty("file.separator") +
|
|
77 "vncsession.fbs");
|
|
78
|
|
79 // Construct new panel with file name field and "Browse" button.
|
|
80
|
|
81 Panel fnamePanel = new Panel();
|
|
82 GridBagLayout fnameGridbag = new GridBagLayout();
|
|
83 fnamePanel.setLayout(fnameGridbag);
|
|
84
|
|
85 GridBagConstraints fnameConstraints = new GridBagConstraints();
|
|
86 fnameConstraints.gridwidth = GridBagConstraints.RELATIVE;
|
|
87 fnameConstraints.fill = GridBagConstraints.BOTH;
|
|
88 fnameConstraints.weightx = 4.0;
|
|
89
|
|
90 fnameField = new TextField(fname, 64);
|
|
91 fnameGridbag.setConstraints(fnameField, fnameConstraints);
|
|
92 fnamePanel.add(fnameField);
|
|
93 fnameField.addActionListener(this);
|
|
94
|
|
95 fnameConstraints.gridwidth = GridBagConstraints.REMAINDER;
|
|
96 fnameConstraints.weightx = 1.0;
|
|
97
|
|
98 browseButton = new Button("Browse");
|
|
99 fnameGridbag.setConstraints(browseButton, fnameConstraints);
|
|
100 fnamePanel.add(browseButton);
|
|
101 browseButton.addActionListener(this);
|
|
102
|
|
103 // Construct the frame.
|
|
104
|
|
105 GridBagLayout gridbag = new GridBagLayout();
|
|
106 setLayout(gridbag);
|
|
107
|
|
108 GridBagConstraints gbc = new GridBagConstraints();
|
|
109 gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
110 gbc.fill = GridBagConstraints.BOTH;
|
|
111 gbc.weighty = 1.0;
|
|
112 gbc.insets = new Insets(10, 0, 0, 0);
|
|
113
|
|
114 Label helpLabel =
|
|
115 new Label("File name to save next recorded session in:", Label.CENTER);
|
|
116 gridbag.setConstraints(helpLabel, gbc);
|
|
117 add(helpLabel);
|
|
118
|
|
119 gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
120 gbc.weighty = 0.0;
|
|
121 gbc.insets = new Insets(0, 0, 0, 0);
|
|
122
|
|
123 gridbag.setConstraints(fnamePanel, gbc);
|
|
124 add(fnamePanel);
|
|
125
|
|
126 gbc.fill = GridBagConstraints.BOTH;
|
|
127 gbc.weighty = 1.0;
|
|
128 gbc.insets = new Insets(10, 0, 10, 0);
|
|
129
|
|
130 statusLabel = new Label("", Label.CENTER);
|
|
131 gridbag.setConstraints(statusLabel, gbc);
|
|
132 add(statusLabel);
|
|
133
|
|
134 gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
135 gbc.weightx = 1.0;
|
|
136 gbc.weighty = 0.0;
|
|
137 gbc.gridwidth = 1;
|
|
138 gbc.insets = new Insets(0, 0, 0, 0);
|
|
139
|
|
140 recordButton = new Button("Record");
|
|
141 gridbag.setConstraints(recordButton, gbc);
|
|
142 add(recordButton);
|
|
143 recordButton.addActionListener(this);
|
|
144
|
|
145 nextButton = new Button("Next file");
|
|
146 gridbag.setConstraints(nextButton, gbc);
|
|
147 add(nextButton);
|
|
148 nextButton.addActionListener(this);
|
|
149
|
|
150 closeButton = new Button("Close");
|
|
151 gridbag.setConstraints(closeButton, gbc);
|
|
152 add(closeButton);
|
|
153 closeButton.addActionListener(this);
|
|
154
|
|
155 // Set correct text, font and color for the statusLabel.
|
|
156 stopRecording();
|
|
157
|
|
158 pack();
|
|
159
|
|
160 addWindowListener(this);
|
|
161 }
|
|
162
|
|
163 //
|
|
164 // If the given string ends with ".NNN" where NNN is a decimal
|
|
165 // number, increase this number by one. Otherwise, append ".001"
|
|
166 // to the given string.
|
|
167 //
|
|
168
|
|
169 protected String nextFilename(String fname) {
|
|
170 int len = fname.length();
|
|
171 int suffixPos = len;
|
|
172 int suffixNum = 1;
|
|
173
|
|
174 if (len > 4 && fname.charAt(len - 4) == '.') {
|
|
175 try {
|
|
176 suffixNum = Integer.parseInt(fname.substring(len - 3, len)) + 1;
|
|
177 suffixPos = len - 4;
|
|
178 } catch (NumberFormatException e) { }
|
|
179 }
|
|
180
|
|
181 char[] zeroes = {'0', '0', '0'};
|
|
182 String suffix = String.valueOf(suffixNum);
|
|
183 if (suffix.length() < 3) {
|
|
184 suffix = new String(zeroes, 0, 3 - suffix.length()) + suffix;
|
|
185 }
|
|
186
|
|
187 return fname.substring(0, suffixPos) + '.' + suffix;
|
|
188 }
|
|
189
|
|
190 //
|
|
191 // Find next name of a file which does not exist yet.
|
|
192 //
|
|
193
|
|
194 protected String nextNewFilename(String fname) {
|
|
195 String newName = fname;
|
|
196 File f;
|
|
197 try {
|
|
198 do {
|
|
199 newName = nextFilename(newName);
|
|
200 f = new File(newName);
|
|
201 } while (f.exists());
|
|
202 } catch (SecurityException e) { }
|
|
203
|
|
204 return newName;
|
|
205 }
|
|
206
|
|
207 //
|
|
208 // Let the user choose a file name showing a FileDialog.
|
|
209 //
|
|
210
|
|
211 protected boolean browseFile() {
|
|
212 File currentFile = new File(fnameField.getText());
|
|
213
|
|
214 FileDialog fd =
|
|
215 new FileDialog(this, "Save next session as...", FileDialog.SAVE);
|
|
216 fd.setDirectory(currentFile.getParent());
|
|
217 fd.setVisible(true);
|
|
218 if (fd.getFile() != null) {
|
|
219 String newDir = fd.getDirectory();
|
|
220 String sep = System.getProperty("file.separator");
|
|
221 if (newDir.length() > 0) {
|
|
222 if (!sep.equals(newDir.substring(newDir.length() - sep.length())))
|
|
223 newDir += sep;
|
|
224 }
|
|
225 String newFname = newDir + fd.getFile();
|
|
226 if (newFname.equals(fnameField.getText())) {
|
|
227 fnameField.setText(newFname);
|
|
228 return true;
|
|
229 }
|
|
230 }
|
|
231 return false;
|
|
232 }
|
|
233
|
|
234 //
|
|
235 // Start recording.
|
|
236 //
|
|
237
|
|
238 public void startRecording() {
|
|
239 statusLabel.setText("Status: Recording...");
|
|
240 statusLabel.setFont(new Font("Helvetica", Font.BOLD, 12));
|
|
241 statusLabel.setForeground(Color.red);
|
|
242 recordButton.setLabel("Stop recording");
|
|
243
|
|
244 recording = true;
|
|
245
|
|
246 viewer.setRecordingStatus(fnameField.getText());
|
|
247 }
|
|
248
|
|
249 //
|
|
250 // Stop recording.
|
|
251 //
|
|
252
|
|
253 public void stopRecording() {
|
|
254 statusLabel.setText("Status: Not recording.");
|
|
255 statusLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
|
|
256 statusLabel.setForeground(Color.black);
|
|
257 recordButton.setLabel("Record");
|
|
258
|
|
259 recording = false;
|
|
260
|
|
261 viewer.setRecordingStatus(null);
|
|
262 }
|
|
263
|
|
264 //
|
|
265 // Close our window properly.
|
|
266 //
|
|
267
|
|
268 public void windowClosing(WindowEvent evt) {
|
|
269 setVisible(false);
|
|
270 }
|
|
271
|
|
272 //
|
|
273 // Ignore window events we're not interested in.
|
|
274 //
|
|
275
|
|
276 public void windowActivated(WindowEvent evt) {}
|
|
277 public void windowDeactivated (WindowEvent evt) {}
|
|
278 public void windowOpened(WindowEvent evt) {}
|
|
279 public void windowClosed(WindowEvent evt) {}
|
|
280 public void windowIconified(WindowEvent evt) {}
|
|
281 public void windowDeiconified(WindowEvent evt) {}
|
|
282
|
|
283
|
|
284 //
|
|
285 // Respond to button presses
|
|
286 //
|
|
287
|
|
288 public void actionPerformed(ActionEvent evt) {
|
|
289 if (evt.getSource() == browseButton) {
|
|
290 if (browseFile() && recording)
|
|
291 startRecording();
|
|
292
|
|
293 } else if (evt.getSource() == recordButton) {
|
|
294 if (!recording) {
|
|
295 startRecording();
|
|
296 } else {
|
|
297 stopRecording();
|
|
298 fnameField.setText(nextNewFilename(fnameField.getText()));
|
|
299 }
|
|
300
|
|
301 } else if (evt.getSource() == nextButton) {
|
|
302 fnameField.setText(nextNewFilename(fnameField.getText()));
|
|
303 if (recording)
|
|
304 startRecording();
|
|
305
|
|
306 } else if (evt.getSource() == closeButton) {
|
|
307 setVisible(false);
|
|
308
|
|
309 }
|
|
310 }
|
|
311 }
|