diff options
Diffstat (limited to 'cmpcj/src/de/schwarzrot/control')
21 files changed, 2689 insertions, 0 deletions
diff --git a/cmpcj/src/de/schwarzrot/control/app/AboutDialog.java b/cmpcj/src/de/schwarzrot/control/app/AboutDialog.java new file mode 100644 index 0000000..7a361cf --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/app/AboutDialog.java @@ -0,0 +1,69 @@ +/** + * ======================== legal notice ====================== + * + * File: AboutDialog.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.app; + + +import java.awt.Dimension; +import java.awt.Window; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; +import de.schwarzrot.base.util.AbstractDialog; + + +public class AboutDialog extends AbstractDialog { + private static final long serialVersionUID = 713L; + + + public AboutDialog(Window parent) { + super(parent, true, DialogMode.CLOSE, Orientation.Center); + } + + + @Override + public JComponent createContentPane() { + JPanel rv = new JPanel(); + + rv.setLayout(new BoxLayout(rv, BoxLayout.Y_AXIS)); + rv.setBorder(new EmptyBorder(20, 20, 20, 20)); + JLabel appInfo = new JLabel(msgBundle.getMessage(getClass().getSimpleName() + ".app.info"), JLabel.CENTER); + + rv.add(appInfo); + JLabel aboutText = new JLabel(msgBundle.getMessage(getClass().getSimpleName() + ".about.text"), JLabel.CENTER); + + rv.add(aboutText); + rv.add(Box.createRigidArea(new Dimension(0, 30))); + JLabel contribution = new JLabel(msgBundle.getMessage(getClass().getSimpleName() + ".contribution"), + JLabel.LEFT); + + rv.add(contribution); + + return rv; + } +} diff --git a/cmpcj/src/de/schwarzrot/control/app/CMPCJ.java b/cmpcj/src/de/schwarzrot/control/app/CMPCJ.java new file mode 100644 index 0000000..639d9fc --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/app/CMPCJ.java @@ -0,0 +1,736 @@ +/** + * ======================== legal notice ====================== + * + * File: MCC.java Created: 13. June 2012, 04:57 Author: <a + * href="mailto:geronimo013@gmx.de">Geronimo</a> Project: cmpc - a java frontend + * (client) part of compound media player uses external players to play the + * media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any + * workstation without the need to export or mount shares. cmps is an easy to + * use backend with a (ready to use) HTML-interface. Additionally the backend + * supports authentication via HTTP-digest authorization. cmpc is a client with + * vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! published under + * Creative Commons by-sa For details see + * http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at + * http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.app; + + +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStreamReader; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import javax.swing.AbstractAction; +import javax.swing.DropMode; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSeparator; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.JTree; +import javax.swing.KeyStroke; +import javax.swing.UIManager; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeModel; +import bibliothek.gui.dock.common.CControl; +import bibliothek.gui.dock.common.CGrid; +import ca.odell.glazedlists.BasicEventList; +import ca.odell.glazedlists.EventList; +import ca.odell.glazedlists.FilterList; +import ca.odell.glazedlists.GlazedLists; +import ca.odell.glazedlists.SortedList; +import ca.odell.glazedlists.event.ListEvent; +import ca.odell.glazedlists.event.ListEventListener; +import ca.odell.glazedlists.swing.DefaultEventSelectionModel; +import ca.odell.glazedlists.swing.DefaultEventTableModel; +import ca.odell.glazedlists.swing.GlazedListsSwing; +import ca.odell.glazedlists.swing.TableComparatorChooser; +import ca.odell.glazedlists.swing.TextComponentMatcherEditor; +import de.schwarzrot.base.dock.BasicDockable; +import de.schwarzrot.base.table.PropertyTableFormat; +import de.schwarzrot.base.util.ActionManager; +import de.schwarzrot.base.util.ApplicationServiceProvider; +import de.schwarzrot.base.util.CallbackDefinition; +import de.schwarzrot.base.util.ImageFactory; +import de.schwarzrot.base.util.MessageBundle; +import de.schwarzrot.base.util.SuccessHandler; +import de.schwarzrot.control.client.CMPClient; +import de.schwarzrot.control.client.MediaClientExecutor; +import de.schwarzrot.control.config.ConfigDialog; +import de.schwarzrot.control.config.ConfigFactory; +import de.schwarzrot.control.dnd.ListSelectionSourceTransferHandler; +import de.schwarzrot.control.dnd.TreeSourceAndDestTransferHandler; +import de.schwarzrot.control.support.MediaTextFilterator; +import de.schwarzrot.control.support.MediaTypeSelector; +import de.schwarzrot.control.support.SelectedMedia; +import de.schwarzrot.control.support.TreeSelectionFilter; +import de.schwarzrot.control.table.MediaTableFormat; +import de.schwarzrot.media.domain.AbstractMediaNode; +import de.schwarzrot.media.domain.Config; +import de.schwarzrot.media.domain.Genre; +import de.schwarzrot.media.domain.Media; +import de.schwarzrot.media.domain.MediaServer; +import de.schwarzrot.media.domain.PlayerDefinition; +import de.schwarzrot.media.service.DataManager; +import de.schwarzrot.media.service.MediaExecutor; +import de.schwarzrot.media.util.ListLoader; +import de.schwarzrot.media.util.MedialistParser; + + +public class CMPCJ extends WindowAdapter implements PropertyChangeListener, SuccessHandler, + ListEventListener<AbstractMediaNode>, MediaClientExecutor { + private static final String PREFFERRED_LOOK_N_FEEL = "Nimbus"; //$NON-NLS-1$ + private static final String USER_HOME = "user.home"; //$NON-NLS-1$ + private static final String DOCKING_CONFIG = "srdocking.conf"; //$NON-NLS-1$ + enum Commands { + SrvOpen, SrvRefresh, SrvClose, SrvShutdown, TransmitChanges, Preferences, HelpHelp, HelpAbout + }; + + + public CMPCJ(String[] args, ConfigFactory configFactory) { + nodeCache = new HashMap<File, DefaultMutableTreeNode>(); + changes = new BasicEventList<AbstractMediaNode>(); + rootNode = new DefaultMutableTreeNode(setupServices(args, configFactory)); + changes.addListEventListener(this); + } + + + public void createAndShow() { + @SuppressWarnings("unchecked") + ActionManager<Commands> am = ApplicationServiceProvider.getService(ActionManager.class); + MessageBundle mb = ApplicationServiceProvider.getService(MessageBundle.class); + + mediaList = new SortedList<Media>(GlazedListsSwing.swingThreadProxyList(new BasicEventList<Media>())); + try { + String lookNFeel = UIManager.getSystemLookAndFeelClassName(); + + for (UIManager.LookAndFeelInfo lfi : UIManager.getInstalledLookAndFeels()) { + if (PREFFERRED_LOOK_N_FEEL.equals(lfi.getName())) + lookNFeel = lfi.getClassName(); + } + UIManager.setLookAndFeel(lookNFeel); + } catch (Exception e) { + System.err.println(mb.getMessage(CMPMessageBundle.MCC_6)); + } + am.addCallbackDefinition(new CallbackDefinition<Commands>(Commands.SrvOpen) { + private static final long serialVersionUID = 713L; + + + @Override + public void actionPerformed(ActionEvent e) { + doConnectServer(); + } + }); + am.addCallbackDefinition(new CallbackDefinition<Commands>(Commands.SrvRefresh, false) { + private static final long serialVersionUID = 713L; + + + @Override + public void actionPerformed(ActionEvent e) { + doServerRescan(); + } + }); + am.addCallbackDefinition(new CallbackDefinition<Commands>(Commands.SrvClose, false) { + private static final long serialVersionUID = 713L; + + + @Override + public void actionPerformed(ActionEvent e) { + doDisconnectServer(); + } + }); + am.addCallbackDefinition(new CallbackDefinition<Commands>(Commands.SrvShutdown, false) { + private static final long serialVersionUID = 713L; + + + @Override + public void actionPerformed(ActionEvent e) { + doShutdownServer(); + } + }); + am.addCallbackDefinition(new CallbackDefinition<Commands>(Commands.TransmitChanges, false) { + private static final long serialVersionUID = 713L; + + + @Override + public void actionPerformed(ActionEvent e) { + doTransmitChanges(); + } + }); + am.addCallbackDefinition(new CallbackDefinition<Commands>(Commands.Preferences) { + private static final long serialVersionUID = 713L; + + + @Override + public void actionPerformed(ActionEvent e) { + doConfigureClient(); + } + }); + am.addCallbackDefinition(new CallbackDefinition<Commands>(Commands.HelpHelp, false) { + private static final long serialVersionUID = 713L; + + + @Override + public void actionPerformed(ActionEvent e) { + doShowHelp(); + } + }); + am.addCallbackDefinition(new CallbackDefinition<Commands>(Commands.HelpAbout) { + private static final long serialVersionUID = 713L; + + + @Override + public void actionPerformed(ActionEvent e) { + doShowAbout(); + } + }); + JMenuBar menuBar = new JMenuBar(); + frame = new JFrame(mb.getMessage(CMPMessageBundle.MCC_7)); + control = new CControl(frame); + frame.addWindowListener(this); + frame.add(setupPerspective(frame)); + frame.setJMenuBar(menuBar); + frame.pack(); + frame.setSize(1200, 800); + frame.setLocationRelativeTo(null); + restorePerspective(); + createMenu(menuBar); + frame.setVisible(true); + } + + + @Override + public void handleFailure(Throwable t) { + // loading list from server failed ... + if (t instanceof UnknownHostException) { + //TODO: tell the user ... + } + t.printStackTrace(); + tree.updateUI(); + updateServerActions(false); + } + + + @Override + public void handleSuccess() { + // loading list from server was successful + tree.updateUI(); + updateServerActions(true); + } + + + @Override + public void listChanged(ListEvent<AbstractMediaNode> arg0) { + // get rid of changes made by user + @SuppressWarnings("unchecked") + ActionManager<Commands> am = ApplicationServiceProvider.getService(ActionManager.class); + boolean changesExists = changes.size() > 0; + + System.out.println("changes updated ..."); + am.getAction(Commands.TransmitChanges).setEnabled(changesExists); + } + + + @Override + public void playMedia(Media m) { + Config config = ApplicationServiceProvider.getService(Config.class); + List<String> command = new ArrayList<String>(); + PlayerDefinition pd = config.getPlayerMap().get(m.getType()); + StringBuilder sb = new StringBuilder("http://"); + + sb.append(clientStub.getServerDefinition().getHostName()); + sb.append(":"); + sb.append(clientStub.getServerDefinition().getPort()); + sb.append(m.getURI()); + + command.add(pd.getExecutable()); + for (String param : pd.getParameters()) { + command.add(param); + } + command.add(sb.toString()); + ProcessBuilder pb = new ProcessBuilder(command); + + pb.redirectErrorStream(true); + try { + Process proc = pb.start(); + BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream())); + String line; + + if (config.isDebug()) { + while ((line = br.readLine()) != null) { + System.err.println(line); + } + } else { + while ((line = br.readLine()) != null) + ; + } + } catch (Throwable t) { + t.printStackTrace(); + } + } + + + @Override + public void propertyChange(PropertyChangeEvent evt) { + propertyList.getReadWriteLock().writeLock().lock(); + propertyList.clear(); + if (selectedMedia.getMedia() != null) + propertyList.addAll(selectedMedia.getMedia().getProperties().entrySet()); + propertyList.getReadWriteLock().writeLock().unlock(); + } + + + @Override + public void windowClosing(WindowEvent e) { + savePerspective(); + control.destroy(); + System.exit(0); + } + + + @Override + public void windowOpened(WindowEvent e) { + doConnectServer(); + } + + + protected JComponent createMediaTableView() { + MessageBundle mb = ApplicationServiceProvider.getService(MessageBundle.class); + JTextField filterEdit = new JTextField(30); + mediaTypeSelector = new MediaTypeSelector(mediaList); + FilterList<Media> typeFilteredMedias = new FilterList<Media>(mediaList, mediaTypeSelector); + FilterList<Media> filteredMedias = new FilterList<Media>(typeFilteredMedias, new TreeSelectionFilter(tree)); + FilterList<Media> textFilteredMedias = new FilterList<Media>(filteredMedias, + new TextComponentMatcherEditor<Media>(filterEdit, new MediaTextFilterator())); + MediaTableFormat mtf = new MediaTableFormat(); + DefaultEventTableModel<Media> mediaTableModel = new DefaultEventTableModel<Media>(textFilteredMedias, mtf); + selectedMedia = new SelectedMedia(textFilteredMedias); + DefaultEventSelectionModel<Media> selectionModel = new DefaultEventSelectionModel<Media>(textFilteredMedias); + JTable mediaJTable = new JTable(mediaTableModel); + + selectedMedia.addPropertyChangeListener(this); + selectionModel.addListSelectionListener(selectedMedia); + mediaJTable.setDragEnabled(true); + mediaJTable.setTransferHandler(new ListSelectionSourceTransferHandler(selectionModel)); + mediaJTable.setSelectionModel(selectionModel); + mediaJTable.addMouseListener(new MediaExecutor(mediaJTable, textFilteredMedias, this)); + @SuppressWarnings({ "rawtypes", "unused" }) + TableComparatorChooser tableSorter = TableComparatorChooser.install(mediaJTable, mediaList, + TableComparatorChooser.MULTIPLE_COLUMN_MOUSE_WITH_UNDO); + JScrollPane mediaTableScrollPane = new JScrollPane(mediaJTable); + int mx = mediaJTable.getColumnModel().getColumnCount(); + + for (int i = 0; i < mx; ++i) { + int cw = mtf.getColumnWidth(i); + + if (cw > 0) + mediaJTable.getColumnModel().getColumn(i).setMaxWidth(cw); + } + JPanel tablePane = new JPanel(); + JLabel lFilter = new JLabel(mb.getMessage(CMPMessageBundle.MCC_18)); + + tablePane.setLayout(new GridBagLayout()); + tablePane.add(lFilter, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, + GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + tablePane.add(filterEdit, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, + GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + tablePane.add(mediaTableScrollPane, new GridBagConstraints(0, 1, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, + GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + + return tablePane; + } + + + protected JComponent createMediaTypeList() { + JPanel rv = new JPanel(); + + return rv; + } + + + protected void createMenu(JMenuBar menuBar) { + MessageBundle mb = ApplicationServiceProvider.getService(MessageBundle.class); + @SuppressWarnings("unchecked") + ActionManager<Commands> am = ApplicationServiceProvider.getService(ActionManager.class); + JMenu mServer = new JMenu(mb.getMessage(CMPMessageBundle.MCC_19)); + JMenu mEdit = new JMenu(mb.getMessage(CMPMessageBundle.MCC_20)); + JMenu mWindow = new JMenu(mb.getMessage(CMPMessageBundle.MCC_21)); + JMenu mHelp = new JMenu(mb.getMessage(CMPMessageBundle.MCC_22)); + + mServer.add(new JMenuItem(am.getAction(Commands.SrvOpen))); + mServer.add(new JMenuItem(am.getAction(Commands.SrvRefresh))); + mServer.add(new JMenuItem(am.getAction(Commands.SrvClose))); + mServer.add(new JSeparator()); + mServer.add(new JMenuItem(am.getAction(Commands.SrvShutdown))); + mEdit.add(new JMenuItem(am.getAction(Commands.TransmitChanges))); + mEdit.add(new JSeparator()); + mEdit.add(new JMenuItem(am.getAction(Commands.Preferences))); + mWindow.add(cdGenreTree.createMenuItem()); + mWindow.add(cdMediaTypes.createMenuItem()); + mWindow.add(cdProperties.createMenuItem()); + //TODO: not yet + // mHelp.add(new JMenuItem(getAction(Commands.HelpHelp))); + // mHelp.add(new JSeparator()); + mHelp.add(new JMenuItem(am.getAction(Commands.HelpAbout))); + + menuBar.add(mServer); + menuBar.add(mEdit); + menuBar.add(mWindow); + menuBar.add(mHelp); + } + + + protected JComponent createPropertyView() { + if (selectedMedia.getMedia() != null) + propertyList = GlazedLists.eventList(selectedMedia.getMedia().getProperties().entrySet()); + else + propertyList = new BasicEventList<Map.Entry<String, Object>>(); + SortedList<Map.Entry<String, Object>> psl = new SortedList<Map.Entry<String, Object>>(propertyList, + new Comparator<Map.Entry<String, Object>>() { + @Override + public int compare(Entry<String, Object> a, Entry<String, Object> b) { + return a.getKey().compareToIgnoreCase(b.getKey()); + } + }); + PropertyTableFormat ptf = new PropertyTableFormat(); + DefaultEventTableModel<Map.Entry<String, Object>> tm = new DefaultEventTableModel<Map.Entry<String, Object>>( + psl, ptf); + JTable propertyTable = new JTable(tm); + JScrollPane psp = new JScrollPane(propertyTable); + int mx = propertyTable.getColumnModel().getColumnCount(); + + for (int i = 0; i < mx; ++i) { + int cw = ptf.getColumnWidth(i); + + if (cw > 0) + propertyTable.getColumnModel().getColumn(i).setMaxWidth(cw); + } + return psp; + } + + + protected JComponent createTreeView() { + TreeModel tm = new DefaultTreeModel(rootNode); + tree = new JTree(tm); + tree.setDragEnabled(true); + tree.setEditable(true); + tree.getActionMap().put("removeGenre", new AbstractAction() { //$NON-NLS-1$ + private static final long serialVersionUID = 713L; + + + @Override + public void actionPerformed(ActionEvent e) { + doRemoveGenre(); + } + }); + tree.getActionMap().put("createGenre", new AbstractAction() { //$NON-NLS-1$ + private static final long serialVersionUID = 713L; + + + @Override + public void actionPerformed(ActionEvent e) { + doCreateGenre(); + } + }); + tree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "removeGenre"); //$NON-NLS-1$ + tree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), "createGenre"); //$NON-NLS-1$ + tree.setDropMode(DropMode.USE_SELECTION); + tree.setTransferHandler(new TreeSourceAndDestTransferHandler(tree, nodeCache, changes)); + JScrollPane treeView = new JScrollPane(tree); + + return treeView; + } + + + protected void doConfigureClient() { + ConfigDialog cd = new ConfigDialog(frame); + + cd.showDialog(frame); + } + + + protected void doConnectServer() { + MessageBundle mb = ApplicationServiceProvider.getService(MessageBundle.class); + Config config = ApplicationServiceProvider.getService(Config.class); + Object ms = JOptionPane.showInputDialog(frame, mb.getMessage(CMPMessageBundle.MCC_12), mb + .getMessage(CMPMessageBundle.MCC_13), JOptionPane.PLAIN_MESSAGE, null, config.getKnownServers() + .toArray(), mb.getMessage(CMPMessageBundle.MCC_14)); + + if (ms instanceof MediaServer) { + System.out.println(mb.getMessage(CMPMessageBundle.MCC_15) + ((MediaServer) ms).getHostName() + + mb.getMessage(CMPMessageBundle.MCC_16) + ((MediaServer) ms).getPort()); + + clientStub = new CMPClient((MediaServer) ms); + ApplicationServiceProvider.registerService(ListLoader.class, clientStub); + DataManager dm = ApplicationServiceProvider.getService(DataManager.class); + + dm.load(rootNode, mediaList, this); + } + } + + + // respond to tree action + protected void doCreateGenre() { + MessageBundle mb = ApplicationServiceProvider.getService(MessageBundle.class); + + System.out.println(mb.getMessage(CMPMessageBundle.MCC_17)); + + //TODO: ask user for genre name and create node and cache entries + tree.updateUI(); + }; + + + protected void doDisconnectServer() { + ApplicationServiceProvider.registerService(MediaServer.class, null); + mediaList.getReadWriteLock().writeLock().lock(); + mediaList.clear(); + mediaList.getReadWriteLock().writeLock().unlock(); + ((DefaultMutableTreeNode) tree.getModel().getRoot()).removeAllChildren(); + tree.updateUI(); + selectedMedia.clear(); + updateServerActions(false); + clientStub = null; + } + + + // respond to tree action + protected void doRemoveGenre() { + MessageBundle mb = ApplicationServiceProvider.getService(MessageBundle.class); + + System.out.println(mb.getMessage(CMPMessageBundle.MCC_0)); + DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getSelectionPath().getLastPathComponent(); + if (node == null) + return; + Genre g = (Genre) node.getUserObject(); + + if (g.getMediaList().size() > 0 || g.getChildren().size() > 0) { + //TODO: ask user and/or pop some warning + } else { + nodeCache.remove(g.getRealPath()); + ((DefaultMutableTreeNode) node.getParent()).remove(node); + tree.updateUI(); + } + } + + + protected void doServerRescan() { + clientStub.execServerRescan(); + } + + + protected void doShowAbout() { + AboutDialog dlgAbout = new AboutDialog(frame); + + dlgAbout.showDialog(frame); + } + + + protected void doShowHelp() { + } + + + protected void doShutdownServer() { + clientStub.execServerShutdown(); + doDisconnectServer(); + } + + + protected void doTransmitChanges() { + clientStub.transmitChanges(changes); + } + + + protected void restoreAppStatus() { + Config config = ApplicationServiceProvider.getService(Config.class); + + try { + if (config != null) { + if (config.getMainWidth() > 0 && config.getMainHeight() > 0) + frame.setSize(config.getMainWidth(), config.getMainHeight()); + + if (config.getPosX() > 0 || config.getPosY() > 0) + frame.setLocation(config.getPosX(), config.getPosY()); + } + } catch (Throwable t) { + t.printStackTrace(); + } + } + + + protected void restorePerspective() { + File dockableSettings = new File(configDirectory, DOCKING_CONFIG); + + try { + if (dockableSettings.exists() && dockableSettings.canRead()) + control.getResources().readFile(dockableSettings); + } catch (Throwable t) { + t.printStackTrace(); + } + restoreAppStatus(); + } + + + protected void saveAppStatus() { + Config config = ApplicationServiceProvider.getService(Config.class); + ConfigFactory cf = ApplicationServiceProvider.getService(ConfigFactory.class); + + try { + Dimension mainDim = frame.getSize(); + Point mainPos = frame.getLocation(); + + config.setMainWidth(mainDim.width); + config.setMainHeight(mainDim.height); + config.setPosX(mainPos.x); + config.setPosY(mainPos.y); + + cf.putConfig(config); + } catch (Throwable t) { + t.printStackTrace(); + } + } + + + protected void savePerspective() { + File dockableSettings = new File(configDirectory, DOCKING_CONFIG); + + try { + if (!dockableSettings.exists()) + dockableSettings.getParentFile().mkdirs(); + control.getResources().writeFile(dockableSettings); + } catch (Throwable t) { + t.printStackTrace(); + } + saveAppStatus(); + } + + + protected JComponent setupPerspective(JFrame frame) { + MessageBundle mb = ApplicationServiceProvider.getService(MessageBundle.class); + + cdGenreTree = new BasicDockable("genreTree", mb.getMessage(CMPMessageBundle.MCC_29), createTreeView()); //$NON-NLS-1$ + cdMediaList = new BasicDockable("mediaList", mb.getMessage(CMPMessageBundle.MCC_31), createMediaTableView()); //$NON-NLS-1$ + cdMediaTypes = new BasicDockable( + "mediaTypes", mb.getMessage(CMPMessageBundle.MCC_33), mediaTypeSelector.getComponent()); //$NON-NLS-1$ + cdProperties = new BasicDockable("properties", mb.getMessage(CMPMessageBundle.MCC_35), createPropertyView()); //$NON-NLS-1$ + CGrid grid = new CGrid(control); + + grid.add(0, 0, 1, 2, cdGenreTree); + grid.add(1, 0, 1, 1, cdMediaList); + grid.add(2, 0, 1, 2, cdMediaTypes); + grid.add(1, 1, 1, 1, cdProperties); + + cdMediaList.setStackable(false); + cdMediaList.setExternalizable(false); + cdMediaList.setMinimizable(false); + control.getContentArea().deploy(grid); + + return control.getContentArea(); + } + + + protected Genre setupServices(String[] args, ConfigFactory configFactory) { + MessageBundle mb = new CMPMessageBundle(); + configDirectory = configFactory.getConfigDirectory(); + ApplicationServiceProvider.registerService(Config.class, configFactory.getConfig()); + ApplicationServiceProvider.registerService(ConfigFactory.class, configFactory); + ApplicationServiceProvider.registerService(MessageBundle.class, mb); + if (args.length > 0) { + File tmp = new File(args[0]); + + if (tmp.exists() && tmp.canRead()) { + System.out.println(mb.getMessage(CMPMessageBundle.MCC_4) + " " + tmp.getAbsolutePath() + + mb.getMessage(CMPMessageBundle.MCC_5)); + + input = tmp; + } + } + ApplicationServiceProvider.registerService(ActionManager.class, new ActionManager<Commands>()); + ApplicationServiceProvider.registerService(DataManager.class, new DataManager(input)); + ApplicationServiceProvider.registerService(ImageFactory.class, new ImageFactory()); + ApplicationServiceProvider.registerService(MedialistParser.class, new MedialistParser()); + + File base = new File("/"); //$NON-NLS-1$ + Genre root = new Genre(base); + + // ApplicationServiceProvider.registerService(FilesystemListLoader.class, new FilesystemListLoader(base)); + + return root; + } + + + protected void updateServerActions(boolean connected) { + @SuppressWarnings("unchecked") + ActionManager<Commands> am = ApplicationServiceProvider.getService(ActionManager.class); + + am.getAction(Commands.SrvOpen).setEnabled(!connected); + am.getAction(Commands.SrvClose).setEnabled(connected); + am.getAction(Commands.SrvRefresh).setEnabled(connected); + am.getAction(Commands.SrvShutdown).setEnabled(connected); + } + + + public static void main(final String[] args) { + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + File configDir = new File(System.getProperty(USER_HOME), ".cmp"); //$NON-NLS-1$ + CMPCJ app = new CMPCJ(args, new ConfigFactory(configDir, "CMPCJ")); + + app.createAndShow(); + } + }); + } + + private DefaultMutableTreeNode rootNode; + private SortedList<Media> mediaList; + private SelectedMedia selectedMedia; + private EventList<AbstractMediaNode> changes; + private Map<File, DefaultMutableTreeNode> nodeCache; + private EventList<Map.Entry<String, Object>> propertyList; + private MediaTypeSelector mediaTypeSelector; + private CMPClient clientStub; + private CControl control; + private JFrame frame; + private BasicDockable cdMediaList; + private BasicDockable cdGenreTree; + private BasicDockable cdMediaTypes; + private BasicDockable cdProperties; + private File configDirectory; + private JTree tree; + private File input; +} diff --git a/cmpcj/src/de/schwarzrot/control/app/CMPMessageBundle.java b/cmpcj/src/de/schwarzrot/control/app/CMPMessageBundle.java new file mode 100644 index 0000000..33c4854 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/app/CMPMessageBundle.java @@ -0,0 +1,73 @@ +/** + * ======================== legal notice ====================== + * + * File: MCCMessageBundle.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.app; + + +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import de.schwarzrot.base.util.MessageBundle; + + +public class CMPMessageBundle implements MessageBundle { + public static final String MCC_0 = "MCC_0"; + public static final String MCC_12 = "MCC_12"; + public static final String MCC_13 = "MCC_13"; + public static final String MCC_14 = "MCC_14"; + public static final String MCC_15 = "MCC_15"; + public static final String MCC_16 = "MCC_16"; + public static final String MCC_17 = "MCC_17"; + public static final String MCC_18 = "MCC_18"; + public static final String MCC_19 = "MCC_19"; + public static final String MCC_20 = "MCC_20"; + public static final String MCC_21 = "MCC_21"; + public static final String MCC_22 = "MCC_22"; + public static final String MCC_29 = "MCC_29"; + public static final String MCC_31 = "MCC_31"; + public static final String MCC_33 = "MCC_33"; + public static final String MCC_35 = "MCC_35"; + public static final String MCC_4 = "MCC_4"; + public static final String MCC_5 = "MCC_5"; + public static final String MCC_6 = "MCC_6"; + public static final String MCC_7 = "MCC_7"; + public static final String PTF_0 = "PTF_0"; + public static final String PTF_1 = "PTF_1"; + public static final String MTF_0 = "MTF_0"; + public static final String MTF_1 = "MTF_1"; + public static final String MTF_2 = "MTF_2"; + + + @Override + public String getMessage(String key) { + try { + return RESOURCE_BUNDLE.getString(key); + } catch (MissingResourceException e) { + return '!' + key + '!'; + } + } + + private final String BUNDLE_NAME = "de.schwarzrot.control.app.lang.messages"; //$NON-NLS-1$ + private final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME); +} diff --git a/cmpcj/src/de/schwarzrot/control/client/CMPClient.java b/cmpcj/src/de/schwarzrot/control/client/CMPClient.java new file mode 100644 index 0000000..38c6ccb --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/client/CMPClient.java @@ -0,0 +1,171 @@ +/** + * ======================== legal notice ====================== + * + * File: CMPClient.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.client; + + +import java.net.ConnectException; +import java.net.URL; +import java.net.URLConnection; +import java.net.UnknownHostException; +import java.util.Date; +import ca.odell.glazedlists.EventList; +import de.schwarzrot.base.util.ApplicationServiceProvider; +import de.schwarzrot.media.domain.AbstractMediaNode; +import de.schwarzrot.media.domain.Media; +import de.schwarzrot.media.domain.MediaServer; +import de.schwarzrot.media.domain.PlayList; +import de.schwarzrot.media.util.ElementConsumer; +import de.schwarzrot.media.util.ListLoader; +import de.schwarzrot.media.util.MedialistParser; + + +public class CMPClient implements ListLoader<Media> { + public CMPClient(MediaServer serverDefinition) { + server = serverDefinition; + } + + + public void execServerRescan() { + try { + URL request = new URL("http", server.getHostName(), server.getPort(), "/refresh"); + URLConnection conn = request.openConnection(); + + conn.connect(); + conn.getContentLength(); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + + public void execServerShutdown() { + try { + URL request = new URL("http", server.getHostName(), server.getPort(), "/stop"); + URLConnection conn = request.openConnection(); + + conn.connect(); + conn.getContentLength(); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + + public MediaServer getServerDefinition() { + return server; + } + + + @Override + public long[] loadFirst(ElementConsumer<Media> consumer) { + MedialistParser jsonParser = ApplicationServiceProvider.getService(MedialistParser.class); + URL request = null; + Date start, end; + long[] rv = new long[2]; + + try { + start = new Date(); + request = new URL("http", server.getHostName(), server.getPort(), "/?format=json"); + URLConnection conn = request.openConnection(); + final PlayList firstPlaylist = jsonParser.parseListChunk(conn.getInputStream()); + + for (Media m : firstPlaylist.getResults()) + consumer.consumeElement(m); + + end = new Date(); + rv[0] = firstPlaylist.getResults().size(); + rv[1] = firstPlaylist.getTotal(); + System.out.println("processing of first playlist-part took " + (end.getTime() - start.getTime()) + " ms."); + } catch (UnknownHostException uhe) { + throw new RuntimeException("failed to connect to " + server.getHostName(), uhe); + } catch (ConnectException ce) { + throw new RuntimeException("connection failure with " + server.getHostName(), ce); + } catch (Throwable t) { + t.printStackTrace(); + } + return rv; + } + + + @Override + public long loadRest(long[] listInfo, ElementConsumer<Media> consumer) { + MedialistParser jsonParser = ApplicationServiceProvider.getService(MedialistParser.class); + URL request = null; + Date start, end; + long rv = 0; + + try { + PlayList next; + URLConnection conn; + long total = listInfo[1]; + long n = listInfo[0]; + long elementsRead = 0; + String uri; + + start = new Date(); + try { + while (n < total) { + uri = String.format("/?start=%d&limit=%d&format=json", n, 100); + request = new URL("http", server.getHostName(), server.getPort(), uri); + conn = request.openConnection(); + next = jsonParser.parseListChunk(conn.getInputStream()); + for (Media m : next.getResults()) + consumer.consumeElement(m); + elementsRead = next.getResults().size(); + n += elementsRead; + rv += elementsRead; + Thread.sleep(10); + } + } catch (UnknownHostException uhe) { + throw new RuntimeException("failed to connect to " + server.getHostName(), uhe); + } catch (ConnectException ce) { + throw new RuntimeException("connection failure with " + server.getHostName(), ce); + } catch (Throwable t) { + System.err.println("Error on chunk #" + n); + t.printStackTrace(); + } + end = new Date(); + System.out.println("processing of rest of playlist took " + (end.getTime() - start.getTime()) + " ms."); + } catch (Throwable t) { + t.printStackTrace(); + } + return rv; + } + + + public void transmitChanges(EventList<AbstractMediaNode> changes) { + for (AbstractMediaNode n : changes) { + System.out.println("geänderter Eintrag: " + n.getClass().getSimpleName() + " - " + n.getName()); //$NON-NLS-1$ + System.out.println("\tverschieben von " + n.getOriginalPath().getAbsolutePath() + " nach " + + n.getRealPath().getAbsolutePath()); + + //TODO: really create jobs for changes, so backend can participate on work + + } + } + + private MediaServer server; +} diff --git a/cmpcj/src/de/schwarzrot/control/client/MediaClientExecutor.java b/cmpcj/src/de/schwarzrot/control/client/MediaClientExecutor.java new file mode 100644 index 0000000..4ad39f2 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/client/MediaClientExecutor.java @@ -0,0 +1,34 @@ +/** + * ======================== legal notice ====================== + * + * File: MediaClientExecutor.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.client; + + +import de.schwarzrot.media.domain.Media; + + +public interface MediaClientExecutor { + public void playMedia(Media m); +} diff --git a/cmpcj/src/de/schwarzrot/control/config/ConfigDialog.java b/cmpcj/src/de/schwarzrot/control/config/ConfigDialog.java new file mode 100644 index 0000000..2acb026 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/config/ConfigDialog.java @@ -0,0 +1,131 @@ +/** + * ======================== legal notice ====================== + * + * File: ConfigDialog.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.config; + + +import java.awt.Window; +import java.util.List; +import javax.swing.JComponent; +import javax.swing.JScrollPane; +import javax.swing.JTabbedPane; +import javax.swing.JTable; +import ca.odell.glazedlists.BasicEventList; +import ca.odell.glazedlists.EventList; +import ca.odell.glazedlists.GlazedLists; +import ca.odell.glazedlists.swing.DefaultEventTableModel; +import de.schwarzrot.base.util.AbstractDialog; +import de.schwarzrot.base.util.ApplicationServiceProvider; +import de.schwarzrot.control.table.PlayerDefinitionTableFormat; +import de.schwarzrot.control.table.ServerDefinitionTableFormat; +import de.schwarzrot.media.domain.AbstractMediaNode; +import de.schwarzrot.media.domain.Config; +import de.schwarzrot.media.domain.MediaServer; +import de.schwarzrot.media.domain.PlayerDefinition; + + +public class ConfigDialog extends AbstractDialog { + private static final long serialVersionUID = 713L; + + + public ConfigDialog(Window parent) { + super(parent, true, DialogMode.CANCEL_APPROVE, Orientation.Right); + config = ApplicationServiceProvider.getService(Config.class); + } + + + @Override + public JComponent createContentPane() { + JTabbedPane rv = new JTabbedPane(); + + rv.addTab("server", createServerTable()); + rv.addTab("player", createPlayerTable()); + + return rv; + } + + + protected JComponent createPlayerTable() { + playerDefinitions = new BasicEventList<PlayerDefinition>(); + for (AbstractMediaNode.SupportedMediaType mt : AbstractMediaNode.SupportedMediaType.values()) { + if (mt == AbstractMediaNode.SupportedMediaType.Unknown) + break; + PlayerDefinition pd = config.getPlayerMap().get(mt); + + pd.setMediaType(mt); + playerDefinitions.add(pd); + } + PlayerDefinitionTableFormat ptf = new PlayerDefinitionTableFormat(); + DefaultEventTableModel<PlayerDefinition> tm = new DefaultEventTableModel<PlayerDefinition>(playerDefinitions, + ptf); + JTable playerTable = new JTable(tm); + JScrollPane playerTableScrollPane = new JScrollPane(playerTable); + int mx = playerTable.getColumnModel().getColumnCount(); + + for (int i = 0; i < mx; ++i) { + int cw = ptf.getColumnWidth(i); + + if (cw > 0) { + playerTable.getColumnModel().getColumn(i).setPreferredWidth(cw); + playerTable.getColumnModel().getColumn(i).setMaxWidth(cw); + } + } + return playerTableScrollPane; + } + + + protected JComponent createServerTable() { + serverDefinitions = GlazedLists.eventList(config.getKnownServers()); + ServerDefinitionTableFormat stf = new ServerDefinitionTableFormat(); + DefaultEventTableModel<MediaServer> tm = new DefaultEventTableModel<MediaServer>(serverDefinitions, stf); + JTable serverTable = new JTable(tm); + JScrollPane serverTableScrollPane = new JScrollPane(serverTable); + int mx = serverTable.getColumnModel().getColumnCount(); + + for (int i = 0; i < mx; ++i) { + int cw = stf.getColumnWidth(i); + + if (cw > 0) { + serverTable.getColumnModel().getColumn(i).setPreferredWidth(cw); + serverTable.getColumnModel().getColumn(i).setMaxWidth(cw); + } + } + return serverTableScrollPane; + } + + + @Override + protected void performApprove() { + System.out.println("should save config now!?!"); + List<MediaServer> cfgServers = config.getKnownServers(); + + cfgServers.clear(); + cfgServers.addAll(serverDefinitions); + } + + private EventList<MediaServer> serverDefinitions; + private EventList<PlayerDefinition> playerDefinitions; + private Config config; +} diff --git a/cmpcj/src/de/schwarzrot/control/config/ConfigFactory.java b/cmpcj/src/de/schwarzrot/control/config/ConfigFactory.java new file mode 100644 index 0000000..5424ef5 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/config/ConfigFactory.java @@ -0,0 +1,225 @@ +/** + * ======================== legal notice ====================== + * + * File: ConfigFactory.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.config; + + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import de.schwarzrot.media.domain.Config; +import de.schwarzrot.media.domain.Media; +import de.schwarzrot.media.domain.MediaServer; +import de.schwarzrot.media.domain.PlayerDefinition; + + +public class ConfigFactory { + protected static final Pattern SETUP_MASK = Pattern.compile("^\\s*(\\S+)\\s*=\\s*(.+)$"); + + + public ConfigFactory(File configDirectory, String applicationID) { + baseDir = configDirectory; + appID = applicationID; + } + + + public Config getConfig() { + if (config == null) { + config = readConfig(); + } + return config; + } + + + public File getConfigDirectory() { + return baseDir; + } + + + public void putConfig(Config config) { + if (config != null) + writeConfig(config); + } + + + protected Config readConfig() { + File setupFile = new File(baseDir, "srclient.conf"); + BufferedReader br = null; + Config rv = new Config(); + + if (setupFile.exists()) { + try { + br = new BufferedReader(new FileReader(setupFile)); + String line, trimmedLine; + + while ((line = br.readLine()) != null) { + trimmedLine = line.trim(); + + if (trimmedLine.isEmpty() || trimmedLine.startsWith("#")) + continue; + Matcher m = SETUP_MASK.matcher(trimmedLine); + + if (m.matches()) { + String key = m.group(1); + String value = m.group(2); + + if (key.compareToIgnoreCase("server") == 0) { + String[] parts = value.split("\\s*\\:\\s*"); + MediaServer ms = null; + + if (parts.length > 1) { + ms = new MediaServer(); + ms.setHostName(parts[0]); + ms.setPort(Integer.decode(parts[1])); + + rv.addServer(ms); + } + } else if (key.compareToIgnoreCase("player") == 0) { + String[] parts = value.split("\\s*\\:\\s*"); + PlayerDefinition pd = null; + + if (parts.length > 1) { + pd = new PlayerDefinition(); + String[] cmdline = parts[1].split("\\s+"); + + pd.setExecutable(cmdline[0]); + + for (int i = 1; i < cmdline.length; ++i) { + pd.addParameter(cmdline[i]); + } + if (parts[0].compareTo("*") == 0) { + // default player + for (Media.SupportedMediaType cmt : Media.SupportedMediaType.values()) + rv.putPlayer(cmt, pd); + } else { + for (Media.SupportedMediaType cmt : Media.SupportedMediaType.values()) { + if (parts[0].compareTo(cmt.name()) == 0) + rv.putPlayer(cmt, pd); + } + } + } + } else if (key.compareToIgnoreCase("size") == 0) { + String[] parts = value.split("\\s*x\\s*"); + + if (parts.length > 1) { + try { + rv.setMainWidth(Integer.decode(parts[0])); + } catch (Throwable t) { + } + try { + rv.setMainHeight(Integer.decode(parts[1])); + } catch (Throwable t) { + } + } + } else if (key.compareToIgnoreCase("pos") == 0) { + String[] parts = value.split("\\s*\\/\\s*"); + + if (parts.length > 1) { + try { + rv.setPosX(Integer.decode(parts[0])); + } catch (Throwable t) { + } + try { + rv.setPosY(Integer.decode(parts[1])); + } catch (Throwable t) { + } + } + } + } + } + } catch (Throwable t) { + t.printStackTrace(); + } finally { + if (br != null) { + try { + br.close(); + } catch (IOException e) { + } + } + } + } + return rv; + } + + + protected void writeConfig(Config config) { + File setupFile = new File(baseDir, "srclient.conf"); + PrintWriter out = null; + StringBuilder sb = null; + + if (!setupFile.exists()) + setupFile.getParentFile().mkdirs(); + try { + out = new PrintWriter(new FileWriter(setupFile)); + + sb = new StringBuilder("#\n# configuration for "); + sb.append(appID).append("\n#"); + out.println(sb.toString()); + for (MediaServer server : config.getKnownServers()) { + sb = new StringBuilder("server = "); + sb.append(server.getHostName()).append(":").append(server.getPort()); + out.println(sb.toString()); + } + out.println(); + sb = new StringBuilder("#\n# currently supported media types ("); + sb.append(Media.SupportedMediaType.LegacyVdrRecording.name()); + sb.append(" is the old PES format):\n"); + sb.append("# "); + sb.append("#"); + out.println(sb.toString()); + for (Media.SupportedMediaType mt : config.getPlayerMap().keySet()) { + PlayerDefinition player = config.getPlayerMap().get(mt); + + sb = new StringBuilder("player = "); + sb.append(mt.name()).append(" : ").append(player.getExecutable()); + for (String p : player.getParameters()) { + sb.append(" ").append(p); + } + out.println(sb.toString()); + } + out.println(); + sb = new StringBuilder("size = "); + sb.append(config.getMainWidth()).append(" x ").append(config.getMainHeight()); + out.println(sb.toString()); + + sb = new StringBuilder("pos = "); + sb.append(config.getPosX()).append(" / ").append(config.getPosY()); + out.println(sb.toString()); + } catch (Throwable t) { + t.printStackTrace(); + } finally { + if (out != null) + out.close(); + } + } + private Config config; + private File baseDir; + private final String appID; +} diff --git a/cmpcj/src/de/schwarzrot/control/dnd/FilelistTransferable.java b/cmpcj/src/de/schwarzrot/control/dnd/FilelistTransferable.java new file mode 100644 index 0000000..678bbc1 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/dnd/FilelistTransferable.java @@ -0,0 +1,72 @@ +/** + * ======================== legal notice ====================== + * + * File: FilelistTransferable.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.dnd; + + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.File; +import java.io.IOException; +import java.util.List; + + +public class FilelistTransferable implements Transferable { + public FilelistTransferable(List<File> fileList) { + files = fileList; + } + + + protected FilelistTransferable() { + } + + + @Override + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { + if (DataFlavor.javaFileListFlavor.equals(flavor)) + return files; + throw new UnsupportedFlavorException(flavor); + } + + + @Override + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { DataFlavor.javaFileListFlavor }; + } + + + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + return DataFlavor.javaFileListFlavor.equals(flavor); + } + + + protected void setFileList(List<File> list) { + files = list; + } + + private List<File> files; +} diff --git a/cmpcj/src/de/schwarzrot/control/dnd/ListSelectionSourceTransferHandler.java b/cmpcj/src/de/schwarzrot/control/dnd/ListSelectionSourceTransferHandler.java new file mode 100644 index 0000000..e396e17 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/dnd/ListSelectionSourceTransferHandler.java @@ -0,0 +1,69 @@ +/** + * ======================== legal notice ====================== + * + * File: ListSelectionSourceTransferHandler.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.dnd; + + +import java.awt.datatransfer.Transferable; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import javax.swing.JComponent; +import javax.swing.TransferHandler; +import ca.odell.glazedlists.EventList; +import ca.odell.glazedlists.swing.DefaultEventSelectionModel; +import de.schwarzrot.media.domain.Media; + + +public class ListSelectionSourceTransferHandler extends TransferHandler { + private static final long serialVersionUID = 713L; + + + public ListSelectionSourceTransferHandler(DefaultEventSelectionModel<Media> selectionModel) { + sm = selectionModel; + } + + + @Override + public Transferable createTransferable(JComponent c) { + if (sm.isSelectionEmpty()) + return null; + EventList<Media> selection = sm.getSelected(); + List<File> transferList = new ArrayList<File>(); + + for (Media m : selection) { + transferList.add(m.getRealPath()); + } + return new FilelistTransferable(transferList); + } + + + @Override + public int getSourceActions(JComponent c) { + return TransferHandler.LINK; + } + + private DefaultEventSelectionModel<Media> sm; +} diff --git a/cmpcj/src/de/schwarzrot/control/dnd/TreePathTransferable.java b/cmpcj/src/de/schwarzrot/control/dnd/TreePathTransferable.java new file mode 100644 index 0000000..a54be35 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/dnd/TreePathTransferable.java @@ -0,0 +1,74 @@ +/** + * ======================== legal notice ====================== + * + * File: TreePathTransferable.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.dnd; + + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.IOException; +import javax.swing.tree.TreePath; + + +public class TreePathTransferable implements Transferable { + public static final DataFlavor TreePathFlavor; + + + public TreePathTransferable(TreePath path) { + data = path; + } + + + @Override + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { + if (TreePathFlavor.equals(flavor)) + return data; + throw new UnsupportedFlavorException(flavor); + } + + + @Override + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { TreePathFlavor }; + } + + + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + return TreePathFlavor.equals(flavor); + } + + private TreePath data; + static { + DataFlavor tmp = null; + + try { + tmp = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + ";class=" + TreePath.class.getName()); + } catch (ClassNotFoundException e) { + } + TreePathFlavor = tmp; + } +} diff --git a/cmpcj/src/de/schwarzrot/control/dnd/TreeSourceAndDestTransferHandler.java b/cmpcj/src/de/schwarzrot/control/dnd/TreeSourceAndDestTransferHandler.java new file mode 100644 index 0000000..d9c3285 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/dnd/TreeSourceAndDestTransferHandler.java @@ -0,0 +1,207 @@ +/** + * ======================== legal notice ====================== + * + * File: TreeSourceAndDestTransferHandler.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.dnd; + + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.io.File; +import java.util.List; +import java.util.Map; +import javax.swing.JComponent; +import javax.swing.JTree; +import javax.swing.TransferHandler; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreePath; +import ca.odell.glazedlists.EventList; +import de.schwarzrot.media.domain.AbstractMediaNode; +import de.schwarzrot.media.domain.Genre; +import de.schwarzrot.media.domain.Media; + + +public class TreeSourceAndDestTransferHandler extends TransferHandler { + private static final long serialVersionUID = 713L; + + + public TreeSourceAndDestTransferHandler(JTree tree, Map<File, DefaultMutableTreeNode> cache, + EventList<AbstractMediaNode> changes) { + this.tree = tree; + nodeCache = cache; + this.changes = changes; + } + + + // dest + @Override + public boolean canImport(TransferHandler.TransferSupport support) { + if (!support.isDrop()) + return false; + support.setShowDropLocation(true); + + if (support.isDataFlavorSupported(TreePathTransferable.TreePathFlavor) && support.getDropAction() == MOVE) + return true; + if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) + return true; + + return false; + } + + + // source + @Override + public Transferable createTransferable(JComponent c) { + if (c != tree) + return null; + TreePath selectionPath = tree.getSelectionPath(); + + return new TreePathTransferable(selectionPath); + } + + + // source + @Override + public void exportDone(JComponent c, Transferable data, int action) { + tree.updateUI(); + } + + + // source + @Override + public int getSourceActions(JComponent c) { + return MOVE; + } + + + // dest + @Override + public boolean importData(TransferHandler.TransferSupport support) { + if (!canImport(support)) + return false; + JTree.DropLocation dl = (JTree.DropLocation) support.getDropLocation(); + TreePath targetPath = tree.getClosestPathForLocation(dl.getDropPoint().x, dl.getDropPoint().y); + DefaultMutableTreeNode targetNode = (DefaultMutableTreeNode) targetPath.getLastPathComponent(); + + if (support.isDataFlavorSupported(TreePathTransferable.TreePathFlavor)) { + // move a genre in tree + try { + TreePath sourcePath = (TreePath) support.getTransferable().getTransferData( + TreePathTransferable.TreePathFlavor); + DefaultMutableTreeNode transferNode = (DefaultMutableTreeNode) sourcePath.getLastPathComponent(); + DefaultMutableTreeNode sourceParentNode = (DefaultMutableTreeNode) transferNode.getParent(); + Genre target = (Genre) targetNode.getUserObject(); + Genre transfer = (Genre) transferNode.getUserObject(); + + // System.out.println("importData() targetPath: " + targetPath); + // System.out.println("importData() sourcePath: " + sourcePath); + + sourceParentNode.remove(transferNode); + targetNode.add(transferNode); + nodeCache.remove(transfer.getRealPath()); + // System.out.println("old path of genre to move: " + transfer.getRealPath().getAbsolutePath()); + transfer.setParent(target); + // System.out.println("new path of moved genre: " + transfer.getRealPath().getAbsolutePath()); + nodeCache.put(transfer.getRealPath(), transferNode); + transfer.update(); + refreshNodeCache(); + if (!changes.contains(transfer)) { + changes.getReadWriteLock().writeLock().lock(); + changes.add(transfer); + changes.getReadWriteLock().writeLock().unlock(); + } + } catch (Throwable t) { + t.printStackTrace(); + } + } else if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { + // move media files from one genre to another (no visible tree change) + try { + @SuppressWarnings("unchecked") + List<File> fileList = (List<File>) support.getTransferable().getTransferData( + DataFlavor.javaFileListFlavor); + + for (File f : fileList) + move2TargetNode(targetNode, f); // each media can have different parent, so don't optimize here + } catch (Throwable t) { + t.printStackTrace(); + } + } + return false; + } + + + protected void cacheNode(DefaultMutableTreeNode node) { + Genre g = (Genre) node.getUserObject(); + + nodeCache.put(g.getRealPath(), node); + for (int i = 0; i < node.getChildCount(); ++i) { + DefaultMutableTreeNode sub = (DefaultMutableTreeNode) node.getChildAt(i); + + cacheNode(sub); + } + } + + + protected void move2TargetNode(DefaultMutableTreeNode targetNode, File mediaPath) { + if (targetNode == null || mediaPath == null) + return; + Genre targetGenre = (Genre) targetNode.getUserObject(); + DefaultMutableTreeNode node = nodeCache.get(mediaPath.getParentFile()); + + if (targetGenre != null && node != null) { + Media transferMedia = null; + Genre sourceGenre = (Genre) node.getUserObject(); + + for (Media m : sourceGenre.getMediaList()) { + if (m.getRealPath().equals(mediaPath)) { + transferMedia = m; + break; + } + } + + if (transferMedia != null) { + System.out.println("old path of media to transfer: " + transferMedia.getRealPath().getAbsolutePath()); + transferMedia.setParent(targetGenre); + System.out.println("new path of transferred media: " + transferMedia.getRealPath().getAbsolutePath()); + if (!changes.contains(transferMedia)) { + changes.getReadWriteLock().writeLock().lock(); + changes.add(transferMedia); + changes.getReadWriteLock().writeLock().unlock(); + } + } + } + } + + + protected void refreshNodeCache() { + nodeCache.clear(); + DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getModel().getRoot(); + + cacheNode(node); + } + + private JTree tree; + private EventList<AbstractMediaNode> changes; + private Map<File, DefaultMutableTreeNode> nodeCache; +} diff --git a/cmpcj/src/de/schwarzrot/control/support/GenreSelector.java b/cmpcj/src/de/schwarzrot/control/support/GenreSelector.java new file mode 100644 index 0000000..9566ae8 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/support/GenreSelector.java @@ -0,0 +1,46 @@ +/** + * ======================== legal notice ====================== + * + * File: GenreSelector.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.support; + + +import ca.odell.glazedlists.matchers.Matcher; +import de.schwarzrot.media.domain.Genre; +import de.schwarzrot.media.domain.Media; + + +public class GenreSelector implements Matcher<Media> { + public GenreSelector(Genre genre) { + g = genre; + } + + + @Override + public boolean matches(Media m) { + return m.getRealPath().getAbsolutePath().startsWith(g.getRealPath().getAbsolutePath()); + } + + private Genre g; +}
\ No newline at end of file diff --git a/cmpcj/src/de/schwarzrot/control/support/MediaList2TypeList.java b/cmpcj/src/de/schwarzrot/control/support/MediaList2TypeList.java new file mode 100644 index 0000000..8445db8 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/support/MediaList2TypeList.java @@ -0,0 +1,61 @@ +/** + * ======================== legal notice ====================== + * + * File: MediaList2TypeList.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.support; + + +import ca.odell.glazedlists.EventList; +import ca.odell.glazedlists.TransformedList; +import ca.odell.glazedlists.event.ListEvent; +import de.schwarzrot.media.domain.AbstractMediaNode; +import de.schwarzrot.media.domain.Media; + + +public class MediaList2TypeList extends TransformedList<Media, AbstractMediaNode.SupportedMediaType> { + public MediaList2TypeList(EventList<Media> source) { + super(source); + source.addListEventListener(this); + } + + + @Override + public Media.SupportedMediaType get(int index) { + Media m = source.get(index); + + return m.getType(); + } + + + @Override + public void listChanged(ListEvent<Media> listChanges) { + updates.forwardEvent(listChanges); + } + + + @Override + protected boolean isWritable() { + return false; + } +} diff --git a/cmpcj/src/de/schwarzrot/control/support/MediaTextFilterator.java b/cmpcj/src/de/schwarzrot/control/support/MediaTextFilterator.java new file mode 100644 index 0000000..b36f582 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/support/MediaTextFilterator.java @@ -0,0 +1,41 @@ +/** + * ======================== legal notice ====================== + * + * File: MediaTextFilterator.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.support; + + +import java.util.List; +import ca.odell.glazedlists.TextFilterator; +import de.schwarzrot.media.domain.Media; + + +public class MediaTextFilterator implements TextFilterator<Media> { + @Override + public void getFilterStrings(List<String> baseList, Media m) { + baseList.add(m.getName()); + baseList.add(m.getRealPath().getAbsolutePath()); + baseList.add(m.getSearch()); + } +} diff --git a/cmpcj/src/de/schwarzrot/control/support/MediaTypeSelector.java b/cmpcj/src/de/schwarzrot/control/support/MediaTypeSelector.java new file mode 100644 index 0000000..f60ddc4 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/support/MediaTypeSelector.java @@ -0,0 +1,157 @@ +/** + * ======================== legal notice ====================== + * + * File: MediaTypeSelector.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.support; + + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.ListCellRenderer; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import ca.odell.glazedlists.EventList; +import ca.odell.glazedlists.UniqueList; +import ca.odell.glazedlists.matchers.AbstractMatcherEditor; +import ca.odell.glazedlists.matchers.Matcher; +import ca.odell.glazedlists.swing.DefaultEventListModel; +import ca.odell.glazedlists.swing.DefaultEventSelectionModel; +import de.schwarzrot.base.util.ApplicationServiceProvider; +import de.schwarzrot.base.util.ImageFactory; +import de.schwarzrot.media.domain.Media; + + +public class MediaTypeSelector extends AbstractMatcherEditor<Media> implements ListSelectionListener { + public class MediaTypeCellRenderer extends JLabel implements ListCellRenderer { + private static final long serialVersionUID = 713L; + + + public MediaTypeCellRenderer() { + loadImages(); + } + + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, + boolean cellHasFocus) { + ImageIcon icon = null; + + if (isSelected) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + icon = selImages[((Media.SupportedMediaType) value).ordinal()]; + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + icon = stdImages[((Media.SupportedMediaType) value).ordinal()]; + } + setSize(110, 110); + setHorizontalAlignment(JLabel.CENTER); + + if (icon != null) { + setIcon(icon); + setText(""); + } else { + setText(value.toString()); + } + return this; + } + + + protected void loadImages() { + ImageFactory imgFak = ApplicationServiceProvider.getService(ImageFactory.class); + int i = 0; + + stdImages = new ImageIcon[Media.SupportedMediaType.values().length]; + for (Media.SupportedMediaType smt : Media.SupportedMediaType.values()) { + StringBuilder sb = new StringBuilder(smt.getClass().getSimpleName()); + + sb.append(".").append(smt.name()).append(".default"); + stdImages[i++] = imgFak.getIcon(sb.toString(), 110, 110); + } + + i = 0; + selImages = new ImageIcon[Media.SupportedMediaType.values().length]; + for (Media.SupportedMediaType smt : Media.SupportedMediaType.values()) { + StringBuilder sb = new StringBuilder(smt.getClass().getSimpleName()); + + sb.append(".").append(smt.name()).append(".active"); + selImages[i++] = imgFak.getIcon(sb.toString(), 110, 110); + } + } + + ImageIcon[] stdImages; + ImageIcon[] selImages; + } + + + public MediaTypeSelector(EventList<Media> source) { + EventList<Media.SupportedMediaType> mediaTypeNonUnique = new MediaList2TypeList(source); + + mediaTypeList = new UniqueList<Media.SupportedMediaType>(mediaTypeNonUnique); + DefaultEventListModel<Media.SupportedMediaType> mediaTypeListModel = new DefaultEventListModel<Media.SupportedMediaType>( + mediaTypeList); + + mediaTypeJList = new JList(mediaTypeListModel); + DefaultEventSelectionModel<Media.SupportedMediaType> mediaTypeSelectionModel = new DefaultEventSelectionModel<Media.SupportedMediaType>( + mediaTypeList); + + mediaTypeJList.setSelectionModel(mediaTypeSelectionModel); + selectedTypes = mediaTypeSelectionModel.getSelected(); + mediaTypeJList.addListSelectionListener(this); + mediaTypeJList.setCellRenderer(new MediaTypeCellRenderer()); + mediaTypeJList.setBackground(Color.BLACK); + mediaTypeJList.setMinimumSize(new Dimension(100, 100)); + mediaTypeComponent = new JScrollPane(mediaTypeJList); + } + + + public JComponent getComponent() { + return mediaTypeComponent; + } + + + public JList getJList() { + return mediaTypeJList; + } + + + @Override + public void valueChanged(ListSelectionEvent e) { + Matcher<Media> newMatcher = new MediatypeMatcher(selectedTypes); + + fireChanged(newMatcher); + } + + private EventList<Media.SupportedMediaType> mediaTypeList; + private EventList<Media.SupportedMediaType> selectedTypes; + private JList mediaTypeJList; + private JScrollPane mediaTypeComponent; +} diff --git a/cmpcj/src/de/schwarzrot/control/support/MediatypeMatcher.java b/cmpcj/src/de/schwarzrot/control/support/MediatypeMatcher.java new file mode 100644 index 0000000..a01b43a --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/support/MediatypeMatcher.java @@ -0,0 +1,55 @@ +/** + * ======================== legal notice ====================== + * + * File: MediatypeMatcher.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.support; + + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import ca.odell.glazedlists.matchers.Matcher; +import de.schwarzrot.media.domain.AbstractMediaNode; +import de.schwarzrot.media.domain.Media; + + +public class MediatypeMatcher implements Matcher<Media> { + public MediatypeMatcher(Collection<AbstractMediaNode.SupportedMediaType> mediaTypes) { + this.mediaTypes.addAll(mediaTypes); + } + + + @Override + public boolean matches(Media m) { + if (m == null) + return false; + if (mediaTypes.isEmpty()) + return true; + Media.SupportedMediaType mt = m.getType(); + + return mediaTypes.contains(mt); + } + + private Set<AbstractMediaNode.SupportedMediaType> mediaTypes = new HashSet<Media.SupportedMediaType>(); +} diff --git a/cmpcj/src/de/schwarzrot/control/support/SelectedMedia.java b/cmpcj/src/de/schwarzrot/control/support/SelectedMedia.java new file mode 100644 index 0000000..efde378 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/support/SelectedMedia.java @@ -0,0 +1,85 @@ +/** + * ======================== legal notice ====================== + * + * File: SelectedMedia.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.support; + + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import ca.odell.glazedlists.EventList; +import ca.odell.glazedlists.swing.DefaultEventSelectionModel; +import de.schwarzrot.media.domain.Media; + + +public class SelectedMedia implements ListSelectionListener { + public static final String MEDIA_PROPERTY = "media"; + + + public SelectedMedia(EventList<Media> source) { + pcs = new PropertyChangeSupport(this); + mediaList = source; + } + + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + + public void clear() { + pcs.firePropertyChange(MEDIA_PROPERTY, this.media, this.media = null); + } + + + public Media getMedia() { + return media; + } + + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + + @Override + public void valueChanged(ListSelectionEvent e) { + if (e.getValueIsAdjusting()) + return; + if (e.getSource() instanceof DefaultEventSelectionModel) { + @SuppressWarnings("unchecked") + DefaultEventSelectionModel<Media> sm = (DefaultEventSelectionModel<Media>) e.getSource(); + + if (sm.isSelectionEmpty()) + return; + pcs.firePropertyChange(MEDIA_PROPERTY, this.media, this.media = mediaList.get(sm.getLeadSelectionIndex())); + } + } + + private Media media; + private PropertyChangeSupport pcs; + private EventList<Media> mediaList; +} diff --git a/cmpcj/src/de/schwarzrot/control/support/TreeSelectionFilter.java b/cmpcj/src/de/schwarzrot/control/support/TreeSelectionFilter.java new file mode 100644 index 0000000..99d1646 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/support/TreeSelectionFilter.java @@ -0,0 +1,59 @@ +/** + * ======================== legal notice ====================== + * + * File: TreeSelectionFilter.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.support; + + +import javax.swing.JTree; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import ca.odell.glazedlists.matchers.AbstractMatcherEditor; +import ca.odell.glazedlists.matchers.Matcher; +import de.schwarzrot.media.domain.Genre; +import de.schwarzrot.media.domain.Media; + + +public class TreeSelectionFilter extends AbstractMatcherEditor<Media> implements TreeSelectionListener { + public TreeSelectionFilter(JTree tree) { + this.tree = tree; + tree.addTreeSelectionListener(this); + } + + + @Override + public void valueChanged(TreeSelectionEvent e) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); + + if (node == null) + return; + Genre g = (Genre) node.getUserObject(); + Matcher<Media> newMatcher = new GenreSelector(g); + + fireChanged(newMatcher); + } + + private JTree tree; +} diff --git a/cmpcj/src/de/schwarzrot/control/table/MediaTableFormat.java b/cmpcj/src/de/schwarzrot/control/table/MediaTableFormat.java new file mode 100644 index 0000000..88bdea1 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/table/MediaTableFormat.java @@ -0,0 +1,91 @@ +/** + * ======================== legal notice ====================== + * + * File: MediaTableFormat.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.table; + + +import ca.odell.glazedlists.gui.TableFormat; +import de.schwarzrot.base.util.ApplicationServiceProvider; +import de.schwarzrot.base.util.MessageBundle; +import de.schwarzrot.control.app.CMPMessageBundle; +import de.schwarzrot.media.domain.Media; + + +public class MediaTableFormat implements TableFormat<Media> { + private static MessageBundle bundle; + + + @Override + public int getColumnCount() { + return 3; + } + + + @Override + public String getColumnName(int column) { + if (bundle == null) + bundle = ApplicationServiceProvider.getService(MessageBundle.class); + + switch (column) { + case 0: + return bundle.getMessage(CMPMessageBundle.MTF_0); + case 1: + return bundle.getMessage(CMPMessageBundle.MTF_1); + case 2: + return bundle.getMessage(CMPMessageBundle.MTF_2); + default: + throw new IndexOutOfBoundsException(); + } + } + + + @Override + public Object getColumnValue(Media m, int column) { + switch (column) { + case 0: + return m.getType(); + case 1: + return m.getFormat(); + case 2: + return m.getName(); + default: + throw new IndexOutOfBoundsException(); + } + } + + + public int getColumnWidth(int column) { + switch (column) { + case 0: + return 80; + case 1: + return 110; + case 2: + return -1; + default: + throw new IndexOutOfBoundsException(); + } + } +} diff --git a/cmpcj/src/de/schwarzrot/control/table/PlayerDefinitionTableFormat.java b/cmpcj/src/de/schwarzrot/control/table/PlayerDefinitionTableFormat.java new file mode 100644 index 0000000..cadc6d7 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/table/PlayerDefinitionTableFormat.java @@ -0,0 +1,114 @@ +/** + * ======================== legal notice ====================== + * + * File: PlayerDefinitionTableFormat.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.table; + + +import ca.odell.glazedlists.gui.WritableTableFormat; +import de.schwarzrot.base.util.ApplicationServiceProvider; +import de.schwarzrot.base.util.MessageBundle; +import de.schwarzrot.media.domain.PlayerDefinition; + + +public class PlayerDefinitionTableFormat implements WritableTableFormat<PlayerDefinition> { + private static MessageBundle bundle; + protected static final String KEY_0 = PlayerDefinitionTableFormat.class.getSimpleName() + ".col0"; + protected static final String KEY_1 = PlayerDefinitionTableFormat.class.getSimpleName() + ".col1"; + + + @Override + public int getColumnCount() { + return 2; + } + + + @Override + public String getColumnName(int column) { + if (bundle == null) + bundle = ApplicationServiceProvider.getService(MessageBundle.class); + + switch (column) { + case 0: + return bundle.getMessage(KEY_0); + case 1: + return bundle.getMessage(KEY_1); + default: + throw new IndexOutOfBoundsException(); + } + } + + + @Override + public Object getColumnValue(PlayerDefinition pd, int column) { + switch (column) { + case 0: + return pd.getMediaType().name(); + case 1: + return pd.getCommandLine(); + default: + throw new IndexOutOfBoundsException(); + } + } + + + public int getColumnWidth(int column) { + switch (column) { + case 0: + return 150; + case 1: + return -1; + default: + throw new IndexOutOfBoundsException(); + } + } + + + @Override + public boolean isEditable(PlayerDefinition pd, int column) { + switch (column) { + case 0: + return false; + case 1: + return true; + default: + throw new IndexOutOfBoundsException(); + } + } + + + @Override + public PlayerDefinition setColumnValue(PlayerDefinition pd, Object value, int column) { + switch (column) { + case 0: + break; + case 1: + pd.setCommandLine(value.toString()); + break; + default: + throw new IndexOutOfBoundsException(); + } + return pd; + } +} diff --git a/cmpcj/src/de/schwarzrot/control/table/ServerDefinitionTableFormat.java b/cmpcj/src/de/schwarzrot/control/table/ServerDefinitionTableFormat.java new file mode 100644 index 0000000..2e4c630 --- /dev/null +++ b/cmpcj/src/de/schwarzrot/control/table/ServerDefinitionTableFormat.java @@ -0,0 +1,119 @@ +/** + * ======================== legal notice ====================== + * + * File: ServerDefinitionTableFormat.java + * Created: 13. June 2012, 04:57 + * Author: <a href="mailto:geronimo013@gmx.de">Geronimo</a> + * Project: cmpc - a java frontend (client) part of compound media player + * uses external players to play the media + * + * CMP - compound media player + * + * is a client/server mediaplayer intended to play any media from any workstation + * without the need to export or mount shares. cmps is an easy to use backend + * with a (ready to use) HTML-interface. Additionally the backend supports + * authentication via HTTP-digest authorization. + * cmpc is a client with vdr-like osd-menues. + * + * Copyright (c) 2012 Reinhard Mantey, some rights reserved! + * published under Creative Commons by-sa + * For details see http://creativecommons.org/licenses/by-sa/3.0/ + * + * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp + * + * -------------------------------------------------------------- + */ +package de.schwarzrot.control.table; + + +import ca.odell.glazedlists.gui.WritableTableFormat; +import de.schwarzrot.base.util.ApplicationServiceProvider; +import de.schwarzrot.base.util.MessageBundle; +import de.schwarzrot.media.domain.MediaServer; + + +public class ServerDefinitionTableFormat implements WritableTableFormat<MediaServer> { + private static MessageBundle bundle; + protected static final String KEY_0 = ServerDefinitionTableFormat.class.getSimpleName() + ".col0"; + protected static final String KEY_1 = ServerDefinitionTableFormat.class.getSimpleName() + ".col1"; + + + @Override + public int getColumnCount() { + return 2; + } + + + @Override + public String getColumnName(int column) { + if (bundle == null) + bundle = ApplicationServiceProvider.getService(MessageBundle.class); + + switch (column) { + case 0: + return bundle.getMessage(KEY_0); + case 1: + return bundle.getMessage(KEY_1); + default: + throw new IndexOutOfBoundsException(); + } + } + + + @Override + public Object getColumnValue(MediaServer sd, int column) { + switch (column) { + case 0: + return sd.getHostName(); + case 1: + return sd.getPort(); + default: + throw new IndexOutOfBoundsException(); + } + } + + + public int getColumnWidth(int column) { + switch (column) { + case 0: + return -1; + case 1: + return 80; + default: + throw new IndexOutOfBoundsException(); + } + } + + + @Override + public boolean isEditable(MediaServer sd, int column) { + switch (column) { + case 0: + case 1: + return true; + default: + throw new IndexOutOfBoundsException(); + } + } + + + @Override + public MediaServer setColumnValue(MediaServer sd, Object value, int column) { + switch (column) { + case 0: + sd.setHostName(value.toString()); + break; + + case 1: + try { + sd.setPort(Integer.decode(value.toString())); + } catch (Throwable t) { + } + break; + + default: + throw new IndexOutOfBoundsException(); + } + return sd; + } +} |