Java tutorial
/* * TV-Browser * Copyright (C) 04-2003 Martin Oberhauser (darras@users.sourceforge.net) * * This program 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; either version 2 * of the License, or (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * CVS information: * $RCSfile$ * $Source$ * $Date: 2010-07-24 21:02:31 +0200 (Sat, 24 Jul 2010) $ * $Author: ds10 $ * $Revision: 6684 $ */ package tvbrowser.ui.update; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Font; import java.awt.Insets; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; import javax.swing.ScrollPaneConstants; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.WindowConstants; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import tvbrowser.core.Settings; import tvbrowser.core.icontheme.IconLoader; import util.browserlauncher.Launch; import util.exc.TvBrowserException; import util.ui.EnhancedPanelBuilder; import util.ui.LinkButton; import util.ui.Localizer; import util.ui.TVBrowserIcons; import util.ui.TextAreaIcon; import util.ui.UiUtilities; import util.ui.WindowClosingIf; import util.ui.customizableitems.ItemFilter; import util.ui.customizableitems.SelectableItem; import util.ui.customizableitems.SelectableItemList; import util.ui.customizableitems.SelectableItemRendererCenterComponentIf; import util.ui.html.HTMLTextHelper; import com.jgoodies.forms.builder.ButtonBarBuilder2; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import com.jgoodies.forms.layout.RowSpec; import com.jgoodies.forms.layout.Sizes; import devplugin.Version; /** * A dialog class that shows the plugin updates/new plugins. * */ public class SoftwareUpdateDlg extends JDialog implements ActionListener, ListSelectionListener, WindowClosingIf { /** The localizer for this class. */ private static final util.ui.Localizer mLocalizer = util.ui.Localizer.getLocalizerFor(SoftwareUpdateDlg.class); private JButton mCloseBtn, mDownloadBtn; private String mDownloadUrl; private JCheckBox mAutoUpdates; private SelectableItemList mSoftwareUpdateItemList; private int mLastIndex; private JButton mHelpBtn; private boolean mIsVersionChange; /** * Creates an instance of this class. * <p> * @param parent The parent dialog. * @param downloadUrl The url to download the data from. * @param onlyUpdate If this dialog should only show updates. * @param itemArr The array with the available update items. * @param isVersionChange If this dialog is shown for a TV-Browser version change. */ public SoftwareUpdateDlg(Window parent, String downloadUrl, boolean onlyUpdate, SoftwareUpdateItem[] itemArr, boolean isVersionChange) { super(parent); setModal(true); mIsVersionChange = isVersionChange; createGui(downloadUrl, onlyUpdate, itemArr); } /** * Creates an instance of this class. * <p> * @param parent The parent dialog. * @param downloadUrl The url to download the data from. * @param onlyUpdate If this dialog should only show updates. * @param itemArr The array with the available update items. */ public SoftwareUpdateDlg(Window parent, String downloadUrl, boolean onlyUpdate, SoftwareUpdateItem[] itemArr) { this(parent, downloadUrl, onlyUpdate, itemArr, false); } /** * Creates an instance of this class for drag-n-drop instead of normal plugin downloads. * <p> * @param parent The parent dialog. * @param onlyUpdate If this dialog should only show updates. * @param itemArr The array with the available update items. */ public SoftwareUpdateDlg(Window parent, boolean onlyUpdate, SoftwareUpdateItem[] itemArr) { this(parent, null, onlyUpdate, itemArr); } /** * Creates an instance of this class for drag-n-drop instead of normal plugin downloads. * <p> * @param parent The parent dialog. * @param onlyUpdate If this dialog should only show updates. * @param itemArr The array with the available update items. * @param isVersionChange If this dialog is shown for a TV-Browser version change. */ public SoftwareUpdateDlg(Window parent, boolean onlyUpdate, SoftwareUpdateItem[] itemArr, boolean isVersionChange) { this(parent, null, onlyUpdate, itemArr, isVersionChange); mSoftwareUpdateItemList.selectAll(); mDownloadBtn.setEnabled(mSoftwareUpdateItemList.getItemCount() > 0); } private void createGui(String downloadUrl, boolean onlyUpdate, SoftwareUpdateItem[] itemArr) { mDownloadUrl = downloadUrl; setTitle(mLocalizer.msg("title", "Download plugins")); if (mIsVersionChange) { setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); } JPanel contentPane = (JPanel) getContentPane(); contentPane.setLayout(new BorderLayout(0, 10)); contentPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 11, 11)); mCloseBtn = new JButton(Localizer.getLocalization(Localizer.I18N_CLOSE)); mCloseBtn.addActionListener(this); mCloseBtn.setEnabled(!mIsVersionChange); mDownloadBtn = new JButton(mLocalizer.msg("download", "Download selected items")); mDownloadBtn.addActionListener(this); mHelpBtn = new JButton(mLocalizer.msg("openWebsite", "Open website"), TVBrowserIcons.webBrowser(TVBrowserIcons.SIZE_SMALL)); mHelpBtn.addActionListener(this); mHelpBtn.setEnabled(false); ButtonBarBuilder2 builder = new ButtonBarBuilder2(); if (onlyUpdate && !mIsVersionChange) { mAutoUpdates = new JCheckBox(mLocalizer.msg("autoUpdates", "Find plugin updates automatically"), Settings.propAutoUpdatePlugins.getBoolean()); mAutoUpdates.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { Settings.propAutoUpdatePlugins.setBoolean(e.getStateChange() == ItemEvent.SELECTED); } }); builder.addFixed(mAutoUpdates); builder.addRelatedGap(); } builder.addFixed(mHelpBtn); builder.addGlue(); builder.addFixed(mDownloadBtn); builder.addRelatedGap(); builder.addFixed(mCloseBtn); final CellConstraints cc = new CellConstraints(); FormLayout layout = new FormLayout("default,5dlu,0dlu:grow", "default"); JPanel northPn = new JPanel(layout); northPn.add( new JLabel(onlyUpdate ? mLocalizer.msg("updateHeader", "Updates for installed plugins were found.") : mLocalizer.msg("header", "Here you can download new plugins and updates for it.")), cc.xyw(1, 1, 3)); JPanel southPn = new JPanel(new BorderLayout()); southPn.add(builder.getPanel(), BorderLayout.SOUTH); ArrayList<SoftwareUpdateItem> selectedItems = new ArrayList<SoftwareUpdateItem>(); for (SoftwareUpdateItem item : itemArr) { if (item.isAlreadyInstalled() && item.getInstalledVersion().compareTo(item.getVersion()) < 0) { selectedItems.add(item); } } mDownloadBtn.setEnabled(!selectedItems.isEmpty()); mSoftwareUpdateItemList = new SelectableItemList( selectedItems.toArray(new SoftwareUpdateItem[selectedItems.size()]), itemArr); mSoftwareUpdateItemList.addListSelectionListener(this); mSoftwareUpdateItemList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); mSoftwareUpdateItemList.setListUI(new MyListUI()); mSoftwareUpdateItemList.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); mSoftwareUpdateItemList.addCenterRendererComponent(PluginsSoftwareUpdateItem.class, new SelectableItemRendererCenterComponentIf() { private final ImageIcon NEW_VERSION_ICON = IconLoader.getInstance().getIconFromTheme("status", "software-update-available", 16); public JPanel createCenterPanel(JList list, Object value, int index, boolean isSelected, boolean isEnabled, JScrollPane parentScrollPane, int leftColumnWidth) { FormLayout lay = new FormLayout("5dlu,default,5dlu,default:grow", "2dlu,default,2dlu,fill:pref:grow,2dlu"); EnhancedPanelBuilder pb = new EnhancedPanelBuilder(lay); pb.getPanel().setOpaque(false); SoftwareUpdateItem item = (SoftwareUpdateItem) value; JLabel label = pb.addLabel( HTMLTextHelper.convertHtmlToText(item.getName()) + " " + item.getVersion(), cc.xy(2, 2)); label.setFont(label.getFont().deriveFont(Font.BOLD, label.getFont().getSize2D() + 2)); int width = parentScrollPane.getSize().width - parentScrollPane.getVerticalScrollBar().getWidth() - leftColumnWidth - Sizes.dialogUnitXAsPixel(5, pb.getPanel()) * 4 - parentScrollPane.getInsets().left - parentScrollPane.getInsets().right; if (width <= 0) { width = Settings.propColumnWidth.getInt(); } TextAreaIcon icon = new TextAreaIcon( HTMLTextHelper.convertHtmlToText(item.getDescription()), new JLabel().getFont(), width, 2); JLabel iconLabel = new JLabel(""); iconLabel.setIcon(icon); pb.add(iconLabel, cc.xyw(2, 4, 3)); JLabel label3 = new JLabel(); if (item.isAlreadyInstalled()) { Version installedVersion = item.getInstalledVersion(); if ((installedVersion != null) && (installedVersion.compareTo(item.getVersion()) < 0)) { label.setIcon(NEW_VERSION_ICON); label3.setText("(" + mLocalizer.msg("installed", "Installed version: ") + installedVersion.toString() + ")"); label3.setFont(label3.getFont().deriveFont(label3.getFont().getSize2D() + 2)); pb.add(label3, cc.xy(4, 2)); } } if (isSelected && isEnabled) { label.setForeground(list.getSelectionForeground()); String author = item.getProperty("author"); String website = item.getWebsite(); FormLayout authorAndWebsiteLayout = new FormLayout("default,5dlu,default", "default"); JPanel authorAndWebsite = new JPanel(authorAndWebsiteLayout); authorAndWebsite.setOpaque(false); if (author != null) { lay.appendRow(RowSpec.decode("2dlu")); lay.appendRow(RowSpec.decode("default")); lay.appendRow(RowSpec.decode("2dlu")); pb.add(authorAndWebsite, cc.xyw(2, 7, 3)); JLabel authorLabel = new JLabel(mLocalizer.msg("author", "Author")); authorLabel.setFont(authorLabel.getFont().deriveFont(Font.BOLD)); authorLabel.setForeground(list.getSelectionForeground()); authorLabel.setHorizontalAlignment(SwingConstants.RIGHT); JLabel authorName = new JLabel(HTMLTextHelper.convertHtmlToText(author)); authorName.setForeground(list.getSelectionForeground()); authorAndWebsite.add(authorLabel, cc.xy(1, 1)); authorAndWebsite.add(authorName, cc.xy(3, 1)); } if (website != null) { if (author == null) { lay.appendRow(RowSpec.decode("2dlu")); lay.appendRow(RowSpec.decode("default")); lay.appendRow(RowSpec.decode("2dlu")); pb.add(authorAndWebsite, cc.xyw(2, 7, 3)); } else { authorAndWebsiteLayout.appendRow(RowSpec.decode("1dlu")); authorAndWebsiteLayout.appendRow(RowSpec.decode("default")); } JLabel webLabel = new JLabel(mLocalizer.msg("website", "Website")); webLabel.setFont(webLabel.getFont().deriveFont(Font.BOLD)); webLabel.setForeground(list.getSelectionForeground()); webLabel.setHorizontalAlignment(SwingConstants.RIGHT); LinkButton webLink = new LinkButton(HTMLTextHelper.convertHtmlToText(website)); webLink.setForeground(list.getSelectionForeground()); authorAndWebsite.add(webLabel, cc.xy(1, author == null ? 1 : 3)); authorAndWebsite.add(webLink, cc.xy(3, author == null ? 1 : 3)); } icon.setMaximumLineCount(-1); iconLabel.setForeground(list.getSelectionForeground()); label3.setForeground(list.getSelectionForeground()); } else { if (!item.isStable()) { label.setForeground(new Color(200, 0, 0)); } else { label.setForeground(list.getForeground()); } icon.setMaximumLineCount(1); iconLabel.setForeground(list.getSelectionForeground()); iconLabel.setForeground(list.getForeground()); label3.setForeground(Color.gray); } return pb.getPanel(); } public void calculateSize(JList list, int index, JPanel contPane) { if (list.getUI() instanceof MyListUI) { ((MyListUI) list.getUI()).setCellHeight(index, contPane.getPreferredSize().height); } } }); mSoftwareUpdateItemList.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (SwingUtilities.isRightMouseButton(e) && e.isPopupTrigger()) { showPopupMenu(e); } } @Override public void mouseReleased(MouseEvent e) { if (SwingUtilities.isRightMouseButton(e) && e.isPopupTrigger()) { showPopupMenu(e); } } }); if (!onlyUpdate) { layout.appendRow(RowSpec.decode("5dlu")); layout.appendRow(RowSpec.decode("default")); JLabel filterLabel = new JLabel( mLocalizer.msg("filterLabel", "Show only Plugins with the following category:")); northPn.add(filterLabel, cc.xy(1, 3)); ArrayList<FilterItem> filterList = new ArrayList<FilterItem>(0); for (SoftwareUpdateItem item : itemArr) { int index = 0; for (int i = 0; i < filterList.size(); i++) { int compareValue = filterList.get(i).compareTo(item.getCategory()); if (compareValue == 0) { index = -1; break; } else if (compareValue < 0) { index = i + 1; } } if (index != -1) { filterList.add(index, new FilterItem(item.getCategory())); } } filterList.add(0, new FilterItem("all")); JComboBox filterBox = new JComboBox(filterList.toArray()); mSoftwareUpdateItemList.setFilterComboBox(filterBox); northPn.add(filterBox, cc.xy(3, 3)); } contentPane.add(northPn, BorderLayout.NORTH); contentPane.add(mSoftwareUpdateItemList, BorderLayout.CENTER); contentPane.add(southPn, BorderLayout.SOUTH); Settings.layoutWindow("softwareUpdateDlg", this, new Dimension(700, 600)); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { if (!mIsVersionChange || mSoftwareUpdateItemList.getSelection().length == 0) { close(); } } }); UiUtilities.registerForClosing(this); } public void actionPerformed(ActionEvent event) { if (event.getSource() == mCloseBtn) { close(); } else if (event.getSource() == mDownloadBtn) { mDownloadBtn.setEnabled(false); Cursor cursor = getCursor(); this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); int successfullyDownloadedItems = 0; try { Object[] objects = mSoftwareUpdateItemList.getSelection(); for (Object object : objects) { SoftwareUpdateItem item = (SoftwareUpdateItem) object; try { item.download(mDownloadUrl); successfullyDownloadedItems++; } catch (TvBrowserException e) { util.exc.ErrorHandler.handle(e); } } } finally { mDownloadBtn.setEnabled(true); setCursor(cursor); } if (successfullyDownloadedItems > 0 && !mIsVersionChange) { JOptionPane.showMessageDialog(null, mLocalizer.msg("restartprogram", "please restart tvbrowser before...")); close(); } else if (mIsVersionChange) { close(); } } else if (event.getSource() == mHelpBtn) { final SoftwareUpdateItem item = (SoftwareUpdateItem) ((SelectableItem) mSoftwareUpdateItemList .getSelectedValue()).getItem(); if (item != null) { Launch.openURL(item.getWebsite()); } } } public void valueChanged(ListSelectionEvent event) { mDownloadBtn.setEnabled(mSoftwareUpdateItemList.getSelection().length > 0); if (mIsVersionChange) { mCloseBtn.setEnabled(mSoftwareUpdateItemList.getSelection().length == 0); } if (event.getSource() instanceof JList) { if (!event.getValueIsAdjusting()) { JList list = ((JList) event.getSource()); if (mLastIndex != -1 && list.getSelectedIndex() != mLastIndex && list.getModel().getSize() - 1 >= mLastIndex) { ((MyListUI) list.getUI()).setCellHeight(mLastIndex, list.getCellRenderer().getListCellRendererComponent(list, list.getModel().getElementAt(mLastIndex), mLastIndex, false, false) .getPreferredSize().height); } mLastIndex = list.getSelectedIndex(); if (mLastIndex < 0) { mHelpBtn.setEnabled(false); } else { SoftwareUpdateItem item = (SoftwareUpdateItem) ((SelectableItem) mSoftwareUpdateItemList .getSelectedValue()).getItem(); String website = item.getWebsite(); mHelpBtn.setEnabled(website != null && website.length() > 0); } } } mSoftwareUpdateItemList.calculateSize(); } public void close() { setVisible(false); dispose(); } private static class MyListUI extends javax.swing.plaf.basic.BasicListUI { protected synchronized void setCellHeight(int row, int height) { cellHeights[row] = height; } @Override public Dimension getPreferredSize(JComponent c) { int width = super.getPreferredSize(c).width; int height = 0; Insets i = c.getInsets(); height += i.top + i.bottom; for (int localCellHeight : cellHeights) { height += localCellHeight; } return new Dimension(width, height); } } private void showPopupMenu(MouseEvent e) { if (e.getSource() instanceof JList) { JList list = (JList) e.getSource(); Object listItem = list.getModel().getElementAt(list.locationToIndex(e.getPoint())); if (listItem instanceof SelectableItem) { final Object item = ((SelectableItem) listItem).getItem(); if (item instanceof SoftwareUpdateItem) { if (((SoftwareUpdateItem) item).getWebsite() != null) { JPopupMenu menu = new JPopupMenu(); JMenuItem menuItem = new JMenuItem(mLocalizer.msg("openWebsite", "Open website"), TVBrowserIcons.webBrowser(TVBrowserIcons.SIZE_SMALL)); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Launch.openURL(((SoftwareUpdateItem) item).getWebsite()); } }); menu.add(menuItem); menu.show(e.getComponent(), e.getX(), e.getY()); } } } } } private static class FilterItem implements ItemFilter { private String mType; protected FilterItem(String type) { mType = type; } @Override public String toString() { return mLocalizer.msg(mType, mType); } @Override public boolean equals(Object o) { if (o != null) { if (o instanceof FilterItem) { return mType.equals(((FilterItem) o).mType); } else if (o instanceof String) { return mType.equals(o); } } return false; } /** * Compares the names of this filter item and * the given Object if it is a filter item or * if the given Object is a String with it's * internalisation. * <p> * @param o The Object to compare with * @return < 0 if the name of this item is alphabetical smaller as the given String * 0 if they are equal and > 0 if this name is greater. */ public int compareTo(Object o) { if (o != null) { if (o instanceof FilterItem) { return toString().compareToIgnoreCase(((FilterItem) o).toString()); } else if (o instanceof String) { return toString().compareToIgnoreCase(mLocalizer.msg((String) o, (String) o)); } } return 0; } public boolean accept(Object o) { if (o instanceof SoftwareUpdateItem) { if (mType.equals("all")) { return true; } return equals(((SoftwareUpdateItem) o).getCategory()); } return false; } } }