package com.github.pfichtner.jrunalyser.ui.cal; import static com.google.common.collect.Iterables.transform; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.IOException; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.List; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import com.github.pfichtner.jrunalyser.base.data.LinkedTrackPoint; import com.github.pfichtner.jrunalyser.base.data.WayPoint; import com.github.pfichtner.jrunalyser.base.data.track.Id; import com.github.pfichtner.jrunalyser.base.data.track.Track; import com.github.pfichtner.jrunalyser.base.data.track.Tracks; import com.github.pfichtner.jrunalyser.base.datasource.DatasourceFascade; import com.github.pfichtner.jrunalyser.di.Inject; import com.github.pfichtner.jrunalyser.ui.base.AbstractUiPlugin; import com.github.pfichtner.jrunalyser.ui.base.DefaultGridData; import com.github.pfichtner.jrunalyser.ui.base.GridData; import com.github.pfichtner.jrunalyser.ui.base.GridDataProvider; import com.github.pfichtner.jrunalyser.ui.base.i18n.I18N; import com.github.pfichtner.jrunalyser.ui.cal.swing.DateComponent; import com.github.pfichtner.jrunalyser.ui.cal.swing.MyCalendar; import com.github.pfichtner.jrunalyser.ui.cal.swing.model.AbstractCalenderModel; import com.github.pfichtner.jrunalyser.ui.cal.swing.model.CalendarEntry; import com.github.pfichtner.jrunalyser.ui.cal.swing.model.CalendarModelEvent; import com.github.pfichtner.jrunalyser.ui.cal.swing.model.CalenderModel; import com.github.pfichtner.jrunalyser.ui.cal.swing.model.DefaultCalendarEntry; import com.github.pfichtner.jrunalyser.ui.dock.ebus.TrackAdded; import com.github.pfichtner.jrunalyser.ui.dock.ebus.TrackLoaded; import com.google.common.base.Function; import com.google.common.base.Throwables; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; public class CalendarPlugin extends AbstractUiPlugin implements GridDataProvider { public static class DataSourceCalenderModel extends AbstractCalenderModel { private final DatasourceFascade dsf; public DataSourceCalenderModel(DatasourceFascade dsf) { this.dsf = dsf; } private final Function<Id, CalendarEntry> createEntry = new Function<Id, CalendarEntry>() { @Override public CalendarEntry apply(Id id) { try { return createCalendarEntry( DataSourceCalenderModel.this.dsf, id); } catch (IOException e) { throw Throwables.propagate(e); } } }; @Override public int getCount() { try { return this.dsf.getTrackIds().size(); } catch (IOException e) { throw Throwables.propagate(e); } } @Override public CalendarEntry getEntry(int index) { try { Iterable<Id> trackIds = this.dsf.getTrackIds(new Date(0), new Date(Long.MAX_VALUE)); Id id = Iterables.get(trackIds, index); return createCalendarEntry(this.dsf, id); } catch (IOException e) { throw Throwables.propagate(e); } } @Override public Collection<CalendarEntry> getEntries(Date date) { Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); Date start = new Date(cal.getTime().getTime()); cal.add(Calendar.DAY_OF_MONTH, 1); cal.add(Calendar.MILLISECOND, -1); Date end = new Date(cal.getTime().getTime()); try { return Sets.newHashSet(transform( this.dsf.getTrackIds(start, end), this.createEntry)); } catch (IOException e) { throw Throwables.propagate(e); } } } private static final GridData gridData = new DefaultGridData(0, 0, 1, 1); private MyCalendar calendar; private CalenderModel calenderModel; private DatasourceFascade dsf; private static final I18N i18n = I18N .builder(CalendarPlugin.class) .withParent( com.github.pfichtner.jrunalyser.ui.base.UiPlugins.getI18n()) .build(); public CalendarPlugin() { this.calendar = new MyCalendar(); this.calendar.setDate(new Date()); } @Override public String getTitle() { return i18n .getText("com.github.pfichtner.jrunalyser.ui.cal.CalendarPlugin.title"); //$NON-NLS-1$ } @Override public JComponent getPanel() { return this.calendar; } @Override public GridData getGridData() { return gridData; } private static DefaultCalendarEntry createCalendarEntry( DatasourceFascade dsf, Id trackId) throws IOException { Track track = dsf.loadTrack(trackId); // TODO Do not fixed type (icon) here ImageIcon icon = new ImageIcon( CalendarPlugin.class.getResource("/run.gif")); //$NON-NLS-1$ List<? extends WayPoint> trackpoints = track.getTrackpoints(); // TODO Filter for trackpoints with dates! Date dStart = new Date(Iterables.getFirst(trackpoints, null).getTime() .longValue()); Date dEnd = new Date(Iterables.getLast(trackpoints).getTime() .longValue()); DefaultCalendarEntry calItem = new DefaultCalendarEntry(); calItem.setUserObject(trackId); calItem.setStartDate(dStart); calItem.setEndDate(dEnd); // TODO Do not use fixed type here calItem.setDescription("Running"); calItem.setIcon(icon); return calItem; } @Inject public void setDatasourceFascade(DatasourceFascade dsf) { this.dsf = dsf; this.calenderModel = new DataSourceCalenderModel(dsf); this.calendar.setCalenderModel(this.calenderModel); this.calendar.setDate(new Date()); } @Inject public void setEventBus(final EventBus eventBus) { MouseListener l = new MouseAdapter() { @Override public void mouseClicked(MouseEvent evt) { final DateComponent dc = (DateComponent) evt.getSource(); if (evt.getButton() == MouseEvent.BUTTON1) { Id trackId = getSelectedTrackId(dc.getDate()); if (trackId != null) { eventBus.post(new TrackLoaded(loadTrack(trackId))); } } else if (evt.getButton() == MouseEvent.BUTTON3) { JPopupMenu menu = new JPopupMenu(); final JMenuItem item = new JMenuItem( i18n.getText("com.github.pfichtner.jrunalyser.ui.cal.CalendarPlugin.mDeleteTrack.title")); //$NON-NLS-1$ item.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { Id trackId = getSelectedTrackId(dc.getDate()); Track track = loadTrack(trackId); if (JOptionPane.showConfirmDialog( getPanel(), i18n.getText( "com.github.pfichtner.jrunalyser.ui.cal.CalendarPlugin.mDeleteTrack.warning.title", //$NON-NLS-1$ track.getMetadata().getName()), item.getText(), JOptionPane.YES_NO_OPTION) == 0) { try { CalendarPlugin.this.dsf .removeTrack(trackId); } catch (IOException e) { throw new RuntimeException( "Error deleting track " + trackId, //$NON-NLS-1$ e); } } } }); menu.add(item); menu.show((Component) evt.getSource(), evt.getX(), evt.getY()); } } private Track loadTrack(Id trackId) { try { return CalendarPlugin.this.dsf.loadTrack(trackId); } catch (IOException e) { throw Throwables.propagate(e); } } private Id getSelectedTrackId(long date) { Collection<CalendarEntry> entries = CalendarPlugin.this.calenderModel .getEntries(new Date(date)); // TODO Do not take FIRST track return entries.isEmpty() ? null : (Id) Iterables .get(entries, 0).getUserObject(); } }; this.calendar.addMouseListener(l); } @Subscribe // change calendar's date to track's date public void setTrack(TrackLoaded message) { this.calendar.setDate(new Date(Tracks.getStartPoint(message.getTrack()) .getTime().longValue())); } @Subscribe public void addTrack(TrackAdded message) { Track track = message.getTrack(); List<? extends LinkedTrackPoint> wps = track.getTrackpoints(); if (!wps.isEmpty()) { Date start = new Date(Iterables.get(wps, 0).getTime().longValue()); Date end = new Date(Iterables.getLast(wps).getTime().longValue()); this.calenderModel.fireTableChanged(new CalendarModelEvent( CalendarModelEvent.Type.INSERTED, start, end)); } } }