/*
* Jampa
* Copyright (C) 2008-2009 J. Devauchelle and contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 3 as published by the Free Software Foundation.
*
* 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.
*/
package org.jampa.gui.views;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.util.Util;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.part.ViewPart;
import org.jampa.Activator;
import org.jampa.controllers.Controller;
import org.jampa.controllers.events.EventConstants;
import org.jampa.gui.actions.podcast.NewPodcastAction;
import org.jampa.gui.actions.podcast.OpenAndPlayPodcastAction;
import org.jampa.gui.actions.podcast.OpenPodcastAction;
import org.jampa.gui.actions.podcast.PlayPodcastAction;
import org.jampa.gui.dialogs.PodcastPropertiesDialog;
import org.jampa.gui.translations.Messages;
import org.jampa.logging.Log;
import org.jampa.model.podcasts.Podcast;
import org.jampa.model.validators.PodcastNameValidator;
import org.jampa.net.podcast.PodcastUpdaterJob;
import org.jampa.utils.ApplicationUtils;
public class PodcastListView extends ViewPart implements PropertyChangeListener {
public static String ID = "Jampa.PodcastListView"; //$NON-NLS-1$
private TableViewer viewer = null;
private Composite _parent;
private Action _markReadAction;
private Action _markUnreadAction;
private Action _addPodcast;
private Action _removePodcast;
private Action _refreshPodcast;
private Image _podcastImage;
private Image _podcastPlayImage;
private Image _podcastPauseImage;
private Image _playImage;
private Image _markReadImage;
private Image _markUnreadImage;
private Image _newImage;
private Image _removeImage;
private Image _refreshImage;
private Menu _viewMenu = null;
class ViewContentProvider implements IStructuredContentProvider {
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
// do nothing
}
public void dispose() {
// do nothing
}
public Object[] getElements(Object parent) {
return Controller.getInstance().getPlaylistController().getPodcastList();
}
}
class ViewLabelProvider extends LabelProvider implements ITableLabelProvider {
public Image getImage(Object obj) {
Podcast podcast = (Podcast) obj;
if (Controller.getInstance().getPlaylistController().getCurrentPlaylist() == podcast) {
if (Controller.getInstance().getEngine().isPaused()) {
return _podcastPauseImage;
} else {
return _podcastPlayImage;
}
} else {
return _podcastImage;
}
}
public Image getColumnImage(Object obj, int index) {
switch(index) {
case 0 : return getImage(obj);
default : return null;
}
}
public String getColumnText(Object obj, int index) {
switch(index) {
case 0 : {
Podcast podcast = (Podcast) obj;
String result = podcast.getName();
int unreadCount = podcast.getUnreadItemsCount();
if (unreadCount > 0) {
result = "(" + Integer.toString(unreadCount) + ") " + result;
}
return result;
}
case 1 : return ((Podcast) obj).getTitle();
case 2 : return ((Podcast) obj).getDescription();
case 3 : return ((Podcast) obj).getUrl();
default : return ((Podcast) obj).getName();
}
}
}
public PodcastListView() {
Activator.getDefault();
_podcastImage = Activator.getImageDescriptor("/icons/rss_list_16.png").createImage(); //$NON-NLS-1$
_podcastPlayImage = Activator.getImageDescriptor("/icons/rss_list_play_16.png").createImage(); //$NON-NLS-1$
_podcastPauseImage = Activator.getImageDescriptor("/icons/rss_list_pause_16.png").createImage(); //$NON-NLS-1$
_playImage = Activator.getImageDescriptor("/icons/play_16.png").createImage(); //$NON-NLS-1$
_markReadImage = Activator.getImageDescriptor("/icons/podcast_mark_read_16.png").createImage(); //$NON-NLS-1$
_markUnreadImage = Activator.getImageDescriptor("/icons/podcast_mark_unread_16.png").createImage(); //$NON-NLS-1$
_newImage = Activator.getImageDescriptor("/icons/add_podcast_16.png").createImage(); //$NON-NLS-1$
_removeImage = Activator.getImageDescriptor("/icons/remove_podcast_16.png").createImage(); //$NON-NLS-1$
_refreshImage = Activator.getImageDescriptor("/icons/refresh_podcast_16.png").createImage(); //$NON-NLS-1$
}
public void createPartControl(Composite parent) {
_parent = parent;
this.setPartName(Messages.getString("PodcastListView.ViewTitle")); //$NON-NLS-1$
if (ApplicationUtils.doesEngineSupportPodcasts()) {
viewer = new TableViewer(_parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
TableLayout layout = new TableLayout();
layout.addColumnData(new ColumnWeightData(15, 10, true));
layout.addColumnData(new ColumnWeightData(25, 10, true));
layout.addColumnData(new ColumnWeightData(40, 10, true));
layout.addColumnData(new ColumnWeightData(20, 10, true));
viewer.getTable().setLayout(layout);
// Lines visible is ugly under Windows.
if (!Util.isWindows()) {
viewer.getTable().setLinesVisible(true);
}
viewer.getTable().setHeaderVisible(true);
TableColumn columnName = new TableColumn(viewer.getTable(), SWT.NONE);
columnName.setText(Messages.getString("PodcastListView.Name")); //$NON-NLS-1$
columnName.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
Controller.getInstance().getPlaylistController().sortPodcastList(1);
}
});
TableColumn columnTitle = new TableColumn(viewer.getTable(), SWT.NONE);
columnTitle.setText(Messages.getString("PodcastListView.Title")); //$NON-NLS-1$
columnTitle.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
Controller.getInstance().getPlaylistController().sortPodcastList(2);
}
});
TableColumn columnDescription = new TableColumn(viewer.getTable(), SWT.NONE);
columnDescription.setText(Messages.getString("PodcastListView.Description")); //$NON-NLS-1$
columnDescription.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
Controller.getInstance().getPlaylistController().sortPodcastList(3);
}
});
TableColumn columnUrl = new TableColumn(viewer.getTable(), SWT.NONE);
columnUrl.setText(Messages.getString("PodcastListView.Url")); //$NON-NLS-1$
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setInput(getViewSite());
viewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
ISelection selection = viewer.getSelection();
Object obj = ((IStructuredSelection)selection).getFirstElement();
if (obj != null) {
new OpenPodcastAction(((Podcast) obj).getName()).run();
}
}
});
buildActions();
buildMenus();
buildDND();
// Register listener
Controller.getInstance().getEventController().addPlaylistChangeListener(this);
Controller.getInstance().getEventController().addAudioItemChangeListener(this);
} else {
this.setContentDescription(String.format(Messages.getString("PodcastListView.PodcastsNotSupported"), //$NON-NLS-1$
Controller.getInstance().getEngine().getEngineType()));
}
}
private void buildDND() {
// Drag source
Transfer[] types = new Transfer[] { TextTransfer.getInstance() };
DragSource source = new DragSource(viewer.getTable(), DND.DROP_MOVE);
source.setTransfer(types);
source.addDragListener(new DragSourceAdapter() {
public void dragSetData(DragSourceEvent event) {
event.data = PodcastListView.ID;
}
public void dragStart(DragSourceEvent event) {
event.data = PodcastListView.ID;
Controller.getInstance().getDNDController().setSource(PodcastListView.ID);
}
public void dragFinished(DragSourceEvent event) {
Controller.getInstance().getDNDController().setSource(null);
}
});
// Drop target
DropTarget target = new DropTarget(viewer.getTable(), DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_DEFAULT);
target.setTransfer(types);
target.addDropListener(new DropTargetAdapter() {
public void dragEnter(DropTargetEvent event) {
if (event.detail == DND.DROP_DEFAULT) {
if ((event.operations & DND.DROP_COPY) != 0) {
event.detail = DND.DROP_COPY;
}
}
}
public void dragOver(DropTargetEvent event) {
if (Controller.getInstance().getDNDController().isPodcastListViewSource()) {
Point pt = Display.getCurrent().map(null, viewer.getTable(), event.x, event.y);
TableItem item = viewer.getTable().getItem(pt);
if (item != null) {
event.feedback = DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL;
event.detail = DND.DROP_MOVE;
} else {
event.feedback = DND.FEEDBACK_NONE;
event.detail = DND.DROP_NONE;
}
} else {
// Source is not allowed, no drop feedback.
event.feedback = DND.FEEDBACK_NONE;
event.detail = DND.DROP_NONE;
}
}
public void drop(DropTargetEvent event) {
if (Controller.getInstance().getDNDController().isPodcastListViewSource()) {
// Get the current item.
Point pt = Display.getCurrent().map(null, viewer.getTable(), event.x, event.y);
TableItem item = viewer.getTable().getItem(pt);
Podcast sourcePodcast = (Podcast) ((IStructuredSelection) viewer.getSelection()).getFirstElement();
int toIndex;
if (item != null) {
Podcast podcast = Controller.getInstance().getPlaylistController().getPodcastByName(((Podcast) item.getData()).getName());
toIndex = podcast.getPosition();
} else {
toIndex = -1;
}
if (toIndex != -1) {
List<Podcast> tmpList = new ArrayList<Podcast>();
ISelection selection = viewer.getSelection();
Iterator<?> iter = ((IStructuredSelection) selection).iterator();
while (iter.hasNext()) {
tmpList.add((Podcast) iter.next());
}
// If moving up, move in reverse order to keep the initial order.
if (toIndex < sourcePodcast.getPosition()) {
for (int i = tmpList.size() - 1; i >= 0; i--) {
Controller.getInstance().getPlaylistController().movePodcast(tmpList.get(i), toIndex);
}
} else {
for (int i = 0; i < tmpList.size(); i++) {
Controller.getInstance().getPlaylistController().movePodcast(tmpList.get(i), toIndex);
}
}
}
}
}
});
}
private void buildMenus() {
if (_viewMenu != null) {
_viewMenu.dispose();
}
_viewMenu = new Menu(_parent.getShell(), SWT.POP_UP);
MenuItem playItem = new MenuItem(_viewMenu, SWT.PUSH);
playItem.setText(Messages.getString("PodcastListView.MenuPlay")); //$NON-NLS-1$
playItem.setImage(_playImage);
playItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
ISelection selection = viewer.getSelection();
Object obj = ((IStructuredSelection)selection).getFirstElement();
new PlayPodcastAction(((Podcast) obj).getName()).run();
}
});
MenuItem openItem = new MenuItem(_viewMenu, SWT.PUSH);
openItem.setText(Messages.getString("PodcastListView.MenuOpen")); //$NON-NLS-1$
openItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
ISelection selection = viewer.getSelection();
Object obj = ((IStructuredSelection)selection).getFirstElement();
new OpenPodcastAction(((Podcast) obj).getName()).run();
}
});
MenuItem openAndPlayItem = new MenuItem(_viewMenu, SWT.PUSH);
openAndPlayItem.setText(Messages.getString("PodcastListView.MenuOpenAndPlay")); //$NON-NLS-1$
openAndPlayItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
ISelection selection = viewer.getSelection();
Object obj = ((IStructuredSelection)selection).getFirstElement();
new OpenAndPlayPodcastAction(((Podcast) obj).getName()).run();
}
});
new MenuItem(_viewMenu, SWT.SEPARATOR);
MenuItem markReadItem = new MenuItem(_viewMenu, SWT.PUSH);
markReadItem.setText(Messages.getString("PodcastListView.MenuMarkRead")); //$NON-NLS-1$
markReadItem.setImage(_markReadImage);
markReadItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
setReadStatusSelection(true);
}
});
MenuItem markUnreadItem = new MenuItem(_viewMenu, SWT.PUSH);
markUnreadItem.setText(Messages.getString("PodcastListView.MenuMarkUnread")); //$NON-NLS-1$
markUnreadItem.setImage(_markUnreadImage);
markUnreadItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
setReadStatusSelection(false);
}
});
new MenuItem(_viewMenu, SWT.SEPARATOR);
MenuItem newPodcastItem = new MenuItem(_viewMenu, SWT.PUSH);
newPodcastItem.setText(Messages.getString("PodcastListView.MenuNewPodcast")); //$NON-NLS-1$
newPodcastItem.setImage(_newImage);
newPodcastItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
new NewPodcastAction(_parent.getShell()).run();
}
});
MenuItem renamePodcastItem = new MenuItem(_viewMenu, SWT.PUSH);
renamePodcastItem.setText(Messages.getString("PodcastListView.MenuRenamePodcast")); //$NON-NLS-1$
renamePodcastItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
ISelection selection = viewer.getSelection();
Object obj = ((IStructuredSelection)selection).getFirstElement();
if (obj != null) {
String oldName = ((Podcast) obj).getName();
InputDialog dialog = new InputDialog(_parent.getShell(),
Messages.getString("PodcastListView.RenameDialogTitle"), Messages.getString("PodcastListView.RenameDialogQuestion"), oldName, new PodcastNameValidator()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
int result = dialog.open();
if (result == InputDialog.OK) {
ApplicationUtils.closeViewByID(PodcastView.ID, oldName);
Controller.getInstance().getPlaylistController().renamePodcast(dialog.getValue(), oldName);
}
}
}
});
new MenuItem(_viewMenu, SWT.SEPARATOR);
MenuItem removePodcastItem = new MenuItem(_viewMenu, SWT.PUSH);
removePodcastItem.setText(Messages.getString("PodcastListView.MenuRemovePodcast")); //$NON-NLS-1$
removePodcastItem.setImage(_removeImage);
removePodcastItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
removePodcastSelection();
}
});
new MenuItem(_viewMenu, SWT.SEPARATOR);
MenuItem refreshSelectionItem = new MenuItem(_viewMenu, SWT.PUSH);
refreshSelectionItem.setText(Messages.getString("PodcastListView.MenuRefreshSelection")); //$NON-NLS-1$
refreshSelectionItem.setImage(_refreshImage);
refreshSelectionItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
ISelection selection = viewer.getSelection();
List<Podcast> tmpList = new ArrayList<Podcast>();
Iterator<?> iter = ((IStructuredSelection)selection).iterator();
while (iter.hasNext()) {
tmpList.add((Podcast) iter.next());
}
//new PodcastDownloaderThread(tmpList).start();
new PodcastUpdaterJob(tmpList).schedule();
}
});
new MenuItem(_viewMenu, SWT.SEPARATOR);
MenuItem propertiesItem = new MenuItem(_viewMenu, SWT.PUSH);
propertiesItem.setText(Messages.getString("PodcastListView.MenuProperties")); //$NON-NLS-1$
propertiesItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
ISelection selection = viewer.getSelection();
Object obj = ((IStructuredSelection)selection).getFirstElement();
new PodcastPropertiesDialog(_parent.getShell(), (Podcast) obj).open();
}
});
viewer.getTable().addListener(SWT.MenuDetect, new Listener() {
public void handleEvent(Event event) {
_viewMenu.setVisible(true);
}
});
}
private void buildActions() {
_markReadAction = new Action(Messages.getString("PodcastListView.MarkRead")) { //$NON-NLS-1$
public void run() {
setReadStatusSelection(true);
}
};
_markReadAction.setImageDescriptor(Activator.getImageDescriptor("/icons/podcast_mark_read_16.png"));
_markUnreadAction = new Action(Messages.getString("PodcastListView.MarkUnread")) { //$NON-NLS-1$
public void run() {
setReadStatusSelection(false);
}
};
_markUnreadAction.setImageDescriptor(Activator.getImageDescriptor("/icons/podcast_mark_unread_16.png"));
_addPodcast = new Action(Messages.getString("PodcastListView.AddPodcast")) { //$NON-NLS-1$
public void run() {
new NewPodcastAction(_parent.getShell()).run();
}
};
_addPodcast.setImageDescriptor(Activator.getImageDescriptor("/icons/add_podcast_16.png"));
_removePodcast = new Action(Messages.getString("PodcastListView.RemovePodcast")) { //$NON-NLS-1$
public void run() {
removePodcastSelection();
}
};
_removePodcast.setImageDescriptor(Activator.getImageDescriptor("/icons/remove_podcast_16.png"));
_refreshPodcast = new Action(Messages.getString("PodcastListView.RefreshPodcast")) { //$NON-NLS-1$
public void run() {
Log.getInstance(PodcastListView.class).debug("Refreshing podcasts.");
//new PodcastDownloaderThread(Controller.getInstance().getPlaylistController().getPodcastListAsList()).start();
new PodcastUpdaterJob(Controller.getInstance().getPlaylistController().getPodcastListAsList()).schedule();
}
};
_refreshPodcast.setImageDescriptor(Activator.getImageDescriptor("/icons/refresh_podcast_16.png"));
// Toolbar
IToolBarManager rootMenuManager = getViewSite().getActionBars().getToolBarManager();
rootMenuManager.removeAll();
rootMenuManager.add(_markReadAction);
rootMenuManager.add(_markUnreadAction);
rootMenuManager.add(new Separator());
rootMenuManager.add(_addPodcast);
rootMenuManager.add(_removePodcast);
rootMenuManager.add(new Separator());
rootMenuManager.add(_refreshPodcast);
}
private void removePodcastSelection() {
boolean confirm = MessageDialog.openConfirm(_parent.getShell(),
Messages.getString("PodcastListView.RemoveTitle"), //$NON-NLS-1$
Messages.getString("PodcastListView.RemoveQuestion")); //$NON-NLS-1$
if (confirm) {
Object obj;
ISelection selection = viewer.getSelection();
Iterator<?> iter = ((IStructuredSelection)selection).iterator();
while (iter.hasNext()) {
obj = iter.next();
if ((obj != null) &&
(obj instanceof Podcast)) {
ApplicationUtils.closeViewByID(PodcastView.ID, ((Podcast) obj).getName());
Controller.getInstance().getPlaylistController().removePodcast(((Podcast) obj).getName());
}
}
}
}
private void setReadStatusSelection(boolean newStatus) {
Object obj;
ISelection selection = viewer.getSelection();
Iterator<?> iter = ((IStructuredSelection)selection).iterator();
while (iter.hasNext()) {
obj = iter.next();
if ((obj != null) &&
(obj instanceof Podcast)) {
((Podcast) obj).setReadStatus(newStatus);
}
}
Controller.getInstance().getEventController().fireAudioItemChange(EventConstants.EVT_ITEM_CHANGE_IN_PLAYLIST, null, null);
}
public void dispose() {
_podcastImage.dispose();
_podcastPlayImage.dispose();
_podcastPauseImage.dispose();
_playImage.dispose();
_markReadImage.dispose();
_markUnreadImage.dispose();
_newImage.dispose();
_removeImage.dispose();
_refreshImage.dispose();
// Unregister listener
Controller.getInstance().getEventController().removePlaylistChangeListener(this);
Controller.getInstance().getEventController().removeAudioItemChangeListener(this);
super.dispose();
}
@Override
public void setFocus() {
if (viewer != null) {
viewer.getControl().setFocus();
}
}
@Override
public void propertyChange(PropertyChangeEvent arg0) {
if ((arg0.getPropertyName().equals(EventConstants.EVT_ADD_PLAYLIST)) ||
(arg0.getPropertyName().equals(EventConstants.EVT_REMOVE_PLAYLIST)) ||
(arg0.getPropertyName().equals(EventConstants.EVT_SORT_PLAYLIST_LIST)) ||
(arg0.getPropertyName().equals(EventConstants.EVT_ITEM_CHANGE_IN_PLAYLIST)) ||
(arg0.getPropertyName().equals(EventConstants.EVT_PLAY_NEW_AUDIO_ITEM)) ||
(arg0.getPropertyName().equals(EventConstants.EVT_STOP_PLAYBACK)) ||
(arg0.getPropertyName().equals(EventConstants.EVT_PAUSE_PLAYBACK))) {
class refreshViewer implements Runnable {
public void run() {
viewer.refresh();
}
}
Display.getDefault().asyncExec(new refreshViewer());
}
}
}