Java tutorial
/* * Copyright 2004 - 2008 Christian Sprajc. All rights reserved. * * This file is part of PowerFolder. * * PowerFolder is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * * PowerFolder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with PowerFolder. If not, see <http://www.gnu.org/licenses/>. * * $Id$ */ package de.dal33t.powerfolder.ui.panel; import java.awt.Cursor; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import javax.swing.Action; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import com.jgoodies.forms.builder.PanelBuilder; import com.jgoodies.forms.factories.Borders; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import de.dal33t.powerfolder.Controller; import de.dal33t.powerfolder.transfer.TransferManager; import de.dal33t.powerfolder.ui.PFUIComponent; import de.dal33t.powerfolder.ui.action.BaseAction; import de.dal33t.powerfolder.ui.util.CursorUtils; import de.dal33t.powerfolder.util.Translation; /** * Panel with a combobox for selecting the line speed and a textfield for * entering upload speed. Editing the textfield is only possible if Custom * line_speed was chosen first. * * @author Bytekeeper * @version $revision$ */ public class LineSpeedSelectionPanel extends PFUIComponent { private static final int UNLIMITED = 0; private static final int AUTO_DETECT = -1; private static final int AUTOMATIC_INDEX = 0; private final boolean wan; private JPanel uiComponent; private JComboBox<LineSpeed> speedSelectionBox; private JComponent customSpeedPanel; private SpinnerNumberModel customUploadSpeedSpinnerModel; private SpinnerNumberModel customDownloadSpeedSpinnerModel; private JSpinner customUploadSpeedSpinner; private JLabel customUploadSpeedText; private JSpinner customDownloadSpeedSpinner; private JLabel customDownloadSpeedText; private final boolean showCustomEntry; private JLabel customUploadKbPerSLabel; private JLabel customDownloadKbPerSLabel; private JButton recalculateAutoButton; /** * Constructs a new LineSpeedSelectionPanel. * * @param wan WAN, not LAN. * @param showCustomEntry true if the entry panels for custom upload/download speed * selection should be shown all the time, otherwise they only * visible on demand. */ public LineSpeedSelectionPanel(Controller controller, boolean wan, boolean showCustomEntry) { super(controller); this.showCustomEntry = showCustomEntry; this.wan = wan; initComponents(); } public JPanel getUiComponent() { if (uiComponent == null) { buildPanel(); } return uiComponent; } private void initComponents() { Action recalculateAction = new RecalculateAction(getController()); recalculateAutoButton = new JButton(recalculateAction); customUploadSpeedSpinnerModel = new SpinnerNumberModel(0, 0, 999999, 5); customDownloadSpeedSpinnerModel = new SpinnerNumberModel(0, 0, 999999, 5); customUploadSpeedText = new JLabel(); customUploadSpeedSpinner = new JSpinner(customUploadSpeedSpinnerModel); customDownloadSpeedText = new JLabel(""); customDownloadSpeedSpinner = new JSpinner(customDownloadSpeedSpinnerModel); customUploadKbPerSLabel = new JLabel(Translation.getTranslation("general.kbPerS")); customDownloadKbPerSLabel = new JLabel(Translation.getTranslation("general.kbPerS")); customUploadSpeedSpinnerModel.addChangeListener(new MyChangeListener(customUploadSpeedText)); customDownloadSpeedSpinnerModel.addChangeListener(new MyChangeListener(customDownloadSpeedText)); customSpeedPanel = createCustomSpeedInputFieldPanel(); speedSelectionBox = new JComboBox<>(); if (wan) { loadWanSelection(); } else { loadLanSelection(); } speedSelectionBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { configureUpDownComponents(); } }); configureUpDownComponents(); } private void buildPanel() { FormLayout layout = new FormLayout("pref:grow", "pref, 1dlu, pref"); PanelBuilder builder = new PanelBuilder(layout); CellConstraints cc = new CellConstraints(); customSpeedPanel.setBorder(Borders.createEmptyBorder("0, 0, 3dlu, 0")); JPanel speedSelectionPanel = createSpeedSelectionPanel(); builder.add(speedSelectionPanel, cc.xy(1, 1)); builder.add(customSpeedPanel, cc.xy(1, 3)); uiComponent = builder.getPanel(); uiComponent.setOpaque(false); } private void configureUpDownComponents() { customSpeedPanel.setVisible(showCustomEntry); boolean automaticSelected = wan && speedSelectionBox.getSelectedIndex() == 0; if (((LineSpeed) speedSelectionBox.getSelectedItem()).isEditable()) { // Custom line. customUploadSpeedSpinner.setVisible(true); customDownloadSpeedSpinner.setVisible(true); customUploadKbPerSLabel.setVisible(true); customDownloadKbPerSLabel.setVisible(true); customUploadSpeedText.setVisible(false); customDownloadSpeedText.setVisible(false); customUploadSpeedSpinnerModel.setValue(0); customDownloadSpeedSpinnerModel.setValue(0); } else { // Preset line. customUploadSpeedSpinner.setVisible(false); customDownloadSpeedSpinner.setVisible(false); customUploadKbPerSLabel.setVisible(false); customDownloadKbPerSLabel.setVisible(false); customUploadSpeedText.setVisible(true); customDownloadSpeedText.setVisible(true); if (!automaticSelected) { customUploadSpeedSpinnerModel .setValue(((LineSpeed) speedSelectionBox.getSelectedItem()).getUploadSpeed()); customDownloadSpeedSpinnerModel .setValue(((LineSpeed) speedSelectionBox.getSelectedItem()).getDownloadSpeed()); // Have to do this manually because the spinners are not // guaranteed to change, and if changing from automatic, // text needs to be updated. SwingUtilities.invokeLater(new Runnable() { public void run() { long kbPerS = customUploadSpeedSpinnerModel.getNumber().longValue(); updateLabel(customUploadSpeedText, kbPerS); kbPerS = customDownloadSpeedSpinnerModel.getNumber().longValue(); updateLabel(customDownloadSpeedText, kbPerS); } }); } } recalculateAutoButton.setVisible(automaticSelected); if (automaticSelected) { TransferManager transferManager = getController().getTransferManager(); if (transferManager.getUploadCPSForWAN() > 0) { customUploadSpeedText.setText(transferManager.getUploadCPSForWAN() / 1024 + " " + Translation.getTranslation("general.kbPerS")); } else { customUploadSpeedText.setText(Translation.getTranslation("line_speed.unlimited")); } if (transferManager.getDownloadCPSForWAN() > 0) { customDownloadSpeedText.setText(transferManager.getDownloadCPSForWAN() / 1024 + " " + Translation.getTranslation("general.kbPerS")); } else { customDownloadSpeedText.setText(Translation.getTranslation("line_speed.unlimited")); } } } private JPanel createSpeedSelectionPanel() { FormLayout layout = new FormLayout("80dlu, 3dlu, pref, pref:grow", "pref"); PanelBuilder builder = new PanelBuilder(layout); CellConstraints cc = new CellConstraints(); builder.add(speedSelectionBox, cc.xy(1, 1)); if (wan) { builder.add(recalculateAutoButton, cc.xy(3, 1)); } JPanel panel = builder.getPanel(); panel.setOpaque(false); return panel; } private JPanel createCustomSpeedInputFieldPanel() { FormLayout layout = new FormLayout( "pref, 3dlu, 25dlu, 3dlu, 25dlu, " + "3dlu, " + "pref, 3dlu, 25dlu, 3dlu, 25dlu", "pref"); PanelBuilder builder = new PanelBuilder(layout); CellConstraints cc = new CellConstraints(); builder.add(new JLabel(Translation.getTranslation("line_speed.download_speed")), cc.xy(1, 1)); builder.add(customDownloadSpeedSpinner, cc.xy(3, 1)); builder.add(customDownloadKbPerSLabel, cc.xy(5, 1)); builder.add(customDownloadSpeedText, cc.xyw(3, 1, 3)); builder.add(new JLabel(Translation.getTranslation("line_speed.upload_speed")), cc.xy(7, 1)); builder.add(customUploadSpeedSpinner, cc.xy(9, 1)); builder.add(customUploadKbPerSLabel, cc.xy(11, 1)); builder.add(customUploadSpeedText, cc.xyw(9, 1, 3)); JPanel panel = builder.getPanel(); panel.setOpaque(false); return panel; } /** * Loads the selection with the default values for LAN */ private void loadLanSelection() { addLineSpeed("line_speed.lan10", 1000, UNLIMITED); addLineSpeed("line_speed.lan100", 10000, UNLIMITED); addLineSpeed("line_speed.lan1000", 100000, UNLIMITED); addLineSpeed("line_speed.unlimited", UNLIMITED, UNLIMITED); if (showCustomEntry) { addLineSpeed("line_speed.custom_speed", UNLIMITED, UNLIMITED, true); } } /** * Loads the selection with the default values for WAN */ private void loadWanSelection() { addLineSpeed("line_speed.auto_speed", AUTO_DETECT, AUTO_DETECT); addLineSpeed("line_speed.adsl128", 11, UNLIMITED); addLineSpeed("line_speed.adsl256", 23, UNLIMITED); addLineSpeed("line_speed.adsl512", 46, UNLIMITED); addLineSpeed("line_speed.adsl768", 69, UNLIMITED); addLineSpeed("line_speed.adsl1024", 128, UNLIMITED); addLineSpeed("line_speed.adsl1536", 192, UNLIMITED); addLineSpeed("line_speed.T1", 140, UNLIMITED); addLineSpeed("line_speed.T3", 3930, UNLIMITED); addLineSpeed("line_speed.unlimited", UNLIMITED, UNLIMITED); if (showCustomEntry) { addLineSpeed("line_speed.custom_speed", UNLIMITED, UNLIMITED, true); } } /** * Creates a LineSpeed instance with the given parameters then adds and * returns it. * * @param descr the translation property's name whose value will be used * @param uploadSpeed the upload speed in kb/s, 0 for unlimited * @param downloadSpeed the download speed in kb/s, 0 for unlimited * @return */ private LineSpeed addLineSpeed(String descr, long uploadSpeed, long downloadSpeed) { return addLineSpeed(descr, uploadSpeed, downloadSpeed, false); } /** * Creates a LineSpeed instance with the given parameters then adds and * returns it. * * @param descr the translation property's name whose value will be used * @param uploadSpeed the upload speed in kb/s, 0 for unlimited * @param downloadSpeed the download speed in kb/s, 0 for unlimited * @param editable true if the user should be allowed to modify the upload speed * setting. (The value of LineSpeed.uploadSpeed remains * untouched) * @return the line_speed entry. */ private LineSpeed addLineSpeed(String descr, long uploadSpeed, long downloadSpeed, boolean editable) { LineSpeed ls = new LineSpeed(Translation.getTranslation(descr), uploadSpeed, downloadSpeed, editable); addLineSpeed(ls); return ls; } /** * Adds the given LineSpeed to the selection list. * * @param speed */ public void addLineSpeed(LineSpeed speed) { speedSelectionBox.addItem(speed); } /** * Removes the given LineSpeed from the selection list. * * @param speed */ public void removeLineSpeed(LineSpeed speed) { speedSelectionBox.removeItem(speed); } /** * Updates the panel by selecting the correct Item for the given speed and * also updates the custom value field with that value. TODO: Since some * lines might have the same upload limit (like ISDN/DSL) this method * currenlty selects the first matching item. * * @param autodetect * @param uploadSpeed the upload speed in kb/s, 0 for unlimited * @param downloadSpeed the download speed in kb/s, 0 for unlimited */ public void setSpeedKBPS(boolean autodetect, long uploadSpeed, long downloadSpeed) { if (autodetect) { speedSelectionBox.setSelectedItem(AUTOMATIC_INDEX); } else { // Find the "best" item to select for the given speed // if none matches, falls thru to "Custom". int count = speedSelectionBox.getItemCount(); for (int i = 0; i < count; i++) { LineSpeed lineSpeed = speedSelectionBox.getItemAt(i); if (lineSpeed.getUploadSpeed() == uploadSpeed && lineSpeed.getDownloadSpeed() == downloadSpeed) { speedSelectionBox.setSelectedItem(lineSpeed); return; } } // It's not in the list of presets, it looks like a custom. if (showCustomEntry) { speedSelectionBox.setSelectedIndex(count - 1); // Custom is last item. customUploadSpeedSpinner.setValue(uploadSpeed); customDownloadSpeedSpinner.setValue(downloadSpeed); } } } public boolean isAutomatic() { return wan && speedSelectionBox.getSelectedIndex() == AUTOMATIC_INDEX; } /** * Returns the currently selected upload speed. * * @return The upload speed in kb/s or AUTO_DETECT if an error occured */ public long getUploadSpeedKBPS() { return customUploadSpeedSpinnerModel.getNumber().longValue() * 1024; } /** * Returns the currently selected download speed. * * @return The download speed in kb/s or AUTO_DETECT if an error occured */ public long getDownloadSpeedKBPS() { return customDownloadSpeedSpinnerModel.getNumber().longValue() * 1024; } public void setEnabled(boolean enabled) { customSpeedPanel.setEnabled(enabled); speedSelectionBox.setEnabled(enabled); customUploadSpeedSpinner.setEnabled(enabled); customDownloadSpeedSpinner.setEnabled(enabled); customUploadSpeedText.setEnabled(enabled); customDownloadSpeedText.setEnabled(enabled); } private static void updateLabel(JLabel label, long kbPerS) { if (kbPerS == 0) { label.setText(Translation.getTranslation("line_speed.unlimited")); } else { label.setText(kbPerS + " " + Translation.getTranslation("general.kbPerS")); } } // Inner classes ********************************************************** /** * Container holding the description and upload rate. */ private static class LineSpeed { private long uploadSpeed; private long downloadSpeed; private String desc; private boolean editable; /** * Creates a new LineSpeed * * @param desc the "name" of the speed value * @param uploadSpeed a value >= 0. If this value is below 0 the user may enter * a speed in Kilobytes per second. */ LineSpeed(String desc, long uploadSpeed, long downloadSpeed, boolean editable) { this.desc = desc; this.uploadSpeed = uploadSpeed; this.downloadSpeed = downloadSpeed; this.editable = editable; } public long getUploadSpeed() { return uploadSpeed; } public String toString() { return desc; } public boolean isEditable() { return editable; } public long getDownloadSpeed() { return downloadSpeed; } } private class MyChangeListener implements ChangeListener { private final JLabel label; private MyChangeListener(JLabel label) { this.label = label; } public void stateChanged(ChangeEvent e) { SpinnerNumberModel model = (SpinnerNumberModel) e.getSource(); long kbPerS = model.getNumber().longValue(); updateLabel(label, kbPerS); } } private class RecalculateAction extends BaseAction { private RecalculateAction(Controller controller) { super("action_recalculate", controller); } public void actionPerformed(ActionEvent e) { getController().getThreadPool().execute(new Runnable() { public void run() { TransferManager transferManager = getController().getTransferManager(); FutureTask<Object> task = transferManager.getRecalculateAutomaticRate(); getController().getThreadPool().execute(task); Cursor cursor = CursorUtils.setWaitCursor(getUiComponent()); try { task.get(); updateLabel(customUploadSpeedText, transferManager.getUploadCPSForWAN() / 1024); updateLabel(customDownloadSpeedText, transferManager.getDownloadCPSForWAN() / 1024); } catch (InterruptedException ex) { // Don't care } catch (ExecutionException ex) { // Don't care } finally { CursorUtils.returnToOriginal(getUiComponent(), cursor); } } }); } } }