Java tutorial
/* * TV-Browser * Copyright (C) 04-2003 Martin Oberhauser (martin_oat@yahoo.de) * * 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-06-28 19:33:48 +0200 (Mon, 28 Jun 2010) $ * $Author: bananeweizen $ * $Revision: 6662 $ */ package listviewplugin; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Calendar; import java.util.Iterator; import java.util.Properties; import java.util.Timer; import java.util.TimerTask; import java.util.Vector; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSpinner; import javax.swing.ScrollPaneConstants; import javax.swing.SpinnerDateModel; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.table.TableColumn; import tvbrowser.core.Settings; import tvbrowser.core.filters.FilterComponent; import tvbrowser.core.filters.FilterComponentList; import tvbrowser.core.filters.filtercomponents.ChannelFilterComponent; import tvbrowser.ui.filter.dlgs.EditFilterComponentDlg; import util.io.IOUtilities; import util.ui.CaretPositionCorrector; import util.ui.Localizer; import util.ui.TVBrowserIcons; import util.ui.TimeFormatter; import util.ui.UiUtilities; import util.ui.WindowClosingIf; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import devplugin.Channel; import devplugin.Date; import devplugin.Plugin; import devplugin.Program; import devplugin.ProgramFilter; import devplugin.SettingsItem; /** * Creates a Dialog with a List of Programs * * @author bodo */ public class ListViewDialog extends JDialog implements WindowClosingIf { /** The localizer used by this class. */ private static final util.ui.Localizer mLocalizer = util.ui.Localizer.getLocalizerFor(ListViewDialog.class); /** The Table */ private ListTable mProgramTable; /** The Table-Model */ private ListTableModel mModel; /** Runs at ... */ private JRadioButton mRuns = new JRadioButton(mLocalizer.msg("runs", "Running")); /** Runs on ... */ private JRadioButton mOn = new JRadioButton(mLocalizer.msg("on", "On")); /** Date-Select for mOn */ private JComboBox mDate; /** Time-Spinner for mOn */ private JSpinner mTimeSpinner = new JSpinner(new SpinnerDateModel()); /** Text for mRuns */ private final static String[] TIMETEXT = { mLocalizer.msg("now", "Now"), mLocalizer.msg("15min", "in 15 minutes"), mLocalizer.msg("30min", "in 30 minutes") }; /** Select for mRuns */ private JComboBox mBox; /** channel filter selection */ private JComboBox mChannels; /** Times */ private int[] mTimes; /** Plugin that created the Dialog */ private Plugin mPlugin; /** Timer for Updates */ private Timer mTimer; /** Settings for this Plugin */ private Properties mSettings; private Thread mLeftClickThread; private boolean mPerformingSingleClick; private Thread mMiddleSingleClickThread; private boolean mPerformingMiddleSingleClick; private JComboBox mFilterBox; private ProgramFilter mCurrentFilter; /** * Creates the Dialog * * @param frame Frame for modal * @param plugin Plugin for reference * @param settings The settings of the ListViewPlugin */ public ListViewDialog(Frame frame, Plugin plugin, Properties settings) { super(frame, true); setTitle(mLocalizer.msg("viewList", "View List:")); mPlugin = plugin; mSettings = settings; mTimes = Plugin.getPluginManager().getTvBrowserSettings().getTimeButtonTimes(); mModel = new ListTableModel(); mPerformingSingleClick = false; mCurrentFilter = Plugin.getPluginManager().getFilterManager().getCurrentFilter(); generateList(new Date(), getCurrentTime()); createGUI(); addChangeTimer(); UiUtilities.registerForClosing(this); } /** * Create Change-Thread that updates the Dialog every 10 seconds */ private void addChangeTimer() { int delay = 2000; // delay for 2 sec. int period = 2000; // repeat every 2 secs. mTimer = new Timer(); mTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { if (mRuns.isSelected()) { refreshView(); } } }, delay, period); } /** * Returns the current Time in minutes * * @return Time in minutes */ private int getCurrentTime() { Calendar cal = Calendar.getInstance(); return cal.get(Calendar.HOUR_OF_DAY) * 60 + cal.get(Calendar.MINUTE); } /** * Generates the List of Programs */ private void generateList(Date date, int time) { // If Time > 24 try next Day if (time > 60 * 24) { date = date.addDays(1); time -= 60 * 24; } Channel[] channels = Plugin.getPluginManager().getSubscribedChannels(); if ((mChannels != null) && (mChannels.getSelectedIndex() > 0)) { FilterComponent component = FilterComponentList.getInstance() .getFilterComponentByName(mChannels.getSelectedItem().toString()); if (component instanceof ChannelFilterComponent) { channels = ((ChannelFilterComponent) component).getChannels(); } } for (Channel channel : channels) { Program prg = findProgram(date, time, channel, false); Program nprg = null; if (prg == null) { prg = findProgram(date.addDays(-1), time + 60 * 24, channel, false); } if (prg != null) { nprg = findNextProgram(prg); } else { Iterator<Program> it = Plugin.getPluginManager().getChannelDayProgram(date, channel); if (it.hasNext()) { Program p = it.next(); if (p.getStartTime() > time && mCurrentFilter.accept(p)) { nprg = p; } else { nprg = findProgram(date, time + 60, channel, true); } } else { nprg = findProgram(date, time + 60, channel, true); } if (nprg == null) { it = Plugin.getPluginManager().getChannelDayProgram(date.addDays(1), channel); while (it.hasNext() && nprg == null) { Program p = it.next(); if (!p.isExpired() && mCurrentFilter.accept(p)) { nprg = p; } } } } mModel.updateRow(channel, prg, nprg); } } /** * Finds the program after the given Program * * @param prg Search Program after this * @return following Program */ private Program findNextProgram(Program prg) { Iterator<Program> it = Plugin.getPluginManager().getChannelDayProgram(prg.getDate(), prg.getChannel()); Program nprg = null; boolean last = false; while (it.hasNext()) { Program p = it.next(); if (prg.equals(p) && it.hasNext()) { while (it.hasNext()) { Program test = it.next(); if (!test.isExpired() && mCurrentFilter.accept(test)) { return test; } } last = true; } else if (prg.equals(p) && !it.hasNext()) { last = true; } } if (last) { it = Plugin.getPluginManager().getChannelDayProgram(prg.getDate().addDays(1), prg.getChannel()); while (it.hasNext()) { Program p = it.next(); if (!p.isExpired() && mCurrentFilter.accept(p)) { return p; } } } return nprg; } /** * Finds a Program for a Date/time on a certain Channel * * @param date Date * @param time Time * @param channel Channel * @return added a Program */ private Program findProgram(Date date, int time, Channel channel, boolean next) { for (Iterator<Program> it = Plugin.getPluginManager().getChannelDayProgram(date, channel); it.hasNext();) { Program program = it.next(); int start = program.getStartTime(); int ende = program.getStartTime() + program.getLength(); if (((!next && (start <= time) && (ende > time)) || (next && start > IOUtilities.getMinutesAfterMidnight())) && mCurrentFilter.accept(program)) { return program; } } return null; } /** * Calculates the Time based on the current selection * * @param selectedIndex # of selection * @return calculated Time */ private int calcTimeForSelection(int selectedIndex) { int time = getCurrentTime(); if (selectedIndex == 1) { return time + 15; } else if (selectedIndex == 2) { return time + 30; } else if (selectedIndex > 2) { return mTimes[selectedIndex - 3]; } return time; } /** * Creates the GUI */ private void createGUI() { JPanel content = (JPanel) this.getContentPane(); content.setLayout(new BorderLayout()); content.setBorder(UiUtilities.DIALOG_BORDER); Vector<String> data = new Vector<String>(); data.add(TIMETEXT[0]); data.add(TIMETEXT[1]); data.add(TIMETEXT[2]); TimeFormatter formatter = new TimeFormatter(); for (int time : mTimes) { int h = time / 60; int m = time % 60; StringBuilder builder = new StringBuilder(); builder.append(mLocalizer.msg("at", "at")); builder.append(' '); builder.append(formatter.formatTime(h, m)); data.add(builder.toString()); } data.add(mLocalizer.msg("configureTimes", "Configure Times")); mBox = new JComboBox(data); mBox.addActionListener(new ActionListener() { private int lastSelected = 0; public void actionPerformed(ActionEvent e) { if (mBox.getSelectedIndex() == mBox.getItemCount() - 1) { mBox.setSelectedIndex(lastSelected); Plugin.getPluginManager().showSettings(SettingsItem.TIMEBUTTONS); } else { lastSelected = mDate.getSelectedIndex(); int time = calcTimeForSelection(mBox.getSelectedIndex()); generateList(new Date(), time); } } }); ButtonGroup group = new ButtonGroup(); group.add(mRuns); group.add(mOn); JPanel datetimeselect = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); Vector<Date> dates = new Vector<Date>(); Date currentDate = Date.getCurrentDate(); for (int i = 0; i < 14; i++) { dates.add(currentDate.addDays(i)); } mDate = new JComboBox(dates); datetimeselect.add(mDate); datetimeselect.add(new JLabel(" " + mLocalizer.msg("at", "at") + " ")); JSpinner.DateEditor dateEditor = new JSpinner.DateEditor(mTimeSpinner, Settings.getTimePattern()); mTimeSpinner.setEditor(dateEditor); CaretPositionCorrector.createCorrector(dateEditor.getTextField(), new char[] { ':' }, -1); datetimeselect.add(mTimeSpinner); Vector<String> filters = new Vector<String>(); filters.add(mLocalizer.msg("filterAll", "all channels")); for (String filterName : FilterComponentList.getInstance().getChannelFilterNames()) { filters.add(filterName); } filters.add(mLocalizer.ellipsisMsg("filterDefine", "define filter")); mChannels = new JComboBox(filters); datetimeselect.add(new JLabel(" ")); datetimeselect.add(mChannels); // Event-Handler mRuns.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { refreshView(); } }); mOn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { refreshView(); } }); mDate.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { refreshView(); } }); mTimeSpinner.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent arg0) { refreshView(); } }); mChannels.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // user defined selection if (mChannels.getSelectedIndex() == mChannels.getItemCount() - 1) { EditFilterComponentDlg dlg = new EditFilterComponentDlg(null, null, ChannelFilterComponent.class); FilterComponent rule = dlg.getFilterComponent(); if (rule == null) { return; } if (!(rule instanceof ChannelFilterComponent)) { return; } FilterComponentList.getInstance().add(rule); FilterComponentList.getInstance().store(); String filterName = rule.getName(); mChannels.removeAllItems(); mChannels.addItem(mLocalizer.msg("filterAll", "all channels")); for (String channel : FilterComponentList.getInstance().getChannelFilterNames()) { mChannels.addItem(channel); } mChannels.addItem(mLocalizer.ellipsisMsg("filterDefine", "define filter")); mChannels.setSelectedItem(filterName); } mModel.removeAllRows(); refreshView(); } }); mRuns.setSelected(true); mDate.setEnabled(false); mTimeSpinner.setEnabled(false); JLabel filterLabel = new JLabel("Filter:"); filterLabel.setHorizontalAlignment(SwingConstants.RIGHT); mFilterBox = new JComboBox(Plugin.getPluginManager().getFilterManager().getAvailableFilters()); mFilterBox.setSelectedItem(Plugin.getPluginManager().getFilterManager().getCurrentFilter()); mFilterBox.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { mCurrentFilter = (ProgramFilter) e.getItem(); refreshView(); } } }); // Upper Panel JPanel topPanel = new JPanel( new FormLayout("pref, 3dlu, pref, 15dlu, pref, 3dlu, pref, 3dlu, pref", "pref, 1dlu, pref, 3dlu")); CellConstraints cc = new CellConstraints(); topPanel.add(mRuns, cc.xy(1, 1)); topPanel.add(mBox, cc.xy(3, 1)); topPanel.add(mOn, cc.xy(5, 1)); topPanel.add(datetimeselect, cc.xy(7, 1)); topPanel.add(filterLabel, cc.xy(1, 3)); topPanel.add(mFilterBox, cc.xyw(3, 3, 5)); content.add(topPanel, BorderLayout.NORTH); // Rest of the GUI mProgramTable = new ListTable(mModel); mProgramTable.getTableHeader().setReorderingAllowed(false); mProgramTable.getTableHeader().setResizingAllowed(false); mProgramTable.setToolTipText(""); mProgramTable.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent evt) { if (evt.isPopupTrigger()) { showPopup(evt); } } @Override public void mouseReleased(MouseEvent evt) { if (evt.isPopupTrigger()) { showPopup(evt); } } @Override public void mouseClicked(MouseEvent e) { mouseClickedOnTable(e); } }); // Dispatch the KeyEvent to the RootPane for Closing the Dialog. // Needed for Java 1.4. mProgramTable.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { mProgramTable.getRootPane().dispatchEvent(e); } }); setTableColumProperties(); JScrollPane scroll = new JScrollPane(mProgramTable, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); content.add(scroll, BorderLayout.CENTER); JPanel buttonPn = new JPanel(new BorderLayout()); buttonPn.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0)); content.add(buttonPn, BorderLayout.SOUTH); JButton closeButton = new JButton(Localizer.getLocalization(Localizer.I18N_CLOSE)); closeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { dispose(); } }); JPanel p = new JPanel(new FormLayout("pref,5dlu,pref,5dlu,pref", "pref")); JButton settings = new JButton(TVBrowserIcons.preferences(TVBrowserIcons.SIZE_SMALL)); settings.setToolTipText(mLocalizer.msg("settings", "Open settings")); settings.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { close(); Plugin.getPluginManager().showSettings(ListViewPlugin.getInstance()); } }); final JCheckBox showAtStartup = new JCheckBox(mLocalizer.msg("showAtStart", "Show at start")); showAtStartup.setSelected(mSettings.getProperty("showAtStartup", "false").equals("true")); showAtStartup.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { if (showAtStartup.isSelected()) { mSettings.setProperty("showAtStartup", "true"); } else { mSettings.setProperty("showAtStartup", "false"); } } }); p.add(settings, cc.xy(1, 1)); p.add(showAtStartup, cc.xy(3, 1)); buttonPn.add(p, BorderLayout.WEST); buttonPn.add(closeButton, BorderLayout.EAST); getRootPane().setDefaultButton(closeButton); } /** * Sets the Table-Properties */ private void setTableColumProperties() { ListTableCellRenderer renderer = new ListTableCellRenderer(mModel.getRowCount()); int width = ListViewPlugin.PROGRAMTABLEWIDTH; for (int i = 0; i <= 2; i++) { TableColumn column = mProgramTable.getColumnModel().getColumn(i); column.setCellRenderer(renderer); if (i > 0) { column.setMinWidth(width); } } } /** * Refresh the List with current settings */ private void refreshView() { mBox.setEnabled(mRuns.isSelected()); mDate.setEnabled(mOn.isSelected()); mTimeSpinner.setEnabled(mOn.isSelected()); if (mRuns.isSelected()) { int time = calcTimeForSelection(mBox.getSelectedIndex()); generateList(new Date(), time); } else { java.util.Date startTime = (java.util.Date) mTimeSpinner.getValue(); Calendar cal = Calendar.getInstance(); cal.setTime(startTime); int minutes = cal.get(Calendar.HOUR_OF_DAY) * 60 + cal.get(Calendar.MINUTE); generateList((Date) mDate.getSelectedItem(), minutes); } } /** * Called when a Mouse-Event occurs * * @param e Event */ private void mouseClickedOnTable(final MouseEvent e) { final Program prg = getProgramByClick(e); if (prg == null) { return; } if (SwingUtilities.isLeftMouseButton(e) && (e.getClickCount() == 1) && e.getModifiersEx() == 0) { mLeftClickThread = new Thread("Single left click") { @Override public void run() { try { mPerformingSingleClick = false; sleep(Plugin.SINGLE_CLICK_WAITING_TIME); mPerformingSingleClick = true; Plugin.getPluginManager().handleProgramSingleClick(prg, mPlugin); mPerformingSingleClick = false; } catch (InterruptedException e) { // ignore } } }; mLeftClickThread.setPriority(Thread.MIN_PRIORITY); mLeftClickThread.start(); } else if (SwingUtilities.isLeftMouseButton(e) && (e.getClickCount() == 2) && e.getModifiersEx() == 0) { if (!mPerformingSingleClick && mLeftClickThread != null && mLeftClickThread.isAlive()) { mLeftClickThread.interrupt(); } if (!mPerformingSingleClick) { devplugin.Plugin.getPluginManager().handleProgramDoubleClick(prg, mPlugin); } } else if (SwingUtilities.isMiddleMouseButton(e) && (e.getClickCount() == 1)) { mMiddleSingleClickThread = new Thread("Single click") { @Override public void run() { try { mPerformingMiddleSingleClick = false; sleep(Plugin.SINGLE_CLICK_WAITING_TIME); mPerformingMiddleSingleClick = true; Plugin.getPluginManager().handleProgramMiddleClick(prg, mPlugin); mPerformingMiddleSingleClick = false; } catch (InterruptedException e) { // ignore } } }; mMiddleSingleClickThread.setPriority(Thread.MIN_PRIORITY); mMiddleSingleClickThread.start(); } else if (SwingUtilities.isMiddleMouseButton(e) && (e.getClickCount() == 2)) { if (!mPerformingMiddleSingleClick && mMiddleSingleClickThread != null && mMiddleSingleClickThread.isAlive()) { mMiddleSingleClickThread.interrupt(); } if (!mPerformingMiddleSingleClick) { devplugin.Plugin.getPluginManager().handleProgramMiddleDoubleClick(prg, mPlugin); } } } /** * Gets the Program the User has clicked on * @param e MouseEvent to determine the Program * @return Program the User has clicked on */ private Program getProgramByClick(MouseEvent e) { int col = mProgramTable.getColumnModel().getColumnIndexAtX(e.getX()); int row = mProgramTable.rowAtPoint(e.getPoint()); mProgramTable.setRowSelectionInterval(row, row); Program prg = null; if (col == 1) { prg = mModel.getProgram(row); } else if (col == 2) { prg = mModel.getNextProgram(row); } return prg; } /** * Shows the Popup * @param e Mouse-Event */ private void showPopup(MouseEvent e) { Program prg = getProgramByClick(e); if (prg == null) { return; } JPopupMenu menu = devplugin.Plugin.getPluginManager().createPluginContextMenu(prg, mPlugin); menu.show(mProgramTable, e.getX() - 15, e.getY() - 15); } @Override public void setVisible(boolean b) { super.setVisible(b); mTimer.cancel(); } public void close() { dispose(); } }