~soylent-tv/screenstudio/screenstudiogit

« back to all changes in this revision

Viewing changes to src/screenstudio/gui/ScreenStudio.java

  • Committer: Karl Ellis
  • Author(s): Patrick Balleux
  • Date: 2016-09-04 06:26:14 UTC
  • Revision ID: git-v1:8539b9552bec3c9aa82b39f695a6958885b15095
Update sources to ScreenStudio 3.0.3
See https://github.com/patrickballeux/screenstudio

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2016 patrick
 
3
 *
 
4
 * This program 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 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 General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
 */
 
17
package screenstudio.gui;
 
18
 
 
19
import java.awt.AWTException;
 
20
import java.awt.BorderLayout;
 
21
import java.awt.Rectangle;
 
22
import java.awt.SystemTray;
 
23
import java.awt.TrayIcon;
 
24
import java.awt.event.ActionEvent;
 
25
import java.io.File;
 
26
import java.io.IOException;
 
27
import java.util.List;
 
28
import java.util.logging.Level;
 
29
import java.util.logging.Logger;
 
30
import java.util.prefs.BackingStoreException;
 
31
import javax.swing.DefaultComboBoxModel;
 
32
import javax.swing.ImageIcon;
 
33
import javax.swing.JFileChooser;
 
34
import javax.swing.JFrame;
 
35
import javax.swing.JMenuItem;
 
36
import javax.swing.ToolTipManager;
 
37
import javax.swing.filechooser.FileFilter;
 
38
import javax.swing.table.DefaultTableModel;
 
39
import javax.xml.parsers.ParserConfigurationException;
 
40
import org.xml.sax.SAXException;
 
41
import screenstudio.Version;
 
42
import screenstudio.encoder.FFMpeg;
 
43
import screenstudio.panel.editor.Editor;
 
44
import screenstudio.sources.Compositor;
 
45
import screenstudio.sources.Microphone;
 
46
import screenstudio.sources.Screen;
 
47
import screenstudio.sources.Source;
 
48
import screenstudio.sources.Webcam;
 
49
import screenstudio.targets.Layout;
 
50
import screenstudio.targets.Layout.SourceType;
 
51
 
 
52
/**
 
53
 *
 
54
 * @author patrick
 
55
 */
 
56
public class ScreenStudio extends javax.swing.JFrame {
 
57
 
 
58
    private final SourceLayoutPreview mLayoutPreview;
 
59
    private FFMpeg mFFMpeg = null;
 
60
    private File mVideoOutputFolder = new File(System.getProperty("user.home"));
 
61
    private long mRecordingTimestamp = 0;
 
62
    private java.awt.TrayIcon trayIcon;
 
63
 
 
64
    /**
 
65
     * Creates new form MainVersion3
 
66
     */
 
67
    public ScreenStudio() {
 
68
        initComponents();
 
69
        this.setIconImage(new ImageIcon(ScreenStudio.class.getResource("/screenstudio/gui/images/icon.png")).getImage());
 
70
        initControls();
 
71
        mLayoutPreview = new SourceLayoutPreview(tableSources);
 
72
        mLayoutPreview.setOutputWidth((Integer) spinWidth.getValue());
 
73
        mLayoutPreview.setOutputHeight((Integer) spinHeight.getValue());
 
74
        panPreviewLayout.add(mLayoutPreview, BorderLayout.CENTER);
 
75
        this.setTitle("ScreenStudio " + screenstudio.Version.MAIN);
 
76
        this.setSize(700, 400);
 
77
        ToolTipManager.sharedInstance().setDismissDelay(8000);
 
78
        ToolTipManager.sharedInstance().setInitialDelay(2000);
 
79
        new Thread(() -> {
 
80
            if (Version.hasNewVersion()) {
 
81
                lblMessages.setText("A new version is available...");
 
82
            }
 
83
        }).start();
 
84
    }
 
85
 
 
86
    private void initControls() {
 
87
        DefaultTableModel model = (DefaultTableModel) tableSources.getModel();
 
88
        while (model.getRowCount() > 0) {
 
89
            model.removeRow(0);
 
90
        }
 
91
        cboTarget.setModel(new DefaultComboBoxModel<>(FFMpeg.FORMATS.values()));
 
92
        cboTarget.setSelectedIndex(0);
 
93
        cboVideoPresets.setModel(new DefaultComboBoxModel<>(FFMpeg.Presets.values()));
 
94
        cboAudioBitrate.setModel(new DefaultComboBoxModel<>(FFMpeg.AudioRate.values()));
 
95
        cboRTMPServers.setModel(new DefaultComboBoxModel<>());
 
96
        txtRTMPKey.setText((""));
 
97
        try {
 
98
            cboAudioMicrophones.setModel(new DefaultComboBoxModel());
 
99
            cboAudioSystems.setModel(new DefaultComboBoxModel());
 
100
            cboAudioMicrophones.addItem(new Microphone());
 
101
            cboAudioSystems.addItem(new Microphone());
 
102
            for (Microphone o : Microphone.getSources()) {
 
103
                if (o.getDescription().toLowerCase().contains("monitor")) {
 
104
                    cboAudioSystems.addItem(o);
 
105
                } else {
 
106
                    cboAudioMicrophones.addItem(o);
 
107
                }
 
108
            }
 
109
        } catch (IOException | InterruptedException ex) {
 
110
 
 
111
        }
 
112
        setRTMPControls((FFMpeg.FORMATS) cboTarget.getSelectedItem());
 
113
        int defaultWidth = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode().getWidth();
 
114
        int defaultHeight = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode().getHeight();
 
115
        spinWidth.setValue(defaultWidth);
 
116
        spinHeight.setValue(defaultHeight);
 
117
        lblVideoFolder.setText(mVideoOutputFolder.getAbsolutePath());
 
118
        lblVideoFolder.setToolTipText(mVideoOutputFolder.getAbsolutePath());
 
119
        updateMenuWebcams();
 
120
        updateMenuDesktops();
 
121
        // get audio sync
 
122
        java.util.prefs.Preferences p = java.util.prefs.Preferences.userRoot().node("screenstudio");
 
123
        spinAudioDelay.setValue(p.getFloat("audiodelay", 0));
 
124
 
 
125
        if (SystemTray.isSupported()) {
 
126
            trayIcon = new TrayIcon(this.getIconImage(), "ScreenStudio: Double-click to activate recording...");
 
127
            if (Screen.isOSX()) {
 
128
                trayIcon.setToolTip("ScreenStudio: CTRL-Click to activate recording...");
 
129
            }
 
130
            trayIcon.setImageAutoSize(true);
 
131
            trayIcon.addActionListener((ActionEvent e) -> {
 
132
                mnuCapture.doClick();
 
133
            });
 
134
            try {
 
135
                SystemTray.getSystemTray().add(trayIcon);
 
136
            } catch (AWTException ex) {
 
137
                Logger.getLogger(ScreenStudio.class.getName()).log(Level.SEVERE, null, ex);
 
138
            }
 
139
 
 
140
        } else {
 
141
            trayIcon = null;
 
142
        }
 
143
 
 
144
    }
 
145
 
 
146
    private void updateControls(boolean enabled) {
 
147
 
 
148
        cboTarget.setEnabled(enabled);
 
149
        cboVideoPresets.setEnabled(enabled);
 
150
        cboAudioBitrate.setEnabled(enabled);
 
151
        cboRTMPServers.setEnabled(enabled);
 
152
        txtRTMPKey.setEnabled(enabled);
 
153
        cboAudioMicrophones.setEnabled(enabled);
 
154
        cboAudioSystems.setEnabled(enabled);
 
155
        cboAudioMicrophones.setEnabled(enabled);
 
156
        cboAudioSystems.setEnabled(enabled);
 
157
        txtRTMPKey.setEnabled(enabled);
 
158
        cboRTMPServers.setEnabled(enabled);
 
159
        spinWidth.setEnabled(enabled);
 
160
        spinHeight.setEnabled(enabled);
 
161
        numVideoBitrate.setEnabled(enabled);
 
162
        spinFPS.setEnabled(enabled);
 
163
        btnSetVideoFolder.setEnabled(enabled);
 
164
        mnuFileLoad.setEnabled(enabled);
 
165
        mnuFileSave.setEnabled(enabled);
 
166
    }
 
167
 
 
168
    private void loadLayout(File file) {
 
169
        Layout layout = new Layout();
 
170
        try {
 
171
            layout.load(file);
 
172
            cboAudioBitrate.setSelectedItem(layout.getAudioBitrate());
 
173
            for (int i = 0; i < cboAudioMicrophones.getItemCount(); i++) {
 
174
                if (cboAudioMicrophones.getItemAt(i).getDescription().equals(layout.getAudioMicrophone())) {
 
175
                    cboAudioMicrophones.setSelectedIndex(i);
 
176
                    break;
 
177
                }
 
178
            }
 
179
            for (int i = 0; i < cboAudioSystems.getItemCount(); i++) {
 
180
                if (cboAudioSystems.getItemAt(i).getDescription().equals(layout.getAudioSystem())) {
 
181
                    cboAudioSystems.setSelectedIndex(i);
 
182
                    break;
 
183
                }
 
184
            }
 
185
            spinFPS.setValue(layout.getOutputFramerate());
 
186
            spinHeight.setValue(layout.getOutputHeight());
 
187
            cboVideoPresets.setSelectedItem(layout.getOutputPreset());
 
188
            cboTarget.setSelectedItem(layout.getOutputTarget());
 
189
            txtRTMPKey.setText(layout.getOutputRTMPKey());
 
190
            cboRTMPServers.setSelectedItem(layout.getOutputRTMPServer());
 
191
            mVideoOutputFolder = layout.getOutputVideoFolder();
 
192
            lblVideoFolder.setText(mVideoOutputFolder.getAbsolutePath());
 
193
            lblVideoFolder.setToolTipText(mVideoOutputFolder.getAbsolutePath());
 
194
            spinWidth.setValue(layout.getOutputWidth());
 
195
            numVideoBitrate.setValue(layout.getVideoBitrate());
 
196
 
 
197
            // load sources...
 
198
            DefaultTableModel model = (DefaultTableModel) tableSources.getModel();
 
199
            while (model.getRowCount() > 0) {
 
200
                model.removeRow(0);
 
201
            }
 
202
            Screen[] screens = Screen.getSources();
 
203
            Webcam[] webcams = Webcam.getSources();
 
204
            for (screenstudio.targets.Source s : layout.getSources()) {
 
205
                Object[] row = new Object[model.getColumnCount()];
 
206
                row[0] = true;
 
207
                row[1] = s.Type;
 
208
                row[2] = "Not found!";
 
209
                row[3] = s.X;
 
210
                row[4] = s.Y;
 
211
                row[5] = s.Width;
 
212
                row[6] = s.Height;
 
213
                row[7] = s.Alpha;
 
214
                switch (s.Type) {
 
215
                    case Desktop:
 
216
                        row[0] = false;
 
217
                        for (Screen screen : screens) {
 
218
                            if (screen.getLabel().equals(s.ID)) {
 
219
                                row[2] = screen;
 
220
                                row[0] = true;
 
221
                                break;
 
222
                            }
 
223
                        }
 
224
                        break;
 
225
                    case Image:
 
226
                        row[2] = new File(s.ID);
 
227
                        row[0] = new File(s.ID).exists();
 
228
                        break;
 
229
                    case LabelFile:
 
230
                        row[2] = new File(s.ID);
 
231
                        row[0] = new File(s.ID).exists();
 
232
                        break;
 
233
                    case LabelText:
 
234
                        LabelText t = new LabelText(s.ID);
 
235
                        t.setForegroundColor(s.foregroundColor);
 
236
                        t.setBackgroundColor(s.backgroundColor);
 
237
                        t.setFontName(s.fontName);
 
238
                        System.out.println("Font: " + s.fontName);
 
239
                        row[2] = t;
 
240
                        break;
 
241
                    case Stream:
 
242
                        row[2] = s.ID;
 
243
                        break;
 
244
                    case Video:
 
245
                        row[2] = new File(s.ID);
 
246
                        row[0] = new File(s.ID).exists();
 
247
                        break;
 
248
                    case Webcam:
 
249
                        row[0] = false;
 
250
                        for (Webcam webcam : webcams) {
 
251
                            if (webcam.getDevice().equals(s.ID)) {
 
252
                                row[2] = webcam;
 
253
                                row[0] = true;
 
254
                                break;
 
255
                            }
 
256
                        }
 
257
                        break;
 
258
                }
 
259
                model.addRow(row);
 
260
            }
 
261
        } catch (IOException | ParserConfigurationException | SAXException | InterruptedException ex) {
 
262
            Logger.getLogger(ScreenStudio.class.getName()).log(Level.SEVERE, null, ex);
 
263
        }
 
264
 
 
265
        panPreviewLayout.repaint();
 
266
    }
 
267
 
 
268
    private void saveLayout(File file) {
 
269
        Layout layout = new Layout();
 
270
        layout.setAudioBitrate(cboAudioBitrate.getItemAt(cboAudioBitrate.getSelectedIndex()));
 
271
        layout.setAudioMicrophone(cboAudioMicrophones.getItemAt(cboAudioMicrophones.getSelectedIndex()).getDescription());
 
272
        layout.setAudioSystem(cboAudioSystems.getItemAt(cboAudioSystems.getSelectedIndex()).getDescription());
 
273
        layout.setOutputFramerate((Integer) spinFPS.getValue());
 
274
        layout.setOutputHeight((Integer) spinHeight.getValue());
 
275
        layout.setOutputPreset(cboVideoPresets.getItemAt(cboVideoPresets.getSelectedIndex()));
 
276
        layout.setOutputRTMPKey(txtRTMPKey.getText());
 
277
        if (cboRTMPServers.getSelectedIndex() != -1) {
 
278
            layout.setOutputRTMPServer(cboRTMPServers.getSelectedItem().toString());
 
279
        } else {
 
280
            layout.setOutputRTMPServer("");
 
281
        }
 
282
        layout.setOutputTarget(cboTarget.getItemAt(cboTarget.getSelectedIndex()));
 
283
        layout.setOutputVideoFolder(mVideoOutputFolder);
 
284
        layout.setOutputWith((Integer) spinWidth.getValue());
 
285
        layout.setVideoBitrate((Integer) numVideoBitrate.getValue());
 
286
 
 
287
        List<Source> sources = Compositor.getSources(tableSources, (Integer) spinFPS.getValue());
 
288
        for (Source s : sources) {
 
289
            layout.addSource(s.getType(), s.getID(), s.getBounds().x, s.getBounds().y, s.getBounds().width, s.getBounds().height, s.getAlpha().getAlpha(), s.getZOrder(), s.getForeground(), s.getBackground(),s.getFontName());
 
290
        }
 
291
        try {
 
292
            layout.save(file);
 
293
        } catch (Exception ex) {
 
294
            Logger.getLogger(ScreenStudio.class.getName()).log(Level.SEVERE, null, ex);
 
295
        }
 
296
    }
 
297
 
 
298
    private void setRTMPControls(FFMpeg.FORMATS value) {
 
299
        if (value != null) {
 
300
            switch (value) {
 
301
                case BROADCAST:
 
302
                case MOV:
 
303
                case MP4:
 
304
                case FLV:
 
305
                case TS:
 
306
                    cboRTMPServers.setModel(new DefaultComboBoxModel());
 
307
                    txtRTMPKey.setText((""));
 
308
                    cboRTMPServers.setVisible(false);
 
309
                    txtRTMPKey.setVisible(false);
 
310
                    lblRTMPKey.setVisible(false);
 
311
                    lblRTMPServer.setVisible(false);
 
312
                    break;
 
313
                case HITBOX:
 
314
                case RTMP:
 
315
                case TWITCH:
 
316
                case USTREAM:
 
317
                case VAUGHNLIVE:
 
318
                case YOUTUBE:
 
319
                    cboRTMPServers.setModel(new DefaultComboBoxModel(FFMpeg.getServerList(value)));
 
320
                    txtRTMPKey.setText((""));
 
321
                    cboRTMPServers.setVisible(true);
 
322
                    txtRTMPKey.setVisible(true);
 
323
                    lblRTMPKey.setVisible(true);
 
324
                    lblRTMPServer.setVisible(true);
 
325
                    break;
 
326
            }
 
327
        }
 
328
    }
 
329
 
 
330
    private void updateMenuWebcams() {
 
331
 
 
332
        mnuMainWebcams.removeAll();
 
333
        try {
 
334
            for (Webcam w : Webcam.getSources()) {
 
335
                JMenuItem menu = new JMenuItem(w.getDescription());
 
336
                menu.setActionCommand(w.getDevice());
 
337
                menu.setToolTipText("Device: " + w.getDevice());
 
338
                menu.addActionListener((ActionEvent e) -> {
 
339
                    DefaultTableModel model = (DefaultTableModel) tableSources.getModel();
 
340
                    Object[] row = new Object[model.getColumnCount()];
 
341
                    try {
 
342
                        for (Webcam webcam : Webcam.getSources()) {
 
343
                            if (webcam.getDevice().equals(e.getActionCommand())) {
 
344
                                row[0] = true;
 
345
                                row[1] = SourceType.Webcam;
 
346
                                row[2] = webcam;
 
347
                                row[3] = 0;
 
348
                                row[4] = 0;
 
349
                                row[5] = webcam.getWidth();
 
350
                                row[6] = webcam.getHeight();
 
351
                                row[7] = 1;
 
352
                                model.addRow(row);
 
353
                                mLayoutPreview.repaint();
 
354
                                tabs.setSelectedComponent(panSources);
 
355
                                break;
 
356
 
 
357
                            }
 
358
                        }
 
359
                    } catch (IOException | InterruptedException ex) {
 
360
                        Logger.getLogger(ScreenStudio.class.getName()).log(Level.SEVERE, null, ex);
 
361
                    }
 
362
                });
 
363
 
 
364
                mnuMainWebcams.add(menu);
 
365
            }
 
366
        } catch (IOException | InterruptedException ex) {
 
367
            Logger.getLogger(ScreenStudio.class.getName()).log(Level.SEVERE, null, ex);
 
368
        }
 
369
    }
 
370
 
 
371
    private void updateMenuDesktops() {
 
372
 
 
373
        mnuMainDestops.removeAll();
 
374
        try {
 
375
            for (Screen s : Screen.getSources()) {
 
376
                JMenuItem menu = new JMenuItem(s.getDetailledLabel());
 
377
                menu.setActionCommand(s.getLabel());
 
378
                menu.setToolTipText("Size: " + s.getDetailledLabel());
 
379
                menu.addActionListener((ActionEvent e) -> {
 
380
                    DefaultTableModel model = (DefaultTableModel) tableSources.getModel();
 
381
                    Object[] row = new Object[model.getColumnCount()];
 
382
                    try {
 
383
                        for (Screen screen : Screen.getSources()) {
 
384
                            if (screen.getLabel().equals(e.getActionCommand())) {
 
385
                                row[0] = true;
 
386
                                row[1] = SourceType.Desktop;
 
387
                                row[2] = screen;
 
388
                                row[3] = 0;
 
389
                                row[4] = 0;
 
390
                                row[5] = screen.getWidth();
 
391
                                row[6] = screen.getHeight();
 
392
                                row[7] = 1;
 
393
                                model.addRow(row);
 
394
                                mLayoutPreview.repaint();
 
395
                                tabs.setSelectedComponent(panSources);
 
396
                                break;
 
397
                            }
 
398
 
 
399
                        }
 
400
                    } catch (IOException | InterruptedException ex) {
 
401
                        Logger.getLogger(ScreenStudio.class.getName()).log(Level.SEVERE, null, ex);
 
402
                    }
 
403
                });
 
404
 
 
405
                mnuMainDestops.add(menu);
 
406
            }
 
407
        } catch (IOException | InterruptedException ex) {
 
408
            Logger.getLogger(ScreenStudio.class.getName()).log(Level.SEVERE, null, ex);
 
409
        }
 
410
    }
 
411
 
 
412
    /**
 
413
     * This method is called from within the constructor to initialize the form.
 
414
     * WARNING: Do NOT modify this code. The content of this method is always
 
415
     * regenerated by the Form Editor.
 
416
     */
 
417
    @SuppressWarnings("unchecked")
 
418
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
 
419
    private void initComponents() {
 
420
 
 
421
        tabs = new javax.swing.JTabbedPane();
 
422
        panOutput = new javax.swing.JPanel();
 
423
        jLabel1 = new javax.swing.JLabel();
 
424
        spinWidth = new javax.swing.JSpinner();
 
425
        spinHeight = new javax.swing.JSpinner();
 
426
        jLabel2 = new javax.swing.JLabel();
 
427
        jLabel3 = new javax.swing.JLabel();
 
428
        spinFPS = new javax.swing.JSpinner();
 
429
        jLabel4 = new javax.swing.JLabel();
 
430
        cboTarget = new javax.swing.JComboBox<>();
 
431
        panTargetSettings = new javax.swing.JPanel();
 
432
        jLabel5 = new javax.swing.JLabel();
 
433
        jLabel6 = new javax.swing.JLabel();
 
434
        jLabel7 = new javax.swing.JLabel();
 
435
        lblRTMPServer = new javax.swing.JLabel();
 
436
        lblRTMPKey = new javax.swing.JLabel();
 
437
        numVideoBitrate = new javax.swing.JSpinner();
 
438
        cboVideoPresets = new javax.swing.JComboBox<>();
 
439
        cboAudioBitrate = new javax.swing.JComboBox<>();
 
440
        cboRTMPServers = new javax.swing.JComboBox<>();
 
441
        txtRTMPKey = new javax.swing.JTextField();
 
442
        panSources = new javax.swing.JPanel();
 
443
        jSplitPane1 = new javax.swing.JSplitPane();
 
444
        panPreviewLayout = new javax.swing.JPanel();
 
445
        scrollSources = new javax.swing.JScrollPane();
 
446
        tableSources = new javax.swing.JTable();
 
447
        panOptions = new javax.swing.JPanel();
 
448
        panSettingsAudios = new javax.swing.JPanel();
 
449
        jLabel8 = new javax.swing.JLabel();
 
450
        jLabel9 = new javax.swing.JLabel();
 
451
        cboAudioMicrophones = new javax.swing.JComboBox<>();
 
452
        cboAudioSystems = new javax.swing.JComboBox<>();
 
453
        jLabel10 = new javax.swing.JLabel();
 
454
        spinAudioDelay = new javax.swing.JSpinner();
 
455
        panSettingsVideos = new javax.swing.JPanel();
 
456
        lblVideoFolder = new javax.swing.JLabel();
 
457
        btnSetVideoFolder = new javax.swing.JButton();
 
458
        panSettingsMisc = new javax.swing.JPanel();
 
459
        chkStayVisible = new javax.swing.JCheckBox();
 
460
        panStatus = new javax.swing.JPanel();
 
461
        lblMessages = new javax.swing.JLabel();
 
462
        menuBar = new javax.swing.JMenuBar();
 
463
        mnuFile = new javax.swing.JMenu();
 
464
        mnuCapture = new javax.swing.JMenuItem();
 
465
        jSeparator1 = new javax.swing.JPopupMenu.Separator();
 
466
        mnuFileLoad = new javax.swing.JMenuItem();
 
467
        mnuFileSave = new javax.swing.JMenuItem();
 
468
        mnuEdit = new javax.swing.JMenu();
 
469
        mnuMainWebcams = new javax.swing.JMenu();
 
470
        mnuMainDestops = new javax.swing.JMenu();
 
471
        mnuMainAddImage = new javax.swing.JMenuItem();
 
472
        mnuMainAddLabel = new javax.swing.JMenuItem();
 
473
        jSeparator3 = new javax.swing.JPopupMenu.Separator();
 
474
        mnuMainMoveUp = new javax.swing.JMenuItem();
 
475
        mnuMainMoveDown = new javax.swing.JMenuItem();
 
476
        jSeparator2 = new javax.swing.JPopupMenu.Separator();
 
477
        mnuMainRemove = new javax.swing.JMenuItem();
 
478
 
 
479
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
 
480
        setTitle("ScreenStudio");
 
481
        addWindowStateListener(new java.awt.event.WindowStateListener() {
 
482
            public void windowStateChanged(java.awt.event.WindowEvent evt) {
 
483
                formWindowStateChanged(evt);
 
484
            }
 
485
        });
 
486
        addWindowListener(new java.awt.event.WindowAdapter() {
 
487
            public void windowClosing(java.awt.event.WindowEvent evt) {
 
488
                formWindowClosing(evt);
 
489
            }
 
490
        });
 
491
 
 
492
        jLabel1.setText("Output Format");
 
493
 
 
494
        spinWidth.setModel(new javax.swing.SpinnerNumberModel(720, 640, 1920, 1));
 
495
        spinWidth.addChangeListener(new javax.swing.event.ChangeListener() {
 
496
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
 
497
                spinWidthStateChanged(evt);
 
498
            }
 
499
        });
 
500
 
 
501
        spinHeight.setModel(new javax.swing.SpinnerNumberModel(480, 240, 1080, 1));
 
502
        spinHeight.addChangeListener(new javax.swing.event.ChangeListener() {
 
503
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
 
504
                spinHeightStateChanged(evt);
 
505
            }
 
506
        });
 
507
 
 
508
        jLabel2.setText("X");
 
509
 
 
510
        jLabel3.setText("Framerate");
 
511
 
 
512
        spinFPS.setModel(new javax.swing.SpinnerNumberModel(10, 5, 30, 1));
 
513
 
 
514
        jLabel4.setText("Target");
 
515
 
 
516
        cboTarget.addActionListener(new java.awt.event.ActionListener() {
 
517
            public void actionPerformed(java.awt.event.ActionEvent evt) {
 
518
                cboTargetActionPerformed(evt);
 
519
            }
 
520
        });
 
521
 
 
522
        panTargetSettings.setBorder(javax.swing.BorderFactory.createTitledBorder("Settings"));
 
523
 
 
524
        jLabel5.setText("Video Bitrate");
 
525
 
 
526
        jLabel6.setText("Video Preset");
 
527
 
 
528
        jLabel7.setText("Audio Bitrate");
 
529
 
 
530
        lblRTMPServer.setText("RTMP Server");
 
531
 
 
532
        lblRTMPKey.setText("RTMP Secret Key");
 
533
 
 
534
        numVideoBitrate.setModel(new javax.swing.SpinnerNumberModel(1000, 300, 9000, 100));
 
535
 
 
536
        javax.swing.GroupLayout panTargetSettingsLayout = new javax.swing.GroupLayout(panTargetSettings);
 
537
        panTargetSettings.setLayout(panTargetSettingsLayout);
 
538
        panTargetSettingsLayout.setHorizontalGroup(
 
539
            panTargetSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
540
            .addGroup(panTargetSettingsLayout.createSequentialGroup()
 
541
                .addContainerGap()
 
542
                .addGroup(panTargetSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
543
                    .addGroup(panTargetSettingsLayout.createSequentialGroup()
 
544
                        .addGroup(panTargetSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
 
545
                            .addComponent(jLabel7, javax.swing.GroupLayout.DEFAULT_SIZE, 128, Short.MAX_VALUE)
 
546
                            .addComponent(lblRTMPServer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
547
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
548
                        .addGroup(panTargetSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
549
                            .addComponent(cboAudioBitrate, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
550
                            .addComponent(cboRTMPServers, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
 
551
                    .addGroup(panTargetSettingsLayout.createSequentialGroup()
 
552
                        .addGroup(panTargetSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
 
553
                            .addComponent(jLabel6, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
554
                            .addComponent(jLabel5, javax.swing.GroupLayout.DEFAULT_SIZE, 128, Short.MAX_VALUE))
 
555
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
556
                        .addGroup(panTargetSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
557
                            .addComponent(numVideoBitrate, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
558
                            .addComponent(cboVideoPresets, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
 
559
                    .addGroup(panTargetSettingsLayout.createSequentialGroup()
 
560
                        .addComponent(lblRTMPKey, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE)
 
561
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
562
                        .addComponent(txtRTMPKey, javax.swing.GroupLayout.PREFERRED_SIZE, 435, javax.swing.GroupLayout.PREFERRED_SIZE)))
 
563
                .addContainerGap(53, Short.MAX_VALUE))
 
564
        );
 
565
        panTargetSettingsLayout.setVerticalGroup(
 
566
            panTargetSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
567
            .addGroup(panTargetSettingsLayout.createSequentialGroup()
 
568
                .addContainerGap()
 
569
                .addGroup(panTargetSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
570
                    .addComponent(jLabel5)
 
571
                    .addComponent(numVideoBitrate, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
572
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
573
                .addGroup(panTargetSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
574
                    .addComponent(jLabel6)
 
575
                    .addComponent(cboVideoPresets, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
576
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
577
                .addGroup(panTargetSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
578
                    .addComponent(jLabel7)
 
579
                    .addComponent(cboAudioBitrate, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
580
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
581
                .addGroup(panTargetSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
582
                    .addComponent(lblRTMPServer)
 
583
                    .addComponent(cboRTMPServers, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
584
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
585
                .addGroup(panTargetSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
586
                    .addComponent(lblRTMPKey)
 
587
                    .addComponent(txtRTMPKey, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
588
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
589
        );
 
590
 
 
591
        javax.swing.GroupLayout panOutputLayout = new javax.swing.GroupLayout(panOutput);
 
592
        panOutput.setLayout(panOutputLayout);
 
593
        panOutputLayout.setHorizontalGroup(
 
594
            panOutputLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
595
            .addGroup(panOutputLayout.createSequentialGroup()
 
596
                .addContainerGap()
 
597
                .addGroup(panOutputLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
598
                    .addComponent(panTargetSettings, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
599
                    .addGroup(panOutputLayout.createSequentialGroup()
 
600
                        .addGroup(panOutputLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
601
                            .addComponent(jLabel1)
 
602
                            .addComponent(jLabel3)
 
603
                            .addComponent(jLabel4))
 
604
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
605
                        .addGroup(panOutputLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
 
606
                            .addGroup(panOutputLayout.createSequentialGroup()
 
607
                                .addComponent(spinWidth, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
608
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
609
                                .addComponent(jLabel2)
 
610
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
611
                                .addComponent(spinHeight, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
612
                            .addComponent(spinFPS, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
613
                            .addComponent(cboTarget, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
614
                        .addGap(0, 0, Short.MAX_VALUE)))
 
615
                .addContainerGap())
 
616
        );
 
617
        panOutputLayout.setVerticalGroup(
 
618
            panOutputLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
619
            .addGroup(panOutputLayout.createSequentialGroup()
 
620
                .addContainerGap()
 
621
                .addGroup(panOutputLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
622
                    .addComponent(jLabel1)
 
623
                    .addComponent(spinWidth, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
624
                    .addComponent(spinHeight, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
625
                    .addComponent(jLabel2))
 
626
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
627
                .addGroup(panOutputLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
628
                    .addComponent(jLabel3)
 
629
                    .addComponent(spinFPS, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
630
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
631
                .addGroup(panOutputLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
632
                    .addComponent(jLabel4)
 
633
                    .addComponent(cboTarget, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
634
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
635
                .addComponent(panTargetSettings, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
636
                .addContainerGap())
 
637
        );
 
638
 
 
639
        tabs.addTab("Output", panOutput);
 
640
 
 
641
        panSources.setLayout(new java.awt.BorderLayout());
 
642
 
 
643
        jSplitPane1.setDividerLocation(150);
 
644
        jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
 
645
 
 
646
        panPreviewLayout.setBackground(new java.awt.Color(51, 51, 51));
 
647
        panPreviewLayout.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Layout", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Lucida Grande", 0, 13), new java.awt.Color(255, 255, 255))); // NOI18N
 
648
        panPreviewLayout.setLayout(new java.awt.BorderLayout());
 
649
        jSplitPane1.setRightComponent(panPreviewLayout);
 
650
 
 
651
        scrollSources.setBorder(javax.swing.BorderFactory.createTitledBorder("Video Sources"));
 
652
 
 
653
        tableSources.setModel(new javax.swing.table.DefaultTableModel(
 
654
            new Object [][] {
 
655
                {null, null, null, null, null, null, null, null},
 
656
                {null, null, null, null, null, null, null, null},
 
657
                {null, null, null, null, null, null, null, null},
 
658
                {null, null, null, null, null, null, null, null}
 
659
            },
 
660
            new String [] {
 
661
                " ", "Source", "Description", "X", "Y", "Width", "Height", "Alpha"
 
662
            }
 
663
        ) {
 
664
            Class[] types = new Class [] {
 
665
                java.lang.Boolean.class, java.lang.String.class, java.lang.String.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Float.class
 
666
            };
 
667
            boolean[] canEdit = new boolean [] {
 
668
                true, false, false, true, true, true, true, true
 
669
            };
 
670
 
 
671
            public Class getColumnClass(int columnIndex) {
 
672
                return types [columnIndex];
 
673
            }
 
674
 
 
675
            public boolean isCellEditable(int rowIndex, int columnIndex) {
 
676
                return canEdit [columnIndex];
 
677
            }
 
678
        });
 
679
        tableSources.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_LAST_COLUMN);
 
680
        tableSources.setColumnSelectionAllowed(true);
 
681
        tableSources.setFillsViewportHeight(true);
 
682
        tableSources.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
 
683
        tableSources.getTableHeader().setResizingAllowed(false);
 
684
        tableSources.getTableHeader().setReorderingAllowed(false);
 
685
        tableSources.addMouseListener(new java.awt.event.MouseAdapter() {
 
686
            public void mouseClicked(java.awt.event.MouseEvent evt) {
 
687
                tableSourcesMouseClicked(evt);
 
688
            }
 
689
        });
 
690
        tableSources.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
 
691
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
 
692
                tableSourcesPropertyChange(evt);
 
693
            }
 
694
        });
 
695
        tableSources.addKeyListener(new java.awt.event.KeyAdapter() {
 
696
            public void keyPressed(java.awt.event.KeyEvent evt) {
 
697
                tableSourcesKeyPressed(evt);
 
698
            }
 
699
        });
 
700
        scrollSources.setViewportView(tableSources);
 
701
        tableSources.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
 
702
        if (tableSources.getColumnModel().getColumnCount() > 0) {
 
703
            tableSources.getColumnModel().getColumn(0).setMinWidth(25);
 
704
            tableSources.getColumnModel().getColumn(0).setPreferredWidth(25);
 
705
            tableSources.getColumnModel().getColumn(0).setMaxWidth(25);
 
706
            tableSources.getColumnModel().getColumn(1).setMinWidth(100);
 
707
            tableSources.getColumnModel().getColumn(1).setPreferredWidth(100);
 
708
            tableSources.getColumnModel().getColumn(1).setMaxWidth(100);
 
709
            tableSources.getColumnModel().getColumn(2).setMinWidth(150);
 
710
            tableSources.getColumnModel().getColumn(2).setPreferredWidth(150);
 
711
            tableSources.getColumnModel().getColumn(2).setMaxWidth(2000);
 
712
            tableSources.getColumnModel().getColumn(3).setMinWidth(60);
 
713
            tableSources.getColumnModel().getColumn(3).setPreferredWidth(60);
 
714
            tableSources.getColumnModel().getColumn(3).setMaxWidth(60);
 
715
            tableSources.getColumnModel().getColumn(4).setMinWidth(60);
 
716
            tableSources.getColumnModel().getColumn(4).setPreferredWidth(60);
 
717
            tableSources.getColumnModel().getColumn(4).setMaxWidth(60);
 
718
            tableSources.getColumnModel().getColumn(5).setMinWidth(60);
 
719
            tableSources.getColumnModel().getColumn(5).setPreferredWidth(60);
 
720
            tableSources.getColumnModel().getColumn(5).setMaxWidth(60);
 
721
            tableSources.getColumnModel().getColumn(6).setMinWidth(60);
 
722
            tableSources.getColumnModel().getColumn(6).setPreferredWidth(60);
 
723
            tableSources.getColumnModel().getColumn(6).setMaxWidth(60);
 
724
            tableSources.getColumnModel().getColumn(7).setMinWidth(60);
 
725
            tableSources.getColumnModel().getColumn(7).setPreferredWidth(60);
 
726
            tableSources.getColumnModel().getColumn(7).setMaxWidth(60);
 
727
        }
 
728
 
 
729
        jSplitPane1.setLeftComponent(scrollSources);
 
730
 
 
731
        panSources.add(jSplitPane1, java.awt.BorderLayout.CENTER);
 
732
 
 
733
        tabs.addTab("Sources", panSources);
 
734
 
 
735
        panSettingsAudios.setBorder(javax.swing.BorderFactory.createTitledBorder("Audio"));
 
736
 
 
737
        jLabel8.setText("Microphone Input");
 
738
 
 
739
        jLabel9.setText("Audio System Input");
 
740
 
 
741
        jLabel10.setText("Audio Delay");
 
742
 
 
743
        spinAudioDelay.setModel(new javax.swing.SpinnerNumberModel(Float.valueOf(0.0f), Float.valueOf(-5.0f), Float.valueOf(5.0f), Float.valueOf(0.1f)));
 
744
        spinAudioDelay.setToolTipText("<HTML><BODY>\nApply a delay (in seconds) to the audio.\n<BR><I>If video is late, apply a positive value...</I>\n</BODY></HTML>");
 
745
        spinAudioDelay.setEditor(new javax.swing.JSpinner.NumberEditor(spinAudioDelay, "#.#"));
 
746
        spinAudioDelay.addChangeListener(new javax.swing.event.ChangeListener() {
 
747
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
 
748
                spinAudioDelayStateChanged(evt);
 
749
            }
 
750
        });
 
751
 
 
752
        javax.swing.GroupLayout panSettingsAudiosLayout = new javax.swing.GroupLayout(panSettingsAudios);
 
753
        panSettingsAudios.setLayout(panSettingsAudiosLayout);
 
754
        panSettingsAudiosLayout.setHorizontalGroup(
 
755
            panSettingsAudiosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
756
            .addGroup(panSettingsAudiosLayout.createSequentialGroup()
 
757
                .addContainerGap()
 
758
                .addGroup(panSettingsAudiosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
759
                    .addComponent(jLabel8)
 
760
                    .addComponent(jLabel9)
 
761
                    .addComponent(jLabel10))
 
762
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
763
                .addGroup(panSettingsAudiosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
764
                    .addComponent(cboAudioMicrophones, 0, 461, Short.MAX_VALUE)
 
765
                    .addComponent(cboAudioSystems, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
766
                    .addGroup(panSettingsAudiosLayout.createSequentialGroup()
 
767
                        .addComponent(spinAudioDelay, javax.swing.GroupLayout.PREFERRED_SIZE, 97, javax.swing.GroupLayout.PREFERRED_SIZE)
 
768
                        .addGap(0, 390, Short.MAX_VALUE)))
 
769
                .addContainerGap())
 
770
        );
 
771
        panSettingsAudiosLayout.setVerticalGroup(
 
772
            panSettingsAudiosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
773
            .addGroup(panSettingsAudiosLayout.createSequentialGroup()
 
774
                .addGroup(panSettingsAudiosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
775
                    .addComponent(jLabel8)
 
776
                    .addComponent(cboAudioMicrophones, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
777
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
778
                .addGroup(panSettingsAudiosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
779
                    .addComponent(jLabel9)
 
780
                    .addComponent(cboAudioSystems, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
781
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
782
                .addGroup(panSettingsAudiosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
783
                    .addComponent(jLabel10)
 
784
                    .addComponent(spinAudioDelay, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
785
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
786
        );
 
787
 
 
788
        panSettingsVideos.setBorder(javax.swing.BorderFactory.createTitledBorder("Video Folders"));
 
789
 
 
790
        lblVideoFolder.setText(" ");
 
791
 
 
792
        btnSetVideoFolder.setText("Browse");
 
793
        btnSetVideoFolder.addActionListener(new java.awt.event.ActionListener() {
 
794
            public void actionPerformed(java.awt.event.ActionEvent evt) {
 
795
                btnSetVideoFolderActionPerformed(evt);
 
796
            }
 
797
        });
 
798
 
 
799
        javax.swing.GroupLayout panSettingsVideosLayout = new javax.swing.GroupLayout(panSettingsVideos);
 
800
        panSettingsVideos.setLayout(panSettingsVideosLayout);
 
801
        panSettingsVideosLayout.setHorizontalGroup(
 
802
            panSettingsVideosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
803
            .addGroup(panSettingsVideosLayout.createSequentialGroup()
 
804
                .addComponent(lblVideoFolder, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
805
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
806
                .addComponent(btnSetVideoFolder)
 
807
                .addContainerGap())
 
808
        );
 
809
        panSettingsVideosLayout.setVerticalGroup(
 
810
            panSettingsVideosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
811
            .addGroup(panSettingsVideosLayout.createSequentialGroup()
 
812
                .addGroup(panSettingsVideosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
813
                    .addComponent(lblVideoFolder)
 
814
                    .addComponent(btnSetVideoFolder))
 
815
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
816
        );
 
817
 
 
818
        panSettingsMisc.setBorder(javax.swing.BorderFactory.createTitledBorder("Misc"));
 
819
 
 
820
        chkStayVisible.setText("Stay Visible");
 
821
 
 
822
        javax.swing.GroupLayout panSettingsMiscLayout = new javax.swing.GroupLayout(panSettingsMisc);
 
823
        panSettingsMisc.setLayout(panSettingsMiscLayout);
 
824
        panSettingsMiscLayout.setHorizontalGroup(
 
825
            panSettingsMiscLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
826
            .addGroup(panSettingsMiscLayout.createSequentialGroup()
 
827
                .addContainerGap()
 
828
                .addComponent(chkStayVisible)
 
829
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
830
        );
 
831
        panSettingsMiscLayout.setVerticalGroup(
 
832
            panSettingsMiscLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
833
            .addComponent(chkStayVisible)
 
834
        );
 
835
 
 
836
        javax.swing.GroupLayout panOptionsLayout = new javax.swing.GroupLayout(panOptions);
 
837
        panOptions.setLayout(panOptionsLayout);
 
838
        panOptionsLayout.setHorizontalGroup(
 
839
            panOptionsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
840
            .addGroup(panOptionsLayout.createSequentialGroup()
 
841
                .addContainerGap()
 
842
                .addGroup(panOptionsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
843
                    .addComponent(panSettingsAudios, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
844
                    .addComponent(panSettingsVideos, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
845
                    .addComponent(panSettingsMisc, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
846
                .addContainerGap())
 
847
        );
 
848
        panOptionsLayout.setVerticalGroup(
 
849
            panOptionsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
850
            .addGroup(panOptionsLayout.createSequentialGroup()
 
851
                .addContainerGap()
 
852
                .addComponent(panSettingsAudios, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
853
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
854
                .addComponent(panSettingsVideos, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
855
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
856
                .addComponent(panSettingsMisc, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
857
                .addContainerGap(99, Short.MAX_VALUE))
 
858
        );
 
859
 
 
860
        tabs.addTab("Options", panOptions);
 
861
 
 
862
        getContentPane().add(tabs, java.awt.BorderLayout.CENTER);
 
863
 
 
864
        panStatus.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.LOWERED));
 
865
        panStatus.setPreferredSize(new java.awt.Dimension(767, 20));
 
866
        panStatus.setLayout(new javax.swing.BoxLayout(panStatus, javax.swing.BoxLayout.LINE_AXIS));
 
867
 
 
868
        lblMessages.setText("Welcome to ScreenStudio");
 
869
        panStatus.add(lblMessages);
 
870
 
 
871
        getContentPane().add(panStatus, java.awt.BorderLayout.SOUTH);
 
872
 
 
873
        mnuFile.setText("Layout");
 
874
 
 
875
        mnuCapture.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_R, java.awt.event.InputEvent.CTRL_MASK));
 
876
        mnuCapture.setText("Record");
 
877
        mnuCapture.setToolTipText("<html><body>\nStart recording/streaming using CTRL-R.  \n<BR><B>ScreenStudio</B> will automatically hide in the taskbar of your system.  \n<BR>To stop the recording, simply restore the <B>ScreenStudio</B> window.\n</body></html>");
 
878
        mnuCapture.addActionListener(new java.awt.event.ActionListener() {
 
879
            public void actionPerformed(java.awt.event.ActionEvent evt) {
 
880
                mnuCaptureActionPerformed(evt);
 
881
            }
 
882
        });
 
883
        mnuFile.add(mnuCapture);
 
884
        mnuFile.add(jSeparator1);
 
885
 
 
886
        mnuFileLoad.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
 
887
        mnuFileLoad.setText("Open");
 
888
        mnuFileLoad.setToolTipText("<HTML><BODY>\nOpen a <B>ScreenStudio</B> XML layout file\n</BODY></HTML>");
 
889
        mnuFileLoad.addActionListener(new java.awt.event.ActionListener() {
 
890
            public void actionPerformed(java.awt.event.ActionEvent evt) {
 
891
                mnuFileLoadActionPerformed(evt);
 
892
            }
 
893
        });
 
894
        mnuFile.add(mnuFileLoad);
 
895
 
 
896
        mnuFileSave.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
 
897
        mnuFileSave.setText("Save");
 
898
        mnuFileSave.setToolTipText("<HTML><BODY>\nSave the current layour to a <B>ScreenStudio</B> XML layout file\n</BODY></HTML>");
 
899
        mnuFileSave.addActionListener(new java.awt.event.ActionListener() {
 
900
            public void actionPerformed(java.awt.event.ActionEvent evt) {
 
901
                mnuFileSaveActionPerformed(evt);
 
902
            }
 
903
        });
 
904
        mnuFile.add(mnuFileSave);
 
905
 
 
906
        menuBar.add(mnuFile);
 
907
 
 
908
        mnuEdit.setText("Sources");
 
909
 
 
910
        mnuMainWebcams.setText("Webcams");
 
911
        mnuEdit.add(mnuMainWebcams);
 
912
 
 
913
        mnuMainDestops.setText("Desktops");
 
914
        mnuEdit.add(mnuMainDestops);
 
915
 
 
916
        mnuMainAddImage.setText("Add Image...");
 
917
        mnuMainAddImage.setToolTipText("Browse your hard disk to add a source image file");
 
918
        mnuMainAddImage.addActionListener(new java.awt.event.ActionListener() {
 
919
            public void actionPerformed(java.awt.event.ActionEvent evt) {
 
920
                mnuMainAddImageActionPerformed(evt);
 
921
            }
 
922
        });
 
923
        mnuEdit.add(mnuMainAddImage);
 
924
 
 
925
        mnuMainAddLabel.setText("Add Label");
 
926
        mnuMainAddLabel.setToolTipText("<HTML><BODY>\nAdd a new text label.  \n<BR>Double-click on the source to edit the content.\n</BODY></HTML>");
 
927
        mnuMainAddLabel.addActionListener(new java.awt.event.ActionListener() {
 
928
            public void actionPerformed(java.awt.event.ActionEvent evt) {
 
929
                mnuMainAddLabelActionPerformed(evt);
 
930
            }
 
931
        });
 
932
        mnuEdit.add(mnuMainAddLabel);
 
933
        mnuEdit.add(jSeparator3);
 
934
 
 
935
        mnuMainMoveUp.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_UP, java.awt.event.InputEvent.ALT_MASK));
 
936
        mnuMainMoveUp.setText("Move Up");
 
937
        mnuMainMoveUp.setToolTipText("Move the currently selected source to a higher layer");
 
938
        mnuMainMoveUp.addActionListener(new java.awt.event.ActionListener() {
 
939
            public void actionPerformed(java.awt.event.ActionEvent evt) {
 
940
                mnuMainMoveUpActionPerformed(evt);
 
941
            }
 
942
        });
 
943
        mnuEdit.add(mnuMainMoveUp);
 
944
 
 
945
        mnuMainMoveDown.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_DOWN, java.awt.event.InputEvent.ALT_MASK));
 
946
        mnuMainMoveDown.setText("Move Down");
 
947
        mnuMainMoveDown.setToolTipText("Move the currently selected source to a lower layer");
 
948
        mnuMainMoveDown.addActionListener(new java.awt.event.ActionListener() {
 
949
            public void actionPerformed(java.awt.event.ActionEvent evt) {
 
950
                mnuMainMoveDownActionPerformed(evt);
 
951
            }
 
952
        });
 
953
        mnuEdit.add(mnuMainMoveDown);
 
954
        mnuEdit.add(jSeparator2);
 
955
 
 
956
        mnuMainRemove.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_DELETE, 0));
 
957
        mnuMainRemove.setText("Remove Source");
 
958
        mnuMainRemove.setToolTipText("Remove the currently selected source");
 
959
        mnuMainRemove.addActionListener(new java.awt.event.ActionListener() {
 
960
            public void actionPerformed(java.awt.event.ActionEvent evt) {
 
961
                mnuMainRemoveActionPerformed(evt);
 
962
            }
 
963
        });
 
964
        mnuEdit.add(mnuMainRemove);
 
965
 
 
966
        menuBar.add(mnuEdit);
 
967
 
 
968
        setJMenuBar(menuBar);
 
969
 
 
970
        pack();
 
971
    }// </editor-fold>//GEN-END:initComponents
 
972
 
 
973
    private void tableSourcesPropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_tableSourcesPropertyChange
 
974
        if (mLayoutPreview != null) {
 
975
            mLayoutPreview.repaint();
 
976
        }
 
977
    }//GEN-LAST:event_tableSourcesPropertyChange
 
978
 
 
979
    private void tableSourcesKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_tableSourcesKeyPressed
 
980
        mLayoutPreview.repaint();
 
981
    }//GEN-LAST:event_tableSourcesKeyPressed
 
982
 
 
983
    private void tableSourcesMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tableSourcesMouseClicked
 
984
        if (evt.getClickCount() == 2) {
 
985
            int rowIndex = tableSources.getSelectedRow();
 
986
            if (tableSources.getValueAt(rowIndex, 1) == SourceType.LabelText) {
 
987
                Editor ed = new Editor(((LabelText) tableSources.getValueAt(rowIndex, 2)), this);
 
988
                ed.setModal(true);
 
989
                ed.setVisible(true);
 
990
                tableSources.setValueAt(ed.getLabelText(), rowIndex, 2);
 
991
                tableSources.repaint();
 
992
            }
 
993
        }
 
994
        mLayoutPreview.repaint();
 
995
    }//GEN-LAST:event_tableSourcesMouseClicked
 
996
 
 
997
    private void spinWidthStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinWidthStateChanged
 
998
        if (mLayoutPreview != null) {
 
999
            mLayoutPreview.setOutputWidth((Integer) spinWidth.getValue());
 
1000
        }
 
1001
    }//GEN-LAST:event_spinWidthStateChanged
 
1002
 
 
1003
    private void spinHeightStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinHeightStateChanged
 
1004
        if (mLayoutPreview != null) {
 
1005
            mLayoutPreview.setOutputHeight((Integer) spinHeight.getValue());
 
1006
        }
 
1007
    }//GEN-LAST:event_spinHeightStateChanged
 
1008
 
 
1009
    private void cboTargetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cboTargetActionPerformed
 
1010
        setRTMPControls((FFMpeg.FORMATS) cboTarget.getSelectedItem());
 
1011
    }//GEN-LAST:event_cboTargetActionPerformed
 
1012
 
 
1013
 
 
1014
    private void mnuCaptureActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuCaptureActionPerformed
 
1015
        if (mFFMpeg != null) {
 
1016
            if (mFFMpeg.getState() == FFMpeg.RunningState.Error) {
 
1017
                lblMessages.setText(mFFMpeg.getLastErrorMessage());
 
1018
            } else {
 
1019
                lblMessages.setText("Stopped...");
 
1020
            }
 
1021
            mFFMpeg.stop();
 
1022
            try {
 
1023
                Microphone.getVirtualAudio(null, null);
 
1024
            } catch (IOException | InterruptedException ex) {
 
1025
                Logger.getLogger(ScreenStudio.class.getName()).log(Level.SEVERE, null, ex);
 
1026
            }
 
1027
            mFFMpeg = null;
 
1028
            mnuCapture.setText("Record");
 
1029
            if (!chkStayVisible.isSelected()) {
 
1030
                if (trayIcon != null) {
 
1031
                    trayIcon.setImage(this.getIconImage());
 
1032
                    this.setVisible(true);
 
1033
                }
 
1034
            }
 
1035
            updateControls(true);
 
1036
            if (FFMpeg.isRTMP((FFMpeg.FORMATS) cboTarget.getSelectedItem())) {
 
1037
                txtRTMPKey.setVisible(true);
 
1038
            }
 
1039
        } else {
 
1040
            if (txtRTMPKey.isVisible()) {
 
1041
                txtRTMPKey.setVisible(false);
 
1042
            }
 
1043
            boolean abort = false;
 
1044
            if (tableSources.getRowCount() == 0) {
 
1045
                lblMessages.setText("No video source to display...");
 
1046
                abort = true;
 
1047
            }
 
1048
            if (cboAudioMicrophones.getSelectedIndex() == 0 && cboAudioSystems.getSelectedIndex() == 0) {
 
1049
                lblMessages.setText("No audio source selected...");
 
1050
                abort = true;
 
1051
            }
 
1052
            if (!abort) {
 
1053
                List<Source> sources = Compositor.getSources(tableSources, (Integer) spinFPS.getValue());
 
1054
                Compositor compositor = new Compositor(sources, new Rectangle(0, 0, (Integer) spinWidth.getValue(), (Integer) spinHeight.getValue()), (Integer) spinFPS.getValue());
 
1055
                mFFMpeg = new FFMpeg(compositor);
 
1056
                String audio = "default";
 
1057
                Microphone mic = null;
 
1058
                Microphone sys = null;
 
1059
                if (cboAudioMicrophones.getSelectedIndex() > 0) {
 
1060
                    mic = (Microphone) cboAudioMicrophones.getSelectedItem();
 
1061
                }
 
1062
                if (cboAudioSystems.getSelectedIndex() > 0) {
 
1063
                    sys = (Microphone) cboAudioSystems.getSelectedItem();
 
1064
                }
 
1065
                try {
 
1066
                    audio = Microphone.getVirtualAudio(mic, sys);
 
1067
                } catch (IOException ex) {
 
1068
                    Logger.getLogger(ScreenStudio.class.getName()).log(Level.SEVERE, null, ex);
 
1069
                } catch (InterruptedException ex) {
 
1070
                    Logger.getLogger(ScreenStudio.class.getName()).log(Level.SEVERE, null, ex);
 
1071
                }
 
1072
                mFFMpeg.setAudio((FFMpeg.AudioRate) cboAudioBitrate.getSelectedItem(), audio, (Float) spinAudioDelay.getValue());
 
1073
                String server = "";
 
1074
                if (cboRTMPServers.getSelectedItem() != null) {
 
1075
                    server = cboRTMPServers.getSelectedItem().toString();
 
1076
                    server = server.split(";")[1];
 
1077
                }
 
1078
                mFFMpeg.setOutputFormat((FFMpeg.FORMATS) cboTarget.getSelectedItem(), (FFMpeg.Presets) cboVideoPresets.getSelectedItem(), (Integer) numVideoBitrate.getValue(), server, txtRTMPKey.getText(), mVideoOutputFolder);
 
1079
                new Thread(mFFMpeg).start();
 
1080
                lblMessages.setText("Recording...");
 
1081
                mnuCapture.setText("Stop");
 
1082
                if (trayIcon != null) {
 
1083
                    trayIcon.setImage(new ImageIcon(ScreenStudio.class.getResource("/screenstudio/gui/images/iconRunning.png")).getImage());
 
1084
                }
 
1085
 
 
1086
                updateControls(false);
 
1087
                if (!chkStayVisible.isSelected()) {
 
1088
                    if (trayIcon != null) {
 
1089
                        this.setVisible(false);
 
1090
                    } else {
 
1091
                        this.setExtendedState(JFrame.ICONIFIED);
 
1092
                    }
 
1093
                }
 
1094
                mRecordingTimestamp = System.currentTimeMillis();
 
1095
                new Thread(() -> {
 
1096
                    FFMpeg f = mFFMpeg;
 
1097
                    while (f != null) {
 
1098
                        long seconds = (System.currentTimeMillis() - mRecordingTimestamp) / 1000;
 
1099
                        if (seconds < 60) {
 
1100
                            setTitle("Recording! (" + seconds + " sec)");
 
1101
                        } else {
 
1102
                            setTitle("Recording! (" + (seconds / 60) + " min " + (seconds % 60) + " sec)");
 
1103
                        }
 
1104
                        if (f.getState() == FFMpeg.RunningState.Error) {
 
1105
                            System.err.println("Encoder error detected...");
 
1106
                            mnuCapture.doClick();
 
1107
                            break;
 
1108
                        }
 
1109
                        try {
 
1110
                            Thread.sleep(1000);
 
1111
                        } catch (InterruptedException ex) {
 
1112
                            Logger.getLogger(ScreenStudio.class.getName()).log(Level.SEVERE, null, ex);
 
1113
                        }
 
1114
                        f = mFFMpeg;
 
1115
                    }
 
1116
                    setTitle("ScreenStudio " + screenstudio.Version.MAIN);
 
1117
                }).start();
 
1118
            }
 
1119
        }
 
1120
 
 
1121
    }//GEN-LAST:event_mnuCaptureActionPerformed
 
1122
 
 
1123
    private void mnuFileSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuFileSaveActionPerformed
 
1124
        java.util.prefs.Preferences p = java.util.prefs.Preferences.userRoot().node("screenstudio");
 
1125
        String lastFolder = p.get("lastfolder", ".");
 
1126
        JFileChooser chooser = new JFileChooser(new File(lastFolder));
 
1127
        chooser.setAcceptAllFileFilterUsed(false);
 
1128
        chooser.setFileFilter(new FileFilter() {
 
1129
            @Override
 
1130
            public boolean accept(File f) {
 
1131
                return f.isDirectory() || f.getName().toUpperCase().endsWith(".XML");
 
1132
            }
 
1133
 
 
1134
            @Override
 
1135
            public String getDescription() {
 
1136
                return "ScreenStudio XML Layout";
 
1137
            }
 
1138
        });
 
1139
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
 
1140
        if (chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
 
1141
            if (chooser.getSelectedFile() != null) {
 
1142
                saveLayout(chooser.getSelectedFile());
 
1143
                p.put("lastfolder", chooser.getSelectedFile().getParent());
 
1144
                try {
 
1145
                    p.flush();
 
1146
                } catch (BackingStoreException ex) {
 
1147
                    Logger.getLogger(ScreenStudio.class.getName()).log(Level.SEVERE, null, ex);
 
1148
                }
 
1149
            }
 
1150
        }
 
1151
 
 
1152
    }//GEN-LAST:event_mnuFileSaveActionPerformed
 
1153
 
 
1154
    private void mnuFileLoadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuFileLoadActionPerformed
 
1155
        // load last folder...
 
1156
        java.util.prefs.Preferences p = java.util.prefs.Preferences.userRoot().node("screenstudio");
 
1157
        String lastFolder = p.get("lastfolder", ".");
 
1158
        JFileChooser chooser = new JFileChooser(new File(lastFolder));
 
1159
        chooser.setAcceptAllFileFilterUsed(false);
 
1160
        chooser.setFileFilter(new FileFilter() {
 
1161
            @Override
 
1162
            public boolean accept(File f) {
 
1163
                return f.isDirectory() || f.getName().toUpperCase().endsWith(".XML");
 
1164
            }
 
1165
 
 
1166
            @Override
 
1167
            public String getDescription() {
 
1168
                return "ScreenStudio XML Layout";
 
1169
            }
 
1170
        });
 
1171
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
 
1172
        if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
 
1173
            if (chooser.getSelectedFile() != null) {
 
1174
                loadLayout(chooser.getSelectedFile());
 
1175
                p.put("lastfolder", chooser.getSelectedFile().getParent());
 
1176
                try {
 
1177
                    p.flush();
 
1178
                } catch (BackingStoreException ex) {
 
1179
                    Logger.getLogger(ScreenStudio.class.getName()).log(Level.SEVERE, null, ex);
 
1180
                }
 
1181
            }
 
1182
        }
 
1183
 
 
1184
    }//GEN-LAST:event_mnuFileLoadActionPerformed
 
1185
 
 
1186
    private void btnSetVideoFolderActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSetVideoFolderActionPerformed
 
1187
        JFileChooser chooser = new JFileChooser(mVideoOutputFolder);
 
1188
        chooser.setAcceptAllFileFilterUsed(false);
 
1189
        chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
 
1190
        chooser.showOpenDialog(this);
 
1191
        if (chooser.getSelectedFile() != null) {
 
1192
            mVideoOutputFolder = chooser.getSelectedFile();
 
1193
            lblVideoFolder.setText(mVideoOutputFolder.getAbsolutePath());
 
1194
            lblVideoFolder.setToolTipText(mVideoOutputFolder.getAbsolutePath());
 
1195
        }
 
1196
    }//GEN-LAST:event_btnSetVideoFolderActionPerformed
 
1197
 
 
1198
    private void mnuMainAddImageActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuMainAddImageActionPerformed
 
1199
        JFileChooser chooser = new JFileChooser(mVideoOutputFolder);
 
1200
        chooser.setAcceptAllFileFilterUsed(false);
 
1201
        chooser.setFileFilter(new FileFilter() {
 
1202
            @Override
 
1203
            public boolean accept(File f) {
 
1204
                return f.isDirectory() || f.getName().toUpperCase().endsWith(".PNG") || f.getName().toUpperCase().endsWith(".JPG") || f.getName().toUpperCase().endsWith(".GIF") || f.getName().toUpperCase().endsWith(".BMP");
 
1205
            }
 
1206
 
 
1207
            @Override
 
1208
            public String getDescription() {
 
1209
                return "Image Files";
 
1210
            }
 
1211
        });
 
1212
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
 
1213
        chooser.showOpenDialog(this);
 
1214
        if (chooser.getSelectedFile() != null) {
 
1215
            File image = chooser.getSelectedFile();
 
1216
            //add new source...
 
1217
            DefaultTableModel model = (DefaultTableModel) tableSources.getModel();
 
1218
            Object[] row = new Object[model.getColumnCount()];
 
1219
            row[0] = true;
 
1220
            row[1] = SourceType.Image;
 
1221
            row[2] = image;
 
1222
            row[3] = 0;
 
1223
            row[4] = 0;
 
1224
            row[5] = 200;
 
1225
            row[6] = 200;
 
1226
            row[7] = 1.0f;
 
1227
            model.addRow(row);
 
1228
        }
 
1229
        mLayoutPreview.repaint();
 
1230
        tabs.setSelectedComponent(panSources);
 
1231
    }//GEN-LAST:event_mnuMainAddImageActionPerformed
 
1232
 
 
1233
    private void mnuMainAddLabelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuMainAddLabelActionPerformed
 
1234
        DefaultTableModel model = (DefaultTableModel) tableSources.getModel();
 
1235
        Object[] row = new Object[model.getColumnCount()];
 
1236
        row[0] = true;
 
1237
        row[1] = SourceType.LabelText;
 
1238
        row[2] = new LabelText("<HTML><BODY>New Label...</BODY><HTML>");
 
1239
        row[3] = 0;
 
1240
        row[4] = 0;
 
1241
        row[5] = 300;
 
1242
        row[6] = 100;
 
1243
        row[7] = 1.0f;
 
1244
        model.addRow(row);
 
1245
        mLayoutPreview.repaint();
 
1246
        tabs.setSelectedComponent(panSources);
 
1247
    }//GEN-LAST:event_mnuMainAddLabelActionPerformed
 
1248
 
 
1249
    private void mnuMainMoveUpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuMainMoveUpActionPerformed
 
1250
        if (tableSources.getSelectedRow() != -1 && tableSources.getSelectedRow() > 0) {
 
1251
            Object[] row = new Object[tableSources.getColumnCount()];
 
1252
            for (int i = 0; i < row.length; i++) {
 
1253
                row[i] = tableSources.getValueAt(tableSources.getSelectedRow(), i);
 
1254
                tableSources.setValueAt(tableSources.getValueAt(tableSources.getSelectedRow() - 1, i), tableSources.getSelectedRow(), i);
 
1255
                tableSources.setValueAt(row[i], tableSources.getSelectedRow() - 1, i);
 
1256
            }
 
1257
            int index = tableSources.getSelectedRow() - 1;
 
1258
            tableSources.setRowSelectionInterval(index, index);
 
1259
            mLayoutPreview.repaint();
 
1260
            tabs.setSelectedComponent(panSources);
 
1261
        }
 
1262
    }//GEN-LAST:event_mnuMainMoveUpActionPerformed
 
1263
 
 
1264
    private void mnuMainMoveDownActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuMainMoveDownActionPerformed
 
1265
        if (tableSources.getSelectedRow() != -1 && tableSources.getSelectedRow() < tableSources.getRowCount() - 1) {
 
1266
            Object[] row = new Object[tableSources.getColumnCount()];
 
1267
            for (int i = 0; i < row.length; i++) {
 
1268
                row[i] = tableSources.getValueAt(tableSources.getSelectedRow(), i);
 
1269
                tableSources.setValueAt(tableSources.getValueAt(tableSources.getSelectedRow() + 1, i), tableSources.getSelectedRow(), i);
 
1270
                tableSources.setValueAt(row[i], tableSources.getSelectedRow() + 1, i);
 
1271
            }
 
1272
            int index = tableSources.getSelectedRow() + 1;
 
1273
            tableSources.setRowSelectionInterval(index, index);
 
1274
            mLayoutPreview.repaint();
 
1275
            tabs.setSelectedComponent(panSources);
 
1276
        }
 
1277
    }//GEN-LAST:event_mnuMainMoveDownActionPerformed
 
1278
 
 
1279
    private void formWindowStateChanged(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowStateChanged
 
1280
        if (mFFMpeg != null && evt.getOldState() == JFrame.ICONIFIED && trayIcon == null) {
 
1281
            mnuCapture.doClick();
 
1282
        }
 
1283
    }//GEN-LAST:event_formWindowStateChanged
 
1284
 
 
1285
    private void mnuMainRemoveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuMainRemoveActionPerformed
 
1286
        if (tableSources.getSelectedRow() != -1) {
 
1287
            int index = tableSources.getSelectedRow();
 
1288
            DefaultTableModel model = (DefaultTableModel) tableSources.getModel();
 
1289
            model.removeRow(index);
 
1290
            mLayoutPreview.repaint();
 
1291
        }
 
1292
    }//GEN-LAST:event_mnuMainRemoveActionPerformed
 
1293
 
 
1294
    private void spinAudioDelayStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinAudioDelayStateChanged
 
1295
        java.util.prefs.Preferences p = java.util.prefs.Preferences.userRoot().node("screenstudio");
 
1296
        p.putFloat("audiodelay", (Float) spinAudioDelay.getValue());
 
1297
        try {
 
1298
            p.flush();
 
1299
        } catch (BackingStoreException ex) {
 
1300
            Logger.getLogger(ScreenStudio.class.getName()).log(Level.SEVERE, null, ex);
 
1301
        }
 
1302
    }//GEN-LAST:event_spinAudioDelayStateChanged
 
1303
 
 
1304
    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
 
1305
        if (trayIcon != null) {
 
1306
            SystemTray.getSystemTray().remove(trayIcon);
 
1307
        }
 
1308
    }//GEN-LAST:event_formWindowClosing
 
1309
 
 
1310
    /**
 
1311
     * @param args the command line arguments
 
1312
     */
 
1313
    public static void main(String args[]) {
 
1314
        /* Set the Nimbus look and feel */
 
1315
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
 
1316
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
 
1317
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
 
1318
         */
 
1319
        try {
 
1320
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
 
1321
                if ("Nimbus".equals(info.getName())) {
 
1322
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
 
1323
                    break;
 
1324
                }
 
1325
            }
 
1326
        } catch (ClassNotFoundException ex) {
 
1327
            java.util.logging.Logger.getLogger(ScreenStudio.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
 
1328
        } catch (InstantiationException ex) {
 
1329
            java.util.logging.Logger.getLogger(ScreenStudio.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
 
1330
        } catch (IllegalAccessException ex) {
 
1331
            java.util.logging.Logger.getLogger(ScreenStudio.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
 
1332
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
 
1333
            java.util.logging.Logger.getLogger(ScreenStudio.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
 
1334
        }
 
1335
        //</editor-fold>
 
1336
        //</editor-fold>
 
1337
 
 
1338
        /* Create and display the form */
 
1339
        java.awt.EventQueue.invokeLater(new Runnable() {
 
1340
            public void run() {
 
1341
                new ScreenStudio().setVisible(true);
 
1342
            }
 
1343
        });
 
1344
    }
 
1345
 
 
1346
    // Variables declaration - do not modify//GEN-BEGIN:variables
 
1347
    private javax.swing.JButton btnSetVideoFolder;
 
1348
    private javax.swing.JComboBox<FFMpeg.AudioRate> cboAudioBitrate;
 
1349
    private javax.swing.JComboBox<Microphone> cboAudioMicrophones;
 
1350
    private javax.swing.JComboBox<Microphone> cboAudioSystems;
 
1351
    private javax.swing.JComboBox<String> cboRTMPServers;
 
1352
    private javax.swing.JComboBox<FFMpeg.FORMATS> cboTarget;
 
1353
    private javax.swing.JComboBox<FFMpeg.Presets> cboVideoPresets;
 
1354
    private javax.swing.JCheckBox chkStayVisible;
 
1355
    private javax.swing.JLabel jLabel1;
 
1356
    private javax.swing.JLabel jLabel10;
 
1357
    private javax.swing.JLabel jLabel2;
 
1358
    private javax.swing.JLabel jLabel3;
 
1359
    private javax.swing.JLabel jLabel4;
 
1360
    private javax.swing.JLabel jLabel5;
 
1361
    private javax.swing.JLabel jLabel6;
 
1362
    private javax.swing.JLabel jLabel7;
 
1363
    private javax.swing.JLabel jLabel8;
 
1364
    private javax.swing.JLabel jLabel9;
 
1365
    private javax.swing.JPopupMenu.Separator jSeparator1;
 
1366
    private javax.swing.JPopupMenu.Separator jSeparator2;
 
1367
    private javax.swing.JPopupMenu.Separator jSeparator3;
 
1368
    private javax.swing.JSplitPane jSplitPane1;
 
1369
    private javax.swing.JLabel lblMessages;
 
1370
    private javax.swing.JLabel lblRTMPKey;
 
1371
    private javax.swing.JLabel lblRTMPServer;
 
1372
    private javax.swing.JLabel lblVideoFolder;
 
1373
    private javax.swing.JMenuBar menuBar;
 
1374
    private javax.swing.JMenuItem mnuCapture;
 
1375
    private javax.swing.JMenu mnuEdit;
 
1376
    private javax.swing.JMenu mnuFile;
 
1377
    private javax.swing.JMenuItem mnuFileLoad;
 
1378
    private javax.swing.JMenuItem mnuFileSave;
 
1379
    private javax.swing.JMenuItem mnuMainAddImage;
 
1380
    private javax.swing.JMenuItem mnuMainAddLabel;
 
1381
    private javax.swing.JMenu mnuMainDestops;
 
1382
    private javax.swing.JMenuItem mnuMainMoveDown;
 
1383
    private javax.swing.JMenuItem mnuMainMoveUp;
 
1384
    private javax.swing.JMenuItem mnuMainRemove;
 
1385
    private javax.swing.JMenu mnuMainWebcams;
 
1386
    private javax.swing.JSpinner numVideoBitrate;
 
1387
    private javax.swing.JPanel panOptions;
 
1388
    private javax.swing.JPanel panOutput;
 
1389
    private javax.swing.JPanel panPreviewLayout;
 
1390
    private javax.swing.JPanel panSettingsAudios;
 
1391
    private javax.swing.JPanel panSettingsMisc;
 
1392
    private javax.swing.JPanel panSettingsVideos;
 
1393
    private javax.swing.JPanel panSources;
 
1394
    private javax.swing.JPanel panStatus;
 
1395
    private javax.swing.JPanel panTargetSettings;
 
1396
    private javax.swing.JScrollPane scrollSources;
 
1397
    private javax.swing.JSpinner spinAudioDelay;
 
1398
    private javax.swing.JSpinner spinFPS;
 
1399
    private javax.swing.JSpinner spinHeight;
 
1400
    private javax.swing.JSpinner spinWidth;
 
1401
    private javax.swing.JTable tableSources;
 
1402
    private javax.swing.JTabbedPane tabs;
 
1403
    private javax.swing.JTextField txtRTMPKey;
 
1404
    // End of variables declaration//GEN-END:variables
 
1405
}