undo previous commit and redo it properly via a patch file instead of
[invirt/packages/invirt-vnc-client.git] / RecordingFrame.java
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 }