2 // Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
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.
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.
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,
21 // Recording frame. It allows to control recording RFB sessions into
22 // FBS (FrameBuffer Stream) files.
27 import java.awt.event.*;
29 class RecordingFrame extends Frame
30 implements WindowListener, ActionListener {
39 Button recordButton, nextButton, closeButton;
43 // Check if current security manager allows to create a
44 // RecordingFrame object.
47 public static boolean checkSecurity() {
48 SecurityManager security = System.getSecurityManager();
49 if (security != null) {
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.");
67 RecordingFrame(VncViewer v) {
68 super("TightVNC Session Recording");
72 // Determine initial filename for next saved session.
73 // FIXME: Check SecurityManager.
75 String fname = nextNewFilename(System.getProperty("user.dir") +
76 System.getProperty("file.separator") +
79 // Construct new panel with file name field and "Browse" button.
81 Panel fnamePanel = new Panel();
82 GridBagLayout fnameGridbag = new GridBagLayout();
83 fnamePanel.setLayout(fnameGridbag);
85 GridBagConstraints fnameConstraints = new GridBagConstraints();
86 fnameConstraints.gridwidth = GridBagConstraints.RELATIVE;
87 fnameConstraints.fill = GridBagConstraints.BOTH;
88 fnameConstraints.weightx = 4.0;
90 fnameField = new TextField(fname, 64);
91 fnameGridbag.setConstraints(fnameField, fnameConstraints);
92 fnamePanel.add(fnameField);
93 fnameField.addActionListener(this);
95 fnameConstraints.gridwidth = GridBagConstraints.REMAINDER;
96 fnameConstraints.weightx = 1.0;
98 browseButton = new Button("Browse");
99 fnameGridbag.setConstraints(browseButton, fnameConstraints);
100 fnamePanel.add(browseButton);
101 browseButton.addActionListener(this);
103 // Construct the frame.
105 GridBagLayout gridbag = new GridBagLayout();
108 GridBagConstraints gbc = new GridBagConstraints();
109 gbc.gridwidth = GridBagConstraints.REMAINDER;
110 gbc.fill = GridBagConstraints.BOTH;
112 gbc.insets = new Insets(10, 0, 0, 0);
115 new Label("File name to save next recorded session in:", Label.CENTER);
116 gridbag.setConstraints(helpLabel, gbc);
119 gbc.fill = GridBagConstraints.HORIZONTAL;
121 gbc.insets = new Insets(0, 0, 0, 0);
123 gridbag.setConstraints(fnamePanel, gbc);
126 gbc.fill = GridBagConstraints.BOTH;
128 gbc.insets = new Insets(10, 0, 10, 0);
130 statusLabel = new Label("", Label.CENTER);
131 gridbag.setConstraints(statusLabel, gbc);
134 gbc.fill = GridBagConstraints.HORIZONTAL;
138 gbc.insets = new Insets(0, 0, 0, 0);
140 recordButton = new Button("Record");
141 gridbag.setConstraints(recordButton, gbc);
143 recordButton.addActionListener(this);
145 nextButton = new Button("Next file");
146 gridbag.setConstraints(nextButton, gbc);
148 nextButton.addActionListener(this);
150 closeButton = new Button("Close");
151 gridbag.setConstraints(closeButton, gbc);
153 closeButton.addActionListener(this);
155 // Set correct text, font and color for the statusLabel.
160 addWindowListener(this);
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.
169 protected String nextFilename(String fname) {
170 int len = fname.length();
174 if (len > 4 && fname.charAt(len - 4) == '.') {
176 suffixNum = Integer.parseInt(fname.substring(len - 3, len)) + 1;
178 } catch (NumberFormatException e) { }
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;
187 return fname.substring(0, suffixPos) + '.' + suffix;
191 // Find next name of a file which does not exist yet.
194 protected String nextNewFilename(String fname) {
195 String newName = fname;
199 newName = nextFilename(newName);
200 f = new File(newName);
201 } while (f.exists());
202 } catch (SecurityException e) { }
208 // Let the user choose a file name showing a FileDialog.
211 protected boolean browseFile() {
212 File currentFile = new File(fnameField.getText());
215 new FileDialog(this, "Save next session as...", FileDialog.SAVE);
216 fd.setDirectory(currentFile.getParent());
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())))
225 String newFname = newDir + fd.getFile();
226 if (newFname.equals(fnameField.getText())) {
227 fnameField.setText(newFname);
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");
246 viewer.setRecordingStatus(fnameField.getText());
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");
261 viewer.setRecordingStatus(null);
265 // Close our window properly.
268 public void windowClosing(WindowEvent evt) {
273 // Ignore window events we're not interested in.
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) {}
285 // Respond to button presses
288 public void actionPerformed(ActionEvent evt) {
289 if (evt.getSource() == browseButton) {
290 if (browseFile() && recording)
293 } else if (evt.getSource() == recordButton) {
298 fnameField.setText(nextNewFilename(fnameField.getText()));
301 } else if (evt.getSource() == nextButton) {
302 fnameField.setText(nextNewFilename(fnameField.getText()));
306 } else if (evt.getSource() == closeButton) {