/* $Id: DaySummaryDialog.java 124 2008-03-06 07:19:25Z bananeweizen $
* GNU GPL Version 2, Copyright (C) 2005 Paul C. Kunysch */
package de.kunysch.tvbrowser.localimdb;
import java.awt.*;
import java.awt.event.*;
import java.security.InvalidParameterException;
import java.text.MessageFormat;
import java.util.Iterator;
import java.util.Set;
import javax.swing.*;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.ListSelectionEvent;
import util.ui.Localizer;
import de.kunysch.localimdb.Movie;
import de.kunysch.tvbrowser.Settings;
import devplugin.*;
/**
* This dialog can display day summaries. It can also be used to display data
* for one program.
*/
public class DaySummaryDialog extends JDialog {
private static Localizer mLocalizer = util.ui.Localizer.getLocalizerFor(DaySummaryDialog.class);
private static final long serialVersionUID = 1L;
private devplugin.Date day;
private JTable table;
private Plugin plugin;
private JButton nextDayBtn, prevDayBtn, ignoreBtn;
private final MessageFormat titleFormat;
private final MessageFormat titleFormatShowAll;
/**
* This constructor creates a day summary dialog for the current day.
*
* @param plugin
* is the LocalImdb Plugin that will search movie ratings.
* @param parent
* is the parent for the Dialog, it may be null.
*/
public DaySummaryDialog(Plugin plugin, Frame parent) {
this(plugin, parent, devplugin.Plugin.getPluginManager().getCurrentDate());
}
private DaySummaryDialog(Plugin plugin, Frame parent, Date day) {
super(parent, true);
getRootPane().getGlassPane().addMouseListener(new MouseAdapter() {
});
this.plugin = plugin;
this.day = day;
this.titleFormat = new MessageFormat(mLocalizer.msg("title", "Day summary - {0,date} - LocalImdb {1}")); //$NON-NLS-1$
this.titleFormatShowAll = new MessageFormat(mLocalizer.msg(
"title.all", "Day summary - {0,date}-{1,date} - LocalImdb {2}")); //$NON-NLS-1$
final Settings settings = SettingsKeys.getSettings();
setLocation(settings.getInt(SettingsKeys.DIALOG_X), settings.getInt(SettingsKeys.DIALOG_Y));
setSize(settings.getInt(SettingsKeys.DIALOG_W), settings.getInt(SettingsKeys.DIALOG_H));
updateDialog(0);
initColumnLayout();
}
/**
* This constructor creates a dialog that shows one program.
*
* @param plugin
* is the LocalImdb Plugin that will search movie ratings.
* @param parent
* is the parent for the Dialog, it may be null.
* @param prog
* is the program that will be highlighted.
*/
public DaySummaryDialog(Plugin plugin, Frame parent, Program prog) {
this(plugin, parent, prog.getDate().addDays(
prog.getStartTime() < devplugin.Plugin.getPluginManager().getTvBrowserSettings().getProgramTableEndOfDay() ? -1
: 0));
final DaySummaryTableModel model = ((DaySummaryTableModel) table.getModel());
model.onColumnClicked(0);
int firstRow = model.select(prog, table.getSelectionModel());
if (-1 == firstRow) {
throw new InvalidParameterException(mLocalizer.msg("err.notrated", "Program is not rated")); //$NON-NLS-1$
}
Rectangle firstRowRect = table.getCellRect(firstRow, 0, true);
if (null != firstRowRect) {
table.scrollRectToVisible(firstRowRect);
}
}
/**
* This internal function is used to change the current day.
*
* @param addDays
* may be -1 for the previous or 1 for the next day. To recreate the
* data for the current day 0 may be used here.
*/
private void updateDialog(int addDays) {
day = day.addDays(addDays);
Date nextDay = day.addDays(1);
DaySummaryTableModel model = new DaySummaryTableModel(table.getModel());
Channel[] channels = devplugin.Plugin.getPluginManager().getSubscribedChannels();
if (null == channels || 0 == channels.length) {
return;
}
for (int i = 0; i < channels.length; ++i) {
if (plugin.isChannelHidden(channels[i])) {
continue;
}
Iterator<Program> iter = devplugin.Plugin.getPluginManager().getChannelDayProgram(day, channels[i]);
final int startOfDay = devplugin.Plugin.getPluginManager().getTvBrowserSettings().getProgramTableStartOfDay();
try {
if (iter != null) {
while (iter.hasNext()) {
Program prog = iter.next();
if (prog.getTimeField(ProgramFieldType.START_TIME_TYPE) < startOfDay) {
continue;
}
Set<Movie>[] movies = plugin.findMovies(prog);
if (null != movies) {
model.addSearchResult(prog, movies[0], movies[1]);
}
}
}
} catch (NullPointerException e) {
}
iter = devplugin.Plugin.getPluginManager().getChannelDayProgram(nextDay, channels[i]);
final int endOfDay = devplugin.Plugin.getPluginManager().getTvBrowserSettings().getProgramTableEndOfDay();
try {
if (iter != null) {
while (iter.hasNext()) {
Program prog = iter.next();
if (prog.getTimeField(ProgramFieldType.START_TIME_TYPE) > endOfDay) {
continue;
}
Set<Movie>[] movies = plugin.findMovies(prog);
if (null != movies) {
model.addSearchResult(prog, movies[0], movies[1]);
}
}
}
} catch (NullPointerException e) {
}
}
final Object[] args = { day.getCalendar().getTime(), plugin.getInfo().getVersion().toString() };
setTitle(titleFormat.format(args));
model.sort();
table.setModel(model);
}
private void updateShowAll() {
DaySummaryTableModel model = new DaySummaryTableModel(table.getModel());
model.onColumnClicked(1);
model.onColumnClicked(0); // Now it's sorted by date.
Channel[] channels = devplugin.Plugin.getPluginManager().getSubscribedChannels();
if (null == channels || 0 == channels.length) {
return;
}
Date dayCursor = day;
for (boolean gotData = true; gotData; dayCursor = dayCursor.addDays(-1)) {
gotData = false;
for (int i = 0; i < channels.length; ++i) {
final Iterator<Program> iter = devplugin.Plugin.getPluginManager().getChannelDayProgram(dayCursor, channels[i]);
if (null == iter || !iter.hasNext()) {
continue;
}
gotData = true;
break;
}
}
final Date firstDay = dayCursor = dayCursor.addDays(2);
for (boolean gotData = true; gotData; dayCursor = dayCursor.addDays(1)) {
gotData = false;
for (int i = 0; i < channels.length; ++i) {
if (plugin.isChannelHidden(channels[i])) {
continue;
}
Iterator<Program> iter = devplugin.Plugin.getPluginManager().getChannelDayProgram(dayCursor, channels[i]);
if (null == iter) {
continue;
}
gotData = true;
while (iter.hasNext()) {
Program prog = iter.next();
Set<Movie>[] movies = plugin.findMovies(prog);
if (null != movies) {
model.addSearchResult(prog, movies[0], movies[1]);
}
}
}
}
final Object[] args = { firstDay.getCalendar().getTime(), dayCursor.addDays(-1).getCalendar().getTime(),
plugin.getInfo().getVersion().toString() };
setTitle(titleFormatShowAll.format(args));
model.sort();
table.setModel(model);
}
/**
* This initialized the TableColumnModel. It tries to load a layout from the
* settings.
*/
private void initColumnLayout() {
String[] colSizes = SettingsKeys.getSettings().getList(SettingsKeys.DIALOG_COLS);
final TableColumnModel colModel = table.getColumnModel();
if (colSizes.length != 16) {
colSizes = new String[16];
for (int i = 0; i < colSizes.length; i += 2) {
colSizes[i] = Integer.toString(i / 2);
colSizes[i + 1] = "75"; //$NON-NLS-1$
}
}
System.out.flush();
for (int i = 0; i < colSizes.length; i += 2) {
final int modelIndex = Integer.parseInt(colSizes[i]);
final int colWidth = Integer.parseInt(colSizes[i + 1]);
final TableColumn newColumn = new TableColumn();
newColumn.setHeaderValue(table.getModel().getColumnName(modelIndex));
newColumn.setModelIndex(modelIndex);
newColumn.setWidth(colWidth);
newColumn.setPreferredWidth(colWidth);
colModel.addColumn(newColumn);
}
}
public void onTableSelectionChanged(boolean adjusting) {
ignoreBtn.setEnabled(0 != table.getSelectedRowCount());
}
public void onIgnoreSelectedPrograms() {
final DaySummaryTableModel model = ((DaySummaryTableModel) table.getModel());
int[] selRows = table.getSelectedRows();
for (int i = 0; i < selRows.length; ++i) {
Program prog = model.getProgramFromRow(selRows[i]);
plugin.ignoreProgram(prog);
}
updateDialog(0);
}
/**
* This initializes controls and listeners. It is called by the constructor of
* the superclass. Since our dialog is not yet constructed we initialize
* several fields here.
*
* @see javax.swing.JDialog#dialogInit()
*/
@Override
protected void dialogInit() {
super.dialogInit();
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
table = new JTable();
table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
table.setAutoCreateColumnsFromModel(false);
// dayStringLb = new JLabel("Foo"); //$NON-NLS-1$
getContentPane().setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
c.insets = new Insets(7, 7, 0, 7);
c.anchor = GridBagConstraints.EAST;
getContentPane().add(createNorthButtonsPanel(), c);
c.fill = GridBagConstraints.BOTH;
c.insets = new Insets(7, 7, 7, 7);
c.weightx = 1;
c.weighty = 1;
c.gridwidth = GridBagConstraints.REMAINDER;
getContentPane().add(new JScrollPane(table), c);
c.weighty = 0;
c.insets = new Insets(0, 7, 7, 7);
getContentPane().add(createSouthButtonsPanel(), c);
table.getTableHeader().addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(java.awt.event.MouseEvent evt) {
int column = table.convertColumnIndexToModel(table.getColumnModel().getColumnIndexAtX(evt.getX()));
if (-1 != column && table.getModel() instanceof DaySummaryTableModel) {
((DaySummaryTableModel) table.getModel()).onColumnClicked(column);
}
}
});
table.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 evt) {
int row = table.rowAtPoint(evt.getPoint());
if (-1 == row) {
return;
}
final Program prog = ((DaySummaryTableModel) table.getModel()).getProgramFromRow(row);
if (SwingUtilities.isLeftMouseButton(evt) && (evt.getClickCount() == 2)) {
devplugin.Plugin.getPluginManager().handleProgramDoubleClick(prog, plugin);
}
if (SwingUtilities.isMiddleMouseButton(evt) && (evt.getClickCount() == 1)) {
devplugin.Plugin.getPluginManager().handleProgramMiddleClick(prog, plugin);
}
}
});
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent lse) {
onTableSelectionChanged(lse.getValueIsAdjusting());
}
});
onTableSelectionChanged(false);
}
/**
* This internal function shows a popup menu at the location of a MouseEvent.
*
* @param event
* is a mouse event that requests a popup menu.
*/
private void showPopup(MouseEvent event) {
int row = table.rowAtPoint(event.getPoint());
if (-1 == row) {
return;
}
final Program prog = ((DaySummaryTableModel) table.getModel()).getProgramFromRow(row);
devplugin.Plugin.getPluginManager().createPluginContextMenu(prog, plugin).show((Component) event.getSource(),
event.getX(), event.getY());
((DaySummaryTableModel) table.getModel()).fireTableRowsUpdated(row, row);
}
/**
* This internal function initializes the "SOUTH" panel.
*
* @return a panel with buttons, a label and ActionListeners.
*/
private JPanel createSouthButtonsPanel() {
JPanel buttonsPn = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
if (System.getProperty("os.name").startsWith("Mac OS X")) {
c.insets.bottom = 7;
}
prevDayBtn = new JButton(mLocalizer.msg("btn.previous", "Previous day")); //$NON-NLS-1$
prevDayBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
updateDialog(-1);
}
});
c.insets.right = 7;
buttonsPn.add(prevDayBtn, c);
final JButton showallBtn = new JButton(mLocalizer.msg("btn.showall", "Show all days")); //$NON-NLS-1$
showallBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
DaySummaryDialog.this.getRootPane().getGlassPane().setVisible(true);
final Cursor oldCursor = getCursor();
new Thread() {
@Override
public void run() {
setCursor(new Cursor(Cursor.WAIT_CURSOR));
SwingUtilities.invokeLater(new Runnable() {
public void run() {
updateShowAll();
setCursor(oldCursor);
DaySummaryDialog.this.getGlassPane().setVisible(false);
}
});
}
}.start();
}
});
buttonsPn.add(showallBtn, c);
c.insets.right = 0;
nextDayBtn = new JButton(mLocalizer.msg("btn.next", "Next day")); //$NON-NLS-1$
nextDayBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
updateDialog(1);
}
});
buttonsPn.add(nextDayBtn, c);
c.weightx = 1;
c.anchor = GridBagConstraints.EAST;
ignoreBtn = new JButton(mLocalizer.msg("btn.ignore", "Filter")); //$NON-NLS-1$
ignoreBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
onIgnoreSelectedPrograms();
}
});
buttonsPn.add(ignoreBtn, c);
final JButton closeBtn = new JButton(Localizer.getLocalization(Localizer.I18N_CLOSE));
closeBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
saveLayout();
dispose();
}
});
buttonsPn.add(closeBtn, c);
getRootPane().setDefaultButton(closeBtn);
return buttonsPn;
}
/**
* This internal function initializes the "NORTH" panel.
*
* @return a panel with buttons, a label and ActionListeners.
*/
private JPanel createNorthButtonsPanel() {
JPanel buttonsPn = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.EAST;
final JButton settingsBtn = new JButton(mLocalizer.msg("btn.settings", "Settings...")); //$NON-NLS-1$
settingsBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new SettingsDialog(plugin, DaySummaryDialog.this).setVisible(true);
updateDialog(0);
}
});
buttonsPn.add(settingsBtn, c);
c.insets.left = 7;
final JButton htmlBtn = new JButton(mLocalizer.msg("btn.htmlexport", "HTML Export...")); //$NON-NLS-1$
htmlBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
DaySummaryTableModel model = (DaySummaryTableModel) table.getModel();
if (null != model) {
HtmlExporter.openHtmlFile(model.getRows());
}
}
});
buttonsPn.add(htmlBtn, c);
final JButton helpBtn = new JButton(mLocalizer.msg("btn.help", "Help...")); //$NON-NLS-1$
helpBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final JDialog help = new HelpDialog(DaySummaryDialog.this, getClass().getResource(
mLocalizer.msg("helpurl", "help/intro.html"))); //$NON-NLS-1$
help.setModal(isModal());
help.setVisible(true);
}
});
buttonsPn.add(helpBtn, c);
return buttonsPn;
}
/**
* This internal function stores column and dialog layout information in the
* settings object.
*/
private void saveLayout() {
final Settings settings = SettingsKeys.getSettings();
settings.setInt(SettingsKeys.DIALOG_X, getX());
settings.setInt(SettingsKeys.DIALOG_Y, getY());
settings.setInt(SettingsKeys.DIALOG_W, getWidth());
settings.setInt(SettingsKeys.DIALOG_H, getHeight());
final TableColumnModel colModel = table.getColumnModel();
final StringBuffer colSizes = new StringBuffer();
for (int i = 0; i < colModel.getColumnCount(); ++i) {
colSizes.append(Integer.toString(colModel.getColumn(i).getModelIndex()));
colSizes.append(';');
colSizes.append(Integer.toString(colModel.getColumn(i).getWidth()));
colSizes.append(';');
}
settings.setProperty(SettingsKeys.DIALOG_COLS, colSizes.toString());
}
}