/*
* 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.MenuManager;
import org.eclipse.jface.resource.ImageDescriptor;
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.Menu;
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.PlayAction;
import org.jampa.gui.translations.Messages;
import org.jampa.logging.Log;
import org.jampa.model.playlists.AudioItem;
import org.jampa.model.playlists.Playlist;
import org.jampa.utils.Constants;
import org.jampa.utils.Utils;
public class PlaylistView extends ViewPart implements PropertyChangeListener {
public static String ID = "Jampa.PlaylistView"; //$NON-NLS-1$
private TableViewer viewer;
private String _id;
private Playlist _thePlaylist;
private Image _playImage;
private Image _pauseImage;
private Image _titleImage;
private Image _titlePlayImage;
private Image _titlePauseImage;
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().getPlaylistData(_id);
}
}
class ViewLabelProvider extends LabelProvider implements ITableLabelProvider {
public Image getImage(Object obj) {
if (Controller.getInstance().getEngine().isPaused())
return _pauseImage;
else
return _playImage;
}
public Image getColumnImage(Object obj, int index) {
if (index == 0) {
if (((AudioItem) obj).isBoPlaying())
return getImage(obj);
else
return null;
}
else
return null;
}
public String getColumnText(Object obj, int index) {
String result;
switch (index) {
case 1 : result = ((AudioItem) obj).getTrackNumber(); break;
case 2 : result = ((AudioItem) obj).getPropertiesList().get(AudioItem.TITLE); break;
case 3 : result = ((AudioItem) obj).getPropertiesList().get(AudioItem.ARTIST); break;
case 4 : result = ((AudioItem) obj).getPropertiesList().get(AudioItem.ALBUM); break;
case 5 : result = ((AudioItem) obj).getPropertiesList().get(AudioItem.GENRE); break;
case 6 : result = Utils.seconds2String(((AudioItem) obj).getTrackLength()); break;
case 7 : result = ((AudioItem) obj).getPropertiesList().get(AudioItem.YEAR); break;
default : result = ""; //$NON-NLS-1$
}
return result;
}
}
public PlaylistView() {
Activator.getDefault();
ImageDescriptor playImageDescriptor = Activator.getImageDescriptor("/icons/playing_16.png"); //$NON-NLS-1$
_playImage = playImageDescriptor.createImage();
ImageDescriptor pauseImageDescriptor = Activator.getImageDescriptor("/icons/pause_16.png"); //$NON-NLS-1$
_pauseImage = pauseImageDescriptor.createImage();
ImageDescriptor titleImageDescriptor = Activator.getImageDescriptor("/icons/playlist_16.png"); //$NON-NLS-1$
_titleImage = titleImageDescriptor.createImage();
ImageDescriptor titlePlayImageDescriptor = Activator.getImageDescriptor("/icons/playlistplay_16.png"); //$NON-NLS-1$
_titlePlayImage = titlePlayImageDescriptor.createImage();
ImageDescriptor titlePauseImageDescriptor = Activator.getImageDescriptor("/icons/playlistpause_16.png"); //$NON-NLS-1$
_titlePauseImage = titlePauseImageDescriptor.createImage();
}
@Override
public void createPartControl(Composite parent) {
_id = this.getViewSite().getSecondaryId();
if (_id.equals(Constants.DEFAULT_PLAYLIST_ID)) {
this.setPartName(Messages.getString("PlaylistView.DefaultPlaylistTitle")); //$NON-NLS-1$
} else {
this.setPartName(_id);
}
if ((Controller.getInstance().getPlaylistController().getCurrentPlaylist() != null) &&
(Controller.getInstance().getPlaylistController().getCurrentPlaylist().getName().equals(_id))) {
if (Controller.getInstance().getEngine().isPaused())
this.setTitleImage(_titlePauseImage);
else
this.setTitleImage(_titlePlayImage);
} else {
this.setTitleImage(_titleImage);
}
_thePlaylist = Controller.getInstance().getPlaylistController().getPlaylistByName(_id);
this.viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
TableLayout layout = new TableLayout();
layout.addColumnData(new ColumnWeightData(5, 20, true));
layout.addColumnData(new ColumnWeightData(10, 35, true));
layout.addColumnData(new ColumnWeightData(250, 150, true));
layout.addColumnData(new ColumnWeightData(200, 150, true));
layout.addColumnData(new ColumnWeightData(200, 150, true));
layout.addColumnData(new ColumnWeightData(30, 75, true));
layout.addColumnData(new ColumnWeightData(30, 75, true));
layout.addColumnData(new ColumnWeightData(30, 50, true));
viewer.getTable().setLayout(layout);
// Lines visible is ugly under Windows.
if (!Util.isWindows()) {
viewer.getTable().setLinesVisible(true);
}
viewer.getTable().setHeaderVisible(true);
TableColumn columnIcon = new TableColumn(viewer.getTable(), SWT.NONE);
columnIcon.setText(""); //$NON-NLS-1$
TableColumn columnTrack = new TableColumn(viewer.getTable(), SWT.NONE);
columnTrack.setText(Messages.getString("PlaylistView.TrackNumber")); //$NON-NLS-1$
columnTrack.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
Controller.getInstance().getPlaylistController().sortPlaylist(_thePlaylist, 3);
}
});
TableColumn columnTitle = new TableColumn(viewer.getTable(), SWT.NONE);
columnTitle.setText(Messages.getString("PlaylistView.Title")); //$NON-NLS-1$
columnTitle.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
Controller.getInstance().getPlaylistController().sortPlaylist(_thePlaylist, 0);
}
});
TableColumn columnArtist = new TableColumn(viewer.getTable(), SWT.NONE);
columnArtist.setText(Messages.getString("PlaylistView.Artist")); //$NON-NLS-1$
columnArtist.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
Controller.getInstance().getPlaylistController().sortPlaylist(_thePlaylist, 1);
}
});
TableColumn columnAlbum = new TableColumn(viewer.getTable(), SWT.NONE);
columnAlbum.setText(Messages.getString("PlaylistView.Album")); //$NON-NLS-1$
columnAlbum.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
Controller.getInstance().getPlaylistController().sortPlaylist(_thePlaylist, 2);
}
});
TableColumn columnGenre = new TableColumn(viewer.getTable(), SWT.NONE);
columnGenre.setText(Messages.getString("PlaylistView.Genre")); //$NON-NLS-1$
columnGenre.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
Controller.getInstance().getPlaylistController().sortPlaylist(_thePlaylist, 4);
}
});
TableColumn columnLength = new TableColumn(viewer.getTable(), SWT.NONE);
columnLength.setText(Messages.getString("PlaylistView.Length")); //$NON-NLS-1$
columnLength.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
Controller.getInstance().getPlaylistController().sortPlaylist(_thePlaylist, 5);
}
});
TableColumn columnYear = new TableColumn(viewer.getTable(), SWT.NONE);
columnYear.setText(Messages.getString("PlaylistView.Year")); //$NON-NLS-1$
columnYear.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
Controller.getInstance().getPlaylistController().sortPlaylist(_thePlaylist, 6);
}
});
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();
new PlayAction(_thePlaylist, (AudioItem) obj).run();
}
});
// Popup menu
MenuManager menuManager = new MenuManager();
Menu menu = menuManager.createContextMenu(viewer.getTable());
// Set the MenuManager
viewer.getTable().setMenu(menu);
getSite().registerContextMenu(menuManager, viewer);
// Make the selection available
getSite().setSelectionProvider(viewer);
buildDND();
Controller.getInstance().getEventController().addAudioItemChangeListener(this);
}
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 = _id;
}
public void dragStart(DragSourceEvent event) {
event.data = _id;
Controller.getInstance().getDNDController().setSource(_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().isLibraryViewSource()) ||
(Controller.getInstance().getDNDController().isDiskViewSource()) ||
(Controller.getInstance().getDNDController().isSamePlaylistViewSource(_id))) {
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;
if (Controller.getInstance().getDNDController().isSamePlaylistViewSource(_id)) {
event.detail = DND.DROP_MOVE;
} else {
event.detail = DND.DROP_COPY;
}
}
else {
if ((Controller.getInstance().getDNDController().isLibraryViewSource()) ||
(Controller.getInstance().getDNDController().isDiskViewSource())) {
// Drop from Library or Disk View, can be done on any place of the view,
// even "outside" an item.
event.feedback = DND.FEEDBACK_NONE;
} 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;
}
}
private int getDropIndex(DropTargetEvent event) {
// Get the current item.
Point pt = Display.getCurrent().map(null, viewer.getTable(), event.x, event.y);
TableItem item = viewer.getTable().getItem(pt);
// Get the index of the drop.
if (item != null) {
Playlist playlist = Controller.getInstance().getPlaylistController().getPlaylistByName(_id);
return playlist.getAudioItemIndex((AudioItem) item.getData());
} else {
return -1;
}
}
@SuppressWarnings("unchecked")
public void drop(DropTargetEvent event) {
if (Controller.getInstance().getDNDController().isSamePlaylistViewSource(_id)) {
// Drag from current view.
// Get the current item.
Point pt = Display.getCurrent().map(null, viewer.getTable(), event.x, event.y);
TableItem item = viewer.getTable().getItem(pt);
// Get the index of the drop.
Playlist playlist = Controller.getInstance().getPlaylistController().getPlaylistByName(_id);
int index = playlist.getAudioItemIndex((AudioItem) item.getData());
// Make a list of items to move.
AudioItem itemToMove;
AudioItem firstItem = null;
List<AudioItem> list = new ArrayList<AudioItem>();
ISelection selection = viewer.getSelection();
Iterator iter = ((IStructuredSelection) selection).iterator();
while (iter.hasNext()) {
itemToMove = (AudioItem) iter.next();
if (firstItem == null)
firstItem = itemToMove;
list.add(itemToMove);
}
// If moving up, move in reverse order to keep the initial order.
if (playlist.getAudioItemIndex(firstItem) > index) {
for (int i = list.size() - 1; i >= 0; i--) {
Controller.getInstance().getPlaylistController().moveTitleAtIndex(_id, index, list.get(i));
}
} else {
for (int i = 0; i < list.size(); i++) {
Controller.getInstance().getPlaylistController().moveTitleAtIndex(_id, index, list.get(i));
}
}
} else if (Controller.getInstance().getDNDController().isLibraryViewSource()) {
// Drag from Library view.
Log.getInstance(PlaylistView.class).debug("Drop from Library View."); //$NON-NLS-1$
if (Controller.getInstance().getDNDController().getLibrarySelection() != null) {
Log.getInstance(PlaylistView.class).debug("Adding items to playlist: " + _id); //$NON-NLS-1$
int index = getDropIndex(event);
Controller.getInstance().getPlaylistController().addItemToPlaylist(_id, Controller.getInstance().getDNDController().getLibrarySelection(), false, index);
}
} else if (Controller.getInstance().getDNDController().isDiskViewSource()) {
// Drag from Disk view.
Log.getInstance(PlaylistView.class).debug("Drop from Disk View."); //$NON-NLS-1$
if (Controller.getInstance().getDNDController().getDiskSelection() != null) {
Log.getInstance(PlaylistView.class).debug("Adding items to playlist: " + _id); //$NON-NLS-1$
int index = getDropIndex(event);
Controller.getInstance().getPlaylistController().addDiskItemsToPlaylist(_id, Controller.getInstance().getDNDController().getDiskSelection(), false, index);
}
}
}
});
}
@Override
public void setFocus() {
viewer.getControl().setFocus();
}
public void dispose() {
_playImage.dispose();
_pauseImage.dispose();
_titleImage.dispose();
_titlePlayImage.dispose();
_titlePauseImage.dispose();
Controller.getInstance().getEventController().removeAudioItemChangeListener(this);
super.dispose();
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
class refreshViewer implements Runnable {
public void run() {
viewer.refresh();
}
}
class iconUpdater implements Runnable {
private Image _image;
public iconUpdater(Image image) {
_image = image;
}
public void run() {
setTitleImage(_image);
}
}
if ((evt.getPropertyName().equals(EventConstants.EVT_PLAY_NEW_AUDIO_ITEM)) ||
(evt.getPropertyName().equals(EventConstants.EVT_STOP_PLAYBACK)) ||
(evt.getPropertyName().equals(EventConstants.EVT_PAUSE_PLAYBACK)) ||
(evt.getPropertyName().equals(EventConstants.EVT_ITEM_CHANGE_IN_PLAYLIST)) ||
(evt.getPropertyName().equals(EventConstants.EVT_SORT_PLAYLIST))) {
if ((Controller.getInstance().getPlaylistController().getCurrentPlaylist() != null) &&
(Controller.getInstance().getPlaylistController().getCurrentPlaylist().getName().equals(_id))) {
if (evt.getPropertyName().equals(EventConstants.EVT_PLAY_NEW_AUDIO_ITEM)) {
Display.getDefault().asyncExec(new iconUpdater(_titlePlayImage));
}
if (evt.getPropertyName().equals(EventConstants.EVT_PAUSE_PLAYBACK)) {
if (Controller.getInstance().getEngine().isPaused())
Display.getDefault().asyncExec(new iconUpdater(_titlePauseImage));
else
Display.getDefault().asyncExec(new iconUpdater(_titlePlayImage));
}
} else {
Display.getDefault().asyncExec(new iconUpdater(_titleImage));
}
if (evt.getPropertyName().equals(EventConstants.EVT_STOP_PLAYBACK)) {
Display.getDefault().asyncExec(new iconUpdater(_titleImage));
}
Display.getDefault().asyncExec(new refreshViewer());
}
}
public TableViewer getViewer() {
return viewer;
}
}