Package tvbrowser.ui.programtable

Source Code of tvbrowser.ui.programtable.DefaultProgramTableModel$DateRange

/*
* 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-06-28 19:33:48 +0200 (Mon, 28 Jun 2010) $
*   $Author: bananeweizen $
* $Revision: 6662 $
*/
package tvbrowser.ui.programtable;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TimeZone;

import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import tvbrowser.core.TvDataBase;
import tvbrowser.core.filters.filtercomponents.ChannelFilterComponent;
import util.io.IOUtilities;
import util.ui.ProgramPanel;
import devplugin.Channel;
import devplugin.ChannelDayProgram;
import devplugin.Date;
import devplugin.Program;
import devplugin.ProgramFilter;
import devplugin.ProgressMonitor;

/**
*
* @author  Til
*/
public class DefaultProgramTableModel implements ProgramTableModel, ChangeListener {
 
  private int mTomorrowLatestTime;
  private int mTodayEarliestTime;

  private ArrayList<ProgramTableModelListener> mListenerList;
 
  private Channel[] mChannelArr, mShownChannelArr;
  private Date mMainDay;
 
  private ArrayList<ProgramPanel>[] mProgramColumn, mShownProgramColumn;
 
  private int mLastTimerMinutesAfterMidnight;
  private Timer mTimer;
 
  private ProgramFilter mProgramFilter=null;

  private HashMap<Channel, DateRange> mDateRangeForChannel;
 
  private int[] mOnAirRows;
 
  /**
   * the currently active channel group
   */
  private ChannelFilterComponent mChannelGroupFilter = null;

  /**
   * Creates a new instance of DefaultProgramTableModel.
   */
  public DefaultProgramTableModel(Channel[] channelArr,
    int todayEarliestTime, int tomorrowLatestTime)
  {
    mDateRangeForChannel = new HashMap<Channel, DateRange>();

    mListenerList = new ArrayList<ProgramTableModelListener>();
    mTodayEarliestTime=todayEarliestTime;
    mTomorrowLatestTime=tomorrowLatestTime;


    mMainDay = new Date();

    setChannels(channelArr);


    mTimer = new Timer(10000, new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        handleTimerEvent();
      }
    });
    mTimer.start();
  }




  private DateRange getDateRangeForChannel(Channel ch) {

    int channelTime = ch.getTimeZone().getRawOffset()/60000;
    if (ch.getTimeZone().useDaylightTime()) {
      channelTime+=60;
    }
   
    int localTime = TimeZone.getDefault().getRawOffset()/60000;
    if (ch.getTimeZone().useDaylightTime()) {
      localTime+=60;
    }
    int timeDiff = channelTime - localTime;  // e.g -240min
   
    int startTimeForChannelLocale = mTodayEarliestTime+timeDiff;
    int endTimeForChannelLocale = mTomorrowLatestTime+59+timeDiff+1440;
   
    int fromDate;
     if (startTimeForChannelLocale>=0) {
      fromDate = startTimeForChannelLocale/24/60;
    }
    else {
      fromDate = (startTimeForChannelLocale/24/60)-1;
    }

    int toDate;
    if (endTimeForChannelLocale>0) {
      toDate = endTimeForChannelLocale/24/60 +1;
    }
    else {
      toDate = (endTimeForChannelLocale/24/60)-1+1;
    }

    if(!TvDataBase.getInstance().isDayProgramAvailable(mMainDay.addDays(fromDate),ch)) {
      fromDate++;
    }
   
    return new DateRange(fromDate, toDate-fromDate);

  }


  public void setTimeRange(int todayEarliestTime, int tomorrowLatestTime) {
    mTodayEarliestTime=todayEarliestTime;
    mTomorrowLatestTime=tomorrowLatestTime;
    fireTableDataChanged(null);
  }


  private void updateDateRange() {
    mDateRangeForChannel.clear();
    for (Channel channel : mChannelArr) {
      DateRange dateRange = getDateRangeForChannel(channel);
      mDateRangeForChannel.put(channel, dateRange);
    }
  }



  public void setChannels(Channel[] channelArr) {
    if (channelArr == null) {
      throw new NullPointerException("shownChannelArr is null!");
    }
    checkThread();

    mChannelArr = channelArr;
   
    mProgramColumn=new ArrayList[mChannelArr.length];
    for (int i=0;i<mProgramColumn.length;i++) {
      mProgramColumn[i]=new ArrayList<ProgramPanel>();
    }

    updateDateRange();

    updateTableContent();
  }
 
 
  public void setProgramFilter(ProgramFilter filter) {
    mProgramFilter=filter;
    updateTableContent();
    fireTableDataChanged(null);
  }
 
  public void setChannelGroup(ChannelFilterComponent channelFilter) {
    mChannelGroupFilter = channelFilter;
    updateTableContent();
    fireTableDataChanged(null);
  }


  public ProgramFilter getProgramFilter() {
    return mProgramFilter;
  }
 
  public ChannelFilterComponent getChannelGroup() {
    return mChannelGroupFilter;
  }


  private static int compareDateTime(Date d1, int m1, Date d2, int m2) {
    if (d1.compareTo(d2)<0) { // (d1<d2)
      return -1;
    }
    else if (d1.compareTo(d2)>0) { //(d1>d2)
      return 1;
    }
    else { // d1 == d2
      if (m1<m2) {
        return -1;
      }
      else if (m1>m2) {
        return 1;
      }
      else {
          return 0;
      }
    }
  }



  private void addChannelDayProgram(int col, ChannelDayProgram[] cdpArr, Date fromDate, int fromMinutes, Date toDate, int toMinutes)
  {
    if (cdpArr == null) {
      return;
    }
    checkThread();

    for (ChannelDayProgram cdp : cdpArr) {
      if (cdp==null) {
        break;
      }
      Iterator<Program> it=cdp.getPrograms();
      if (it!=null) {
        while (it.hasNext()) {
          Program prog=it.next();
          int progTime=prog.getStartTime();
          Date progDate = prog.getDate();
          // program starts before given end time
          if (compareDateTime(progDate, progTime, toDate, toMinutes) <= 0) {
            // program starts after or at given end time
            if (compareDateTime(progDate, progTime, fromDate, fromMinutes) >= 0)  {
              if (filterAccepts(prog)) {
                ProgramPanel panel = new ProgramPanel(prog);
                mProgramColumn[col].add(panel);
              }
            }
            else {
              // add the last program _before_ the day start time which is still running afterwards
              if (mProgramColumn[col].isEmpty()) {
                if (compareDateTime(progDate, progTime + prog.getLength(), fromDate, fromMinutes) > 0) {
                  if (filterAccepts(prog)) {
                    ProgramPanel panel = new ProgramPanel(prog);
                    mProgramColumn[col].add(panel);
                  }
                }
              }
            }
          }
        }
      }
    }
  }


  private boolean filterAccepts(Program program) {
    return (mChannelGroupFilter == null || mChannelGroupFilter.accept(program)) && (mProgramFilter==null || mProgramFilter.accept(program));
  }

  public void setDate(Date date, ProgressMonitor monitor, Runnable callback)
  {
    mMainDay = date;
    updateDateRange();
    updateTableContent(monitor, callback);
  }
 
  public Date getDate() {
    return mMainDay;
  }
 
  public void updateTableContent() {
    updateTableContent(null, null);
  }

  private void updateTableContent(ProgressMonitor monitor, final Runnable callback)
  {
    // if this is the initial update, skip every UI related operation, just set
    // necessary members. the UI update will be forced when setting the initial
    // filter
    if (mProgramFilter == null) {
      mShownProgramColumn = mProgramColumn.clone();
      mShownChannelArr = mChannelArr.clone();
      return;
    }
   
    checkThread();
    mOnAirRows = null;
    deregisterFromPrograms(mProgramColumn);

    TvDataBase db = TvDataBase.getInstance();

    if (monitor != null) {
      monitor.setMaximum(mChannelArr.length - 1);
      monitor.setValue(0);
    }

    Date nextDay = mMainDay.addDays(1);
    for (int i = 0; i < mChannelArr.length; i++) {
      mProgramColumn[i].clear();
      DateRange dateRange = mDateRangeForChannel.get(mChannelArr[i]);
      ChannelDayProgram[] cdp = new ChannelDayProgram[dateRange.getCount()];

      for (int d = 0; d<cdp.length; d++) {
        cdp[d] = db.getDayProgram(mMainDay.addDays(dateRange.getBegin() + d), mChannelArr[i]);
      }
      addChannelDayProgram(i, cdp, mMainDay, mTodayEarliestTime, nextDay, mTomorrowLatestTime);

      if (monitor != null) {
        monitor.setValue(i);
      }
    }

    boolean showEmptyColumns = (mProgramFilter instanceof tvbrowser.core.filters.ShowAllFilter) && (mChannelGroupFilter == null);

    ArrayList<ArrayList<ProgramPanel>> newShownColumns = new ArrayList<ArrayList<ProgramPanel>>();
    ArrayList<Channel> newShownChannels = new ArrayList<Channel>();
    for (int i = 0; i < mProgramColumn.length; i++) {
      if (showEmptyColumns || mProgramColumn[i].size() > 0) {
        newShownColumns.add(mProgramColumn[i]);
        newShownChannels.add(mChannelArr[i]);
      }
    }
    mShownProgramColumn = new ArrayList[newShownColumns.size()];
    mShownChannelArr = new Channel[newShownChannels.size()];

    newShownColumns.toArray(mShownProgramColumn);
    newShownChannels.toArray(mShownChannelArr);

    SwingUtilities.invokeLater(new Runnable() {

      public void run() {
        handleTimerEvent();
        registerAtPrograms(mProgramColumn);
        fireTableDataChanged(callback);
      }
    });
  }

 
 
  public void addProgramTableModelListener(ProgramTableModelListener listener) {
    mListenerList.add(listener);
  }

 
 
  public Channel[] getShownChannels() {
    checkThread();
    return mShownChannelArr;
  }
 
  /**
   * @return The number of available channels.
   */
  public int getAvailableChannelCount() {
    checkThread();
    return mChannelArr.length;
  }

  public int getColumnCount() {
    checkThread();
    return mShownChannelArr.length;
  }

  public int getRowCount(int col) {
    checkThread();
    return mShownProgramColumn[col].size();
  }

  public ProgramPanel getProgramPanel(int col, int row) {
    checkThread();

    ArrayList<ProgramPanel> list=mShownProgramColumn[col];
    if (list.size()<=row) {
      return null;
    }
    return list.get(row);
  }

  private void deregisterFromPrograms(ArrayList<ProgramPanel>[] columns) {
    for (ArrayList<ProgramPanel> list : columns) {
      Iterator<ProgramPanel> it=list.iterator();
      while (it.hasNext()) {
        ProgramPanel panel = it.next();
        Program prog = panel.getProgram();
        prog.removeChangeListener(this);
      }
    }
  }

  private void registerAtPrograms(ArrayList<ProgramPanel>[] columns) {
    for (ArrayList<ProgramPanel> list : columns) {
      Iterator<ProgramPanel> it=list.iterator();
      while (it.hasNext()) {
        ProgramPanel panel = it.next();
        Program prog = panel.getProgram();
        prog.addChangeListener(this);
      }
    }
  }

  protected void fireTableDataChanged(Runnable callback) {
    for (int i = 0; i < mListenerList.size(); i++) {
      ProgramTableModelListener lst = mListenerList.get(i);
      lst.tableDataChanged(callback);
    }
  }

 
 
  protected void fireTableCellUpdated(int col, int row) {
    for (int i = 0; i < mListenerList.size(); i++) {
      ProgramTableModelListener lst = mListenerList.get(i);
      lst.tableCellUpdated(col, row);
    }
  }
 
 
 
  protected int getColumnOfChannel(Channel channel) {
    checkThread();
    for (int col = 0; col < mShownChannelArr.length; col++) {
      if (channel.equals(mShownChannelArr[col])) {
        return col;
      }
    }
   
    // No such column found
    return -1;
  }
 
  /**
   * Checks if this model contains a program.
   *
   * @param p The program to check.
   * @return True if the program is contained.
   * @throws Exception Thrown if something goes wrong.
   * @since 2.5.3
   */
  public boolean contains(Program p) throws Exception {
    checkThread();
     
    for(int i = 0; i < mShownChannelArr.length; i++) {
      if(p.getChannel().equals(mShownChannelArr[i])) {
        for(ProgramPanel panel : mShownProgramColumn[i]) {
          if(panel.getProgram().equals(p)) {
            return true;
          }
        }
      }
    }
   
    return false;
  }


  private void handleTimerEvent() {
    checkThread();

    // Avoid a repaint 6 times a minute (Once a minute is enough)
    int minutesAfterMidnight = IOUtilities.getMinutesAfterMidnight();
    if (minutesAfterMidnight == mLastTimerMinutesAfterMidnight) {
      return;
    }

    mLastTimerMinutesAfterMidnight = minutesAfterMidnight;

    // Force a repaint of all programs on air
    // (so the progress background will be updated)
    if(mOnAirRows == null) {
      int columnCount = getColumnCount();
    mOnAirRows = new int[columnCount];
      Arrays.fill(mOnAirRows, -1);
      for (int col = 0; col < columnCount; col++) {
        int rowCount = getRowCount(col);
    for (int row = 0; row < rowCount; row++) {
          ProgramPanel panel = getProgramPanel(col, row);
          if (panel.getProgram().isOnAir()) {
            mOnAirRows[col] = row;
            fireTableCellUpdated(col, row);
          }
        }
      }
    }
    else {
      for (int col = 0; col < mOnAirRows.length; col++) {
        if(mOnAirRows[col] != -1) {
          ProgramPanel panel = getProgramPanel(col, mOnAirRows[col]);
         
          if(panel.getProgram().isOnAir()) {
            fireTableCellUpdated(col, mOnAirRows[col]);
          }
          else if(panel.getProgram().isExpired()){
            fireTableCellUpdated(col, mOnAirRows[col]);
           
            panel = getProgramPanel(col, mOnAirRows[col]+1);
           
            if(panel == null) {
              mOnAirRows[col] = -1;
            } else {
              mOnAirRows[col] = mOnAirRows[col]+1;
              fireTableCellUpdated(col, mOnAirRows[col]);
            }
          }
        }
      }
    }
  }


  /**
   * Called when a program has changed.
   *
   * @param evt The change event.
   */
  public void stateChanged(ChangeEvent evt) {
    // A program has changed -> fire the event
    final Program program = (Program) evt.getSource();
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        fireProgramHasChanged(program);
      }
    });
  }


  protected void fireProgramHasChanged(Program program) {
    // Get the column of this program
    int col = getColumnOfChannel(program.getChannel());
    if (col == -1) {
      // This program is not shown in this table
      return;
    }
   
    int rowCount = getRowCount(col);
  // Get the row of this program
    for (int row = 0; row < rowCount; row++) {
      ProgramPanel panel = getProgramPanel(col, row);
      if (program == panel.getProgram()) {
        // Tell the panel that its program has changed
        panel.programHasChanged();
       
        // Fire the event
        fireTableCellUpdated(col, row);
        return;
      }
    }
  }
 
 
  private void checkThread() {
    if (! SwingUtilities.isEventDispatchThread()) {
      throw new IllegalStateException("The table model must be used in the "
          + "Swing event thread (use SwingUtilities.invokeLater())");
    }
  }



  private static class DateRange {

    private int mCnt;
    private int mBegin;

    public DateRange(int begin, int cnt) {
      mBegin = begin;
      mCnt = cnt;
    }

    public int getBegin() {
      return mBegin;
    }

    public int getCount() {
      return mCnt;
    }

  }

}
TOP

Related Classes of tvbrowser.ui.programtable.DefaultProgramTableModel$DateRange

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.