/*
* The GPLv3 licence :
* -----------------
* Copyright (c) 2009 Ricardo Dias
*
* This file is part of MuVis.
*
* MuVis 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 3 of the License, or
* (at your option) any later version.
*
* MuVis 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 MuVis. If not, see <http://www.gnu.org/licenses/>.
*/
package muvis.view;
import muvis.view.table.ListViewTableView;
import com.vlsolutions.swing.docking.DockKey;
import com.vlsolutions.swing.docking.Dockable;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Hashtable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import muvis.Elements;
import muvis.Environment;
import muvis.database.MusicLibraryDatabaseManager;
import muvis.filters.BeatTableFilter;
import muvis.filters.DurationTableFilter;
import muvis.filters.GenreTableFilter;
import muvis.filters.MoodTableFilter;
import muvis.filters.TableFilterManager;
import muvis.filters.TextTableFilter;
import muvis.filters.YearTableFilter;
import muvis.util.Observable;
import muvis.util.Observer;
import muvis.view.filters.MuVisBeatFilterDraw;
import muvis.view.filters.MuVisBeatFilterNode;
import muvis.view.filters.MuVisBeatFilterSize;
import muvis.view.filters.MuVisDurationFilterDraw;
import muvis.view.filters.MuVisDurationFilterNode;
import muvis.view.filters.MuVisDurationFilterSize;
import muvis.view.filters.MuVisFilterAction;
import muvis.view.filters.MuVisFilterDraw;
import muvis.view.filters.MuVisGenreFilterDraw;
import muvis.view.filters.MuVisGenreFilterNode;
import muvis.view.filters.MuVisGenreFilterSize;
import muvis.view.filters.MuVisMoodFilterDraw;
import muvis.view.filters.MuVisMoodFilterNode;
import muvis.view.filters.MuVisMoodFilterSize;
import muvis.view.filters.MuVisYearFilterDraw;
import muvis.view.filters.MuVisYearFilterNode;
import muvis.view.filters.MuVisYearFilterSize;
import muvis.view.main.MuVisComputeAlbumSize;
import muvis.view.main.MuVisComputeEqualSize;
import muvis.view.main.MuVisComputeTrackSize;
import muvis.view.main.TMAlgorithmAscOrder;
import muvis.view.main.TMAlgorithmDescOrder;
import muvis.view.filters.TMAlgorithmAscOrderFilter;
import muvis.view.main.filters.TreemapFilterManager;
import net.bouthier.treemapSwing.TMAlgorithmSquarified;
import net.bouthier.treemapSwing.TMView;
import net.bouthier.treemapSwing.TreeMap;
/**
* Panel that holds the filter visualization and the main visualization
* @author Ricardo
*/
public class MainViewHolder extends MainViewHolderUI implements Dockable, ActionListener, Observer, ComponentListener {
private DockKey key;
private JPanel currentPanel;
private String currentPanelStr;
private Hashtable<String, JPanel> mainViewPanels;
private TableFilterManager tableFilterManager;
private TreemapFilterManager treemapFilterManager;
private ScheduledExecutorService scheduler;
/*
* Table Filter elements
*/
private DurationTableFilter durationFilter;
private TextTableFilter textTableFilter;
private YearTableFilter yearTableFilter;
private GenreTableFilter genreTableFilter;
private MoodTableFilter moodTableFilter;
private BeatTableFilter beatTableFilter;
/*
* Duration Filter Elements
*/
private MuVisDurationFilterNode durationFilterRoot;
private TreeMap durationFilterTreeMap;
private MuVisDurationFilterSize durationFilterSize;
private MuVisFilterDraw durationFilterDraw;
private TMView durationFilterView;
private MuVisFilterAction durationAction;
/*
* Year Filter Elements
*/
MuVisYearFilterNode yearFilterRoot;
TreeMap yearFilterTreeMap;
MuVisYearFilterSize yearFilterSize;
MuVisFilterDraw yearFilterDraw;
TMView yearFilterView;
MuVisFilterAction yearAction;
/*
* Genre Filter Elements
*/
MuVisGenreFilterNode genreFilterRoot;
TreeMap genreFilterTreeMap;
MuVisGenreFilterSize genreFilterSize;
MuVisFilterDraw genreFilterDraw;
TMView genreFilterView;
MuVisFilterAction genreAction;
/*
* Mood Filter Elements
*/
MuVisMoodFilterNode moodFilterRoot;
TreeMap moodFilterTreeMap;
MuVisMoodFilterSize moodFilterSize;
MuVisFilterDraw moodFilterDraw;
TMView moodFilterView;
MuVisFilterAction moodAction;
/*
* Beat Filter Elements
*/
MuVisBeatFilterNode beatFilterRoot;
TreeMap beatFilterTreeMap;
MuVisBeatFilterSize beatFilterSize;
MuVisFilterDraw beatFilterDraw;
TMView beatFilterView;
MuVisFilterAction beatAction;
/*
* TreeMap features
*/
MuVisComputeTrackSize treemapTrackSize;
MuVisComputeAlbumSize treemapAlbumsSize;
MuVisComputeEqualSize treemapEqualSize;
TMAlgorithmAscOrder treemapAlgorithmAscOrder;
TMAlgorithmDescOrder treemapAlgorithmDescOrder;
public void addView(String viewName, JPanel panel) {
mainViewPanels.put(viewName, panel);
}
public void setView(String viewName) {
if (currentPanel != null) {
mainViewPanel.remove(currentPanel);
}
currentPanelStr = viewName;
currentPanel = mainViewPanels.get(viewName);
mainViewPanel.add(currentPanel, viewName);
mainViewPanel.validate();
if (viewName.equals(Elements.TREEMAP_VIEW) || viewName.equals(Elements.ARTIST_INSPECTOR_VIEW)) {
mainViewHolderTabs.setEnabledAt(1, true);
} else {
if (mainViewHolderTabs.getSelectedIndex() == 1) {
mainViewHolderTabs.setSelectedIndex(0);
}
mainViewHolderTabs.setEnabledAt(1, false);
}
}
public JPanel getView(String viewName) {
if (mainViewPanels.containsKey(viewName)) {
return mainViewPanels.get(viewName);
} else {
return null;
}
}
public String getActiveView() {
return currentPanelStr;
}
private void createDurationFilterView() {
durationFilterRoot = new MuVisDurationFilterNode();
durationFilterTreeMap = new TreeMap(durationFilterRoot);
durationFilterSize = new MuVisDurationFilterSize();
durationFilterDraw = new MuVisDurationFilterDraw();//new MuVisFilterDraw();
durationFilterView = durationFilterTreeMap.getView(durationFilterSize, durationFilterDraw);
durationAction = new MuVisFilterAction(durationFilterView);
durationFilterView.setAction(durationAction);
durationFilterView.addAlgorithm(new TMAlgorithmAscOrderFilter(), "durationOrdered");
durationFilterView.setAlgorithm("durationOrdered");
durationTreemapFilterPanel.add(durationFilterView, "DurationFilterView");
durationFilterView.setEnabled(true);
}
private void createYearFilterView() {
yearFilterRoot = new MuVisYearFilterNode();
yearFilterTreeMap = new TreeMap(yearFilterRoot);
yearFilterSize = new MuVisYearFilterSize();
yearFilterDraw = new MuVisYearFilterDraw();//new MuVisFilterDraw();
yearFilterView = yearFilterTreeMap.getView(yearFilterSize, yearFilterDraw);
yearAction = new MuVisFilterAction(yearFilterView);
yearFilterView.setAction(yearAction);
//yearFilterView.setAlgorithm(TMView.SQUARIFIED);
yearFilterView.addAlgorithm(new TMAlgorithmAscOrderFilter(), "yearOrdered");
yearFilterView.setAlgorithm("yearOrdered");
yearTreemapFilterPanel.add(yearFilterView, "YearFilterView");
yearFilterView.setEnabled(true);
}
private void createGenreFilterView() {
genreFilterRoot = new MuVisGenreFilterNode();
genreFilterTreeMap = new TreeMap(genreFilterRoot);
genreFilterSize = new MuVisGenreFilterSize();
genreFilterDraw = new MuVisGenreFilterDraw();//new MuVisFilterDraw();
genreFilterView = genreFilterTreeMap.getView(genreFilterSize, genreFilterDraw);
genreAction = new MuVisFilterAction(genreFilterView);
genreFilterView.setAction(genreAction);
//genreFilterView.setAlgorithm(TMView.SQUARIFIED);
genreFilterView.addAlgorithm(new TMAlgorithmAscOrderFilter(), "genreOrdered");
genreFilterView.setAlgorithm("genreOrdered");
genreTreemapFilterPanel.add(genreFilterView, "GenreFilterView");
genreFilterView.setEnabled(true);
}
private void createMoodFilterView() {
moodFilterRoot = new MuVisMoodFilterNode();
moodFilterTreeMap = new TreeMap(moodFilterRoot);
moodFilterSize = new MuVisMoodFilterSize();
moodFilterDraw = new MuVisMoodFilterDraw();//new MuVisFilterDraw();
moodFilterView = moodFilterTreeMap.getView(moodFilterSize, moodFilterDraw);
moodAction = new MuVisFilterAction(moodFilterView);
moodFilterView.setAction(moodAction);
moodFilterView.addAlgorithm(new TMAlgorithmAscOrderFilter(), "moodOrdered");
moodFilterView.setAlgorithm("moodOrdered");
moodTreemapFilterPanel.add(moodFilterView, "MoodFilterView");
moodFilterView.setEnabled(true);
}
private void createBeatFilterView() {
beatFilterRoot = new MuVisBeatFilterNode();
beatFilterTreeMap = new TreeMap(beatFilterRoot);
beatFilterSize = new MuVisBeatFilterSize();
beatFilterDraw = new MuVisBeatFilterDraw(); //new MuVisFilterDraw();
beatFilterView = beatFilterTreeMap.getView(beatFilterSize, beatFilterDraw);
beatAction = new MuVisFilterAction(beatFilterView);
beatFilterView.setAction(beatAction);
beatFilterView.addAlgorithm(new TMAlgorithmAscOrderFilter(), "beatOrdered");
beatFilterView.setAlgorithm("beatOrdered");
beatTreemapFilterPanel.add(beatFilterView, "BeatFilterView");
beatFilterView.setEnabled(true);
}
public void initializeFilters() {
createDurationFilterView();
createYearFilterView();
createGenreFilterView();
createMoodFilterView();
createBeatFilterView();
durationFilter = new DurationTableFilter();
textTableFilter = new TextTableFilter();
yearTableFilter = new YearTableFilter();
genreTableFilter = new GenreTableFilter();
beatTableFilter = new BeatTableFilter();
moodTableFilter = new MoodTableFilter();
if (currentPanel instanceof ListViewTableView) {
tableFilterManager = new TableFilterManager(((ListViewTableView) currentPanel).getSorter());
Environment.getEnvironmentInstance().setTableFilterManager(tableFilterManager);
tableFilterManager.addTableFilter(durationFilter);
tableFilterManager.addTableFilter(textTableFilter);
tableFilterManager.addTableFilter(yearTableFilter);
tableFilterManager.addTableFilter(genreTableFilter);
tableFilterManager.addTableFilter(beatTableFilter);
tableFilterManager.addTableFilter(moodTableFilter);
durationAction.registerObserver(tableFilterManager);
yearAction.registerObserver(tableFilterManager);
genreAction.registerObserver(tableFilterManager);
beatAction.registerObserver(tableFilterManager);
moodAction.registerObserver(tableFilterManager);
}
treemapFilterManager = Environment.getEnvironmentInstance().getTreemapFilterManager();
durationAction.registerObserver(treemapFilterManager);
yearAction.registerObserver(treemapFilterManager);
genreAction.registerObserver(treemapFilterManager);
beatAction.registerObserver(treemapFilterManager);
moodAction.registerObserver(treemapFilterManager);
TextFieldListener textListener = new TextFieldListener(searchTextField);
searchTextField.getDocument().addDocumentListener(textListener);
textListener.registerObserver(treemapFilterManager);
textListener.registerObserver(tableFilterManager);
treemapFilterManager.registerObserver(this);
durationFilterLabel.addMouseListener(new FilterInspector(durationTreemapFilterPanel, durationFilterView));
yearFilterLabel.addMouseListener(new FilterInspector(yearTreemapFilterPanel, yearFilterView));
genreFilterLabel.addMouseListener(new FilterInspector(genreTreemapFilterPanel, genreFilterView));
beatFilterLabel.addMouseListener(new FilterInspector(beatTreemapFilterPanel, beatFilterView));
moodFilterLabel.addMouseListener(new FilterInspector(moodTreemapFilterPanel, moodFilterView));
updateDisplayInfo();
}
public MainViewHolder(JFrame parent) {
key = new DockKey("Main");
mainViewPanels = new Hashtable<String, JPanel>();
key.setTooltip("Main view of your library");
key.setCloseEnabled(false);
key.setAutoHideEnabled(false);
key.setMaximizeEnabled(false);
treemapTrackSize = new MuVisComputeTrackSize();
treemapAlbumsSize = new MuVisComputeAlbumSize();
treemapEqualSize = new MuVisComputeEqualSize();
/*treemapAlgorithmAscOrder = new TMAlgorithmAscOrder();
treemapAlgorithmDescOrder = new TMAlgorithmDescOrder();*/
treemapSquareSizeComboBox.addActionListener(this);
treemapStructureVisualization.addActionListener(this);
scheduler = Executors.newSingleThreadScheduledExecutor();
parent.addComponentListener(this);
// Get a handle, starting now, with a 10 second delay
class UpdateInfoDisplay implements Runnable, Observer {
boolean update = false;
@Override
public void run() {
if (update) {
update = false;
updateDisplayInfo();
}
}
@Override
public void update(Observable obs, Object arg) {
if (obs instanceof MusicLibraryDatabaseManager) {
update = true;
}
}
}
UpdateInfoDisplay updateTable = new UpdateInfoDisplay();
Environment.getEnvironmentInstance().getDatabaseManager().registerObserver(updateTable);
scheduler.scheduleAtFixedRate(updateTable, 10, 45, TimeUnit.SECONDS);
resetFiltersButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
treemapFilterManager.reset();
searchTextField.setText("");
tableFilterManager.resetFilters();
tableFilterManager.filter();
}
});
}
});
}
@Override
public DockKey getDockKey() {
return key;
}
@Override
public Component getComponent() {
return this;
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == treemapSquareSizeComboBox) {
JComboBox cb = (JComboBox) e.getSource();
String typeSize = (String) cb.getSelectedItem();
TreemapView tView = (TreemapView) mainViewPanels.get("TreeMapView");
if (typeSize.contains("tracks")) { //size depends on the number of tracks
tView.getCurrentView().changeTMComputeSize(treemapTrackSize);
} else if (typeSize.contains("albums")) { //size depends on the number of artist albums
tView.getCurrentView().changeTMComputeSize(treemapAlbumsSize);
} else { //the size is equal to all artists
tView.getCurrentView().changeTMComputeSize(treemapEqualSize);
}
} else if (e.getSource() == treemapStructureVisualization) {
JComboBox cb = (JComboBox) e.getSource();
String structureType = (String) cb.getSelectedItem();
TreemapView tView = (TreemapView) mainViewPanels.get("TreeMapView");
if (structureType.contains("Similarity")) {
tView.getCurrentView().setAlgorithm("SimilarityAlgorithm");
chooseSeedArtistButton.setEnabled(true);
} else if (structureType.contains("Asc")) {
tView.getCurrentView().setAlgorithm("AscOrderAlgorithm");
chooseSeedArtistButton.setEnabled(false);
} else if (structureType.contains("Desc")) {
tView.getCurrentView().setAlgorithm("DescOrderAlgorithm");
chooseSeedArtistButton.setEnabled(false);
}
}
}
@Override
public void update(Observable obs, Object arg) {
if (obs instanceof TreemapFilterManager) {
updateDisplayInfo();
}
}
protected void updateDisplayInfo() {
String name = "Main - Browsing " + treemapFilterManager.getCountFilteredTracks() + " tracks";
name += " in " + treemapFilterManager.getCountFilteredAlbums() + " albums";
key.setName(name);
}
@Override
public void componentResized(ComponentEvent e) {
if (e.getComponent() instanceof JFrame) {
Dimension size = e.getComponent().getSize();
double width = featuresFilterPanel.getSize().getWidth();
double diffHeight = 770 - size.getHeight();
double height = 667 - diffHeight;
Dimension newSize = new Dimension((int) width, (int) height);
mainViewHolderTabs.setSize(newSize);
featuresFilterPanel.setSize(newSize);
filtersPanel.setSize(newSize);
}
}
@Override
public void componentMoved(ComponentEvent e) {
//TO NOTHING
}
@Override
public void componentShown(ComponentEvent e) {
//TO NOTHING
}
@Override
public void componentHidden(ComponentEvent e) {
//TO NOTHING
}
}
class FilterInspector implements MouseListener {
JFrame frame = null;
JPanel panel;
TMView view;
FilterInspector(JPanel panel, TMView view) {
this.panel = panel;
this.view = view;
}
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
if (frame == null) {
final JLabel label = (JLabel)e.getSource();
frame = new JFrame(label.getText());
frame.setSize(new Dimension(320, 240));
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
panel.add(view, label.getText());
panel.validate();
}
});
}
frame.add(view);
frame.setSize(new Dimension(320, 240));
frame.setVisible(true);
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}