/* Copyright (C) 2006 Christian Schneider * * This file is part of Nomad. * * Nomad 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 2 of the License, or * (at your option) any later version. * * Nomad 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 Nomad; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package net.sf.nmedit.jsynth.nomad.forms; import java.awt.AWTEvent; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.ComponentOrientation; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.Toolkit; import java.awt.datatransfer.DataFlavor; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.JToggleButton; import javax.swing.SwingUtilities; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import net.sf.nmedit.jsynth.Bank; import net.sf.nmedit.jsynth.Port; import net.sf.nmedit.jsynth.Slot; import net.sf.nmedit.jsynth.SynthException; import net.sf.nmedit.jsynth.Synthesizer; import net.sf.nmedit.jsynth.event.BankUpdateEvent; import net.sf.nmedit.jsynth.event.BankUpdateListener; import net.sf.nmedit.jsynth.event.ComStatusEvent; import net.sf.nmedit.jsynth.event.ComStatusListener; import net.sf.nmedit.jsynth.event.SlotEvent; import net.sf.nmedit.jsynth.event.SlotListener; import net.sf.nmedit.jsynth.event.SynthesizerEvent; import net.sf.nmedit.jsynth.event.SynthesizerStateListener; import net.sf.nmedit.jsynth.nomad.SimpleTextFilter; import net.sf.nmedit.jsynth.worker.PatchLocation; import net.sf.nmedit.jsynth.worker.StorePatchWorker; import net.sf.nmedit.nmutils.Platform; import net.sf.nmedit.nomad.core.Nomad; import net.sf.nmedit.nomad.core.forms.ExceptionDialog; import net.sf.nmedit.nomad.core.swing.Factory; import net.sf.nmedit.nomad.core.swing.JDropDownButtonControl; import net.sf.nmedit.nomad.core.swing.SelectedAction; import net.sf.nmedit.nomad.core.swing.explorer.ContainerNode; import net.sf.nmedit.nomad.core.swing.explorer.ExplorerTree; import net.sf.nmedit.nomad.core.swing.explorer.LeafNode; import net.sf.nmedit.nomad.core.swing.explorer.RootNode; public class SynthObjectForm<S extends Synthesizer> extends JPanel { /** * */ private static final long serialVersionUID = 9030717642000065819L; private S synth; private List<SlotObject<S>> slotObjects = new ArrayList<SlotObject<S>>(); public SynthObjectForm(S synth) { this.synth = synth; create(); (createEventHandler()).install(); } protected EventHandler createEventHandler() { return new EventHandler(); } protected class EventHandler implements SynthesizerStateListener, PropertyChangeListener, ComStatusListener { public void install() { synth.addSynthesizerStateListener(this); synth.addPropertyChangeListener(this); synth.addComStatusListener(this); } public void synthConnectionStateChanged(SynthesizerEvent e) { connectionStateChanged(synth.isConnected()); } public void propertyChange(PropertyChangeEvent evt) { if ("icon".equals(evt.getPropertyName())) { Icon icon = (Icon) evt.getNewValue(); setSynthIcon(icon); } else if (Synthesizer.PROPERTY_NAME.equals(evt.getPropertyName())) { setSynthName((String)evt.getNewValue()); } else if (Synthesizer.DSP_GLOBAL.equals(evt.getPropertyName())) { updateDSPUsageGlobalLabel(); } } public void comStatusChanged(ComStatusEvent e) { updateSynthStatusLabel(); } } /* protected void processEvent(Event event, TreePath path, TreeNode node) { if (node instanceof SlotLeaf && slotsRoot.contains(node)) { SlotLeaf s = (SlotLeaf) node; processEvent(event, s.getSlot()); } else if (node instanceof LeafNode && banksRoot.contains(node.getParent())) { Bank<? extends Synthesizer> b = ((BankLeaf)node.getParent()).bank; processEvent(event, b, node.getParent().getIndex(node)); } }*/ protected void bankPatchLoadEvent( Bank<S> bank, int index) { // no op List<Synthesizer> list = new LinkedList<Synthesizer>(); Synthesizer synth = bank.getSynthesizer(); Slot dst = null; list.add(synth); if (!bank.containsPatch(index)) { // no patch => nothing to open return; } if (synth.getSlotCount() > 1) { SaveInSynthDialog ssd = new SaveInSynthDialog(list); ssd.setTitle("Open Patch..."); ssd.setSaveInBankAllowed(false); ssd.invoke(); if (!ssd.isSaveOption()) return; dst = ssd.getSelectedSlot(); } else { dst = synth.getSlot(0); } if (dst == null) return; StorePatchWorker w = synth.createStorePatchWorker(); w.setSource(new PatchLocation(bank.getBankIndex(), index)); w.setDestination(new PatchLocation(dst.getSlotIndex())); try { w.store(); } catch (SynthException e) { e.printStackTrace(); } } protected void connectionStateChanged(boolean connected) { if (connected) { if (synth.getSlotCount()>0) createSlotComponents(); installBanks(); } else { uninstallBanks(); removeSlotComponents(); } tbConnect.setSelected(connected); } protected void createSlotComponents() { synchronized (slotContainer.getTreeLock()) { for (int s = 0; s<synth.getSlotCount(); s++) { SlotObject<S> si = createSlotObject(synth.getSlot(s)); slotContainer.add(si.root); slotContainer.add(Box.createVerticalStrut(2)); slotObjects.add(si); } slotContainer.add(Box.createVerticalStrut(10)); } revalidate(); repaint(); } protected void removeSlotComponents() { synchronized (slotContainer.getTreeLock()) { for (SlotObject so: slotObjects) { so.uninstall(); } slotObjects.clear(); slotContainer.removeAll(); } revalidate(); repaint(); } public void setSynthName(String name) { if (name == null) name = synth.getDeviceName(); synthNameLabel.setText(name); // TODO set tab bar title } public void setSynthIcon(Icon icon) { icon = ensureIsSmallIcon(icon); synthIconLabel.setIcon(icon); if (icon != null) { int w = icon.getIconWidth(); int h = icon.getIconHeight(); synthIconLabel.setPreferredSize(new Dimension(w, h)); synthIconLabel.setMaximumSize(new Dimension(w, h)); synthIconLabel.setVisible(true); } else { synthIconLabel.setVisible(false); } revalidate(); repaint(); } public S getSynthesizer() { return synth; } private static ImageIcon getIcon(String name) { name = "/icons/tango/16x16/"+name; URL url = Nomad.sharedInstance().getClass().getResource(name); if (url == null) return null; return new ImageIcon(url); } private void installBanks() { RootNode banksRoot = banksTree.getRoot(); banksRoot.removeAllChildren(); for (int i=0;i<synth.getBankCount();i++) { banksRoot.add(new BankLeaf(banksRoot, synth.getBank(i))); } banksTree.fireRootChanged(); } private void setBanksFilter(String filter) { RootNode root = banksTree.getRoot(); for (int i=0;i<root.getChildCount();i++) { TreeNode tn = root.getChildAt(i); if (BankLeaf.class.isInstance(tn)) { ((BankLeaf)tn).setFilter(filter); } } for (int i=0;i<root.getChildCount();i++) { TreeNode tn = root.getChildAt(i); if (BankLeaf.class.isInstance(tn)) { ((BankLeaf)tn).regenerate(); } } } private void uninstallBanks() { RootNode banksRoot = banksTree.getRoot(); for (int i=0;i<banksRoot.getChildCount();i++) { BankLeaf l = (BankLeaf) banksRoot.getChildAt(i); l.uninstall(); } banksRoot.removeAllChildren(); banksTree.fireRootChanged(); } private class BankPosition extends LeafNode { private int position; public BankPosition(BankLeaf bankNode, String text, int position) { super(bankNode, text); this.position = position; } } private class BankLeaf extends ContainerNode implements BankUpdateListener { private Bank<S> bank; private boolean dropped = true; private SimpleTextFilter nameFilter = new SimpleTextFilter(); public BankLeaf(TreeNode parent, Bank<S> bank) { super(parent, bank.getName()); this.bank = bank; bank.addBankUpdateListener(this); regenerate(); } public void setFilter(String filter) { nameFilter.setFilter(filter); if (nameFilter.isFiltering()) { // ensure that all patches are loaded for (int i=0;i<bank.getPatchCount();i++) { if (!bank.isPatchInfoAvailable(i)) { bank.update(i, bank.getPatchCount()); return; } } // all patches available } } private void regenerate() { if (!synth.isConnected()) { this.clear(); banksTree.fireNodeStructureChanged(this); return; } this.clear(); int firstEmptyIndex = -1; for (int i=0;i<bank.getPatchCount();i++) { if (bank.isPatchInfoAvailable(i)) { if (bank.containsPatch(i)) { String patchname = bank.getPatchName(i); String name = bank.getPatchLocationName(i) +": "+ patchname; if (nameFilter.contains(patchname)) addChild(new BankPosition(this, name, i)); } else { if (firstEmptyIndex<0) firstEmptyIndex = i; } } } if (dropped) { // fake node if (getChildCount()==0) addChild(0, new BankPosition(this, "", firstEmptyIndex /* -1 is ok */)); } else { if (firstEmptyIndex>=0) { String name = "<empty>"; if (nameFilter.contains(name)) addChild(0, new BankPosition(this, name, firstEmptyIndex)); } } banksTree.fireNodeStructureChanged(this); } public boolean getAllowsChildren() { return true; } public TreeNode getChildAt(int index) { ensureBankLoaded(); return super.getChildAt(index); } private void ensureBankLoaded() { if (!dropped) return; if (synth.isConnected()) { dropped = false; bank.update(); } } public boolean isLeaf() { return bank.getPatchCount()==0; } public void notifyDropChildren() { dropped = true; super.notifyDropChildren(); } public void uninstall() { bank.removeBankUpdateListener(this); } public void bankUpdated(BankUpdateEvent e) { // System.out.println("update bank start " + Thread.currentThread()); // Throwable ex = new Throwable(); // ex.printStackTrace(); if (dropped) return; SwingUtilities.invokeLater(new Runnable(){public void run(){ regenerate(); }}); /* for (int i=e.getBeginIndex();i<e.getEndIndex();i++) { LeafNode l = (LeafNode) getChildAt(i); String name; if (!bank.isPatchInfoAvailable(i)) name = "?"; else if (!bank.containsPatch(i)) name = "<empty>"; else name = bank.getPatchName(i); l.setText(name); } */ // System.out.println("update bank stop " + Thread.currentThread()); } } static ImageIcon icfolder = getIcon("places/folder.png"); static ImageIcon icfolderopen = getIcon("status/folder-open.png"); static ImageIcon icfolderDragAccept = getIcon("status/folder-drag-accept.png"); static ImageIcon icstart = getIcon("actions/media-playback-start.png"); static ImageIcon icstop = getIcon("actions/media-playback-stop.png"); static ImageIcon icsystem = getIcon("actions/document-properties.png"); // TODO find a good connect/disconnected icon static ImageIcon icconnected = getIcon("categories/applications-other.png"); static ImageIcon icdisconnected = icconnected; static ImageIcon icComIdle = getIcon("status/network-idle.png"); static ImageIcon icComOffline = getIcon("status/network-offline.png"); static ImageIcon icComError = getIcon("status/network-error.png"); static ImageIcon icComReceive = getIcon("status/network-receive.png"); static ImageIcon icComTransmit = getIcon("status/network-transmit.png"); static ImageIcon icComTransmitReceive = getIcon("status/network-transmit-receive.png"); static ImageIcon icAppOther = getIcon("categories/applications-other.png"); private JLabel synthStatusLabel; private JLabel synthIconLabel; private JLabel synthNameLabel; private JComponent slotContainer; private JToggleButton tbConnect; private ExplorerTree banksTree; private JLabel dspUsageGlobal = null; private void updateDSPUsageGlobalLabel() { if (dspUsageGlobal != null) dspUsageGlobal.setText("DSP: "+getDSPPercentage()); } private String getDSPPercentage() { int idsp = (int)(synth.getDoubleProperty(Synthesizer.DSP_GLOBAL)*10000); double ddsp = ((double)idsp)/100; return ddsp+"%"; } public JComponent create() { JPanel synthpane = this; synthpane.setLayout(new BoxLayout(synthpane, BoxLayout.Y_AXIS)); synthpane.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); synthpane.setBorder(BorderFactory.createEmptyBorder(2,4,2,4)); // create components Icon icon = (Icon) synth.getClientProperty("icon"); synthIconLabel = new JLabel(); setSynthIcon(ensureIsSmallIcon(icon)); synthNameLabel = new JLabel(synth.getName()); synthStatusLabel = new JLabel(); updateSynthStatusLabel(); JButton btnSystem = new JButton(icsystem); JLabel lblBanks = new JLabel(); lblBanks.setText("Banks"); lblBanks.setIcon(icfolder); tbConnect = new JToggleButton(icdisconnected); tbConnect.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { final boolean tbDoConnect = tbConnect.isSelected(); SwingUtilities.invokeLater(new Runnable() { public void run() { trySetConnectedState(tbDoConnect); } } ); }}); btnSystem.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { SynthObjectForm.this.showSettings(); } }); final JTextField filter = new JTextField("*"); filter.setMaximumSize(new Dimension(Short.MAX_VALUE, 30)); filter.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { setBanksFilter(filter.getText()); } }); banksTree = new ExplorerTree(); banksTree.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { if (!Platform.isFlavor(Platform.OS.MacOSFlavor)) handleDblClick(e); } public void mouseReleased(MouseEvent e) { if (Platform.isFlavor(Platform.OS.MacOSFlavor)) handleDblClick(e); } public void handleDblClick(MouseEvent e) { if (e.getClickCount()!=2) return; TreePath path = banksTree.getClosestPathForLocation(e.getX(), e.getY()); if (path == null) return; Object node = path.getLastPathComponent(); if (!BankPosition.class.isInstance(node)) return; BankPosition leaf = (BankPosition) node; BankLeaf bl = (BankLeaf)leaf.getParent(); bankPatchLoadEvent(bl.bank, leaf.position); } }); JScrollPane spBanksTree = new JScrollPane(banksTree); // layout components /* PropertiesMain: * * +------------+------------------+ * | ^ | ^ | * | | | | | * | SynIconBox | <- SynPropBox -> | * | | | | | * | ^ | ^ | * |------------+------------------+ * */ Box PropertiesMain = Box.createHorizontalBox(); Box SynIconBox = top(left(Box.createVerticalBox())); Box SynPropBox = top(left(Box.createVerticalBox())); PropertiesMain.add(SynIconBox); PropertiesMain.add(hgap()); PropertiesMain.add(SynPropBox); // add syn icon label SynIconBox.add(top(left(synthIconLabel))); SynIconBox.add(vgap()); //SynIconBox.add(Box.createVerticalGlue()); { /* SynPropBox : * +-----------------------------------------------------------------+ * | SynthNameLabel <---------[SynTitleBox]------> SynthStatusIcon | * |-----------------------------------------------------------------+ * | ... dsp, other properties ... | * |-----------------------------------------------------------------+ * | <--- [SynActionBox] ---> | Properties | Disconnect | * |-----------------------------------------------------------------+ */ Box SynTitleBox = top(left(Box.createHorizontalBox())); SynTitleBox.add(top(left(synthNameLabel))); SynTitleBox.add(hgap()); SynTitleBox.add(Box.createHorizontalGlue()); SynTitleBox.add(top(right(synthStatusLabel))); Box SynActionBox = top(left(Box.createHorizontalBox())); SynActionBox.add(Box.createHorizontalGlue()); Collection<Action> SpecialActions = getSpecialActions(); if (!SpecialActions.isEmpty()) { SynActionBox.add(hgap()); SynActionBox.add(createSpecialActionsComponent(SpecialActions)); } SynActionBox.add(hgap()); SynActionBox.add(btnSystem); SynActionBox.add(hgap()); SynActionBox.add(tbConnect); SynPropBox.add(SynTitleBox); SynPropBox.add(vgap()); SynPropBox.add(SynActionBox); /* TODO support for other properties if (synth.hasProperty(Synthesizer.DSP_GLOBAL)) { dspUsageGlobal = new JLabel(); updateDSPUsageGlobalLabel(); propertyBox.add(dspUsageGlobal); }*/ } /* * synthpane: * +---------------------------+ * | <-- PropertiesMain --> | * +---------------------------+ * | ^ | * | | | * | [vglue] | * | | | * | ^ | * +---------------------------+ * | Slot | * +---------------------------+ * | Banks | * +---------------------------+ */ synthpane.add(top(left(PropertiesMain))); synthpane.add(vgap()); // Slot slotContainer = top(left(Box.createVerticalBox())); synthpane.add(slotContainer); synthpane.add(vgap()); // Bank Box BanksExtra = Box.createHorizontalBox(); BanksExtra.add(lblBanks); BanksExtra.add(hgap()); BanksExtra.add(filter); synthpane.add(top(left(BanksExtra))); synthpane.add(vgap()); synthpane.add(top(left(spBanksTree))); spBanksTree.setMaximumSize(null); spBanksTree.setPreferredSize(null); // ... layout complete! return synthpane; } private JComponent createSpecialActionsComponent(Collection<Action> specialActions) { SelectedAction sa = new SelectedAction(); sa.putValue(AbstractAction.SMALL_ICON, icAppOther); JPopupMenu pop = new JPopupMenu(); JRadioButtonMenuItem rfirst = null; for (Action a: specialActions) { JRadioButtonMenuItem rb = new JRadioButtonMenuItem(a); if (rfirst == null) rfirst = rb; sa.add(rb); pop.add(rb); } JButton btn = Factory.createToolBarButton(sa); new JDropDownButtonControl(btn, pop); return btn; } protected Collection<Action> getSpecialActions() { return Collections.emptyList(); } final int GAP = 2; private Component hgap() { return Box.createRigidArea(new Dimension(GAP,0)); } private Component vgap() { return Box.createRigidArea(new Dimension(0, GAP)); } private static <T extends JComponent> T left(T c) { c.setAlignmentX(JComponent.LEFT_ALIGNMENT); return c; } private static <T extends JComponent> T right(T c) { c.setAlignmentX(JComponent.RIGHT_ALIGNMENT); return c; } private static <T extends JComponent> T top(T c) { c.setAlignmentY(JComponent.TOP_ALIGNMENT); return c; } private Icon ensureIsSmallIcon(Icon icon) { final int SZ = 64; final float SZf = (float) SZ; BufferedImage b = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = b.createGraphics(); try { icon.paintIcon(this, g2, 0, 0); } finally { g2.dispose(); g2 = null; } // aspect ratio float wf = b.getWidth()/SZf; float hf = b.getHeight()/SZf; float maxf = Math.max(wf, hf); int nw = (int) Math.floor(b.getWidth()/maxf); int nh = (int) Math.floor(b.getHeight()/maxf); BufferedImage nb = new BufferedImage(nw, nh, BufferedImage.TYPE_INT_ARGB); g2 = nb.createGraphics(); try { g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2.drawImage(b, 0, 0, nw, nh, 0, 0, b.getWidth(), b.getHeight(), null); } finally { g2.dispose(); g2 = null; } return new ImageIcon(nb); } private void updateSynthStatusLabel() { switch (synth.getComStatus()) { case Idle: synthStatusLabel.setIcon(icComIdle); break; case Offline: synthStatusLabel.setIcon(icComOffline); break; case Error: synthStatusLabel.setIcon(icComError); break; case Receive: synthStatusLabel.setIcon(icComReceive); break; case Transmit: synthStatusLabel.setIcon(icComTransmit); break; case TransmitReceive: synthStatusLabel.setIcon(icComTransmitReceive); break; } } protected static class ClickableLabel extends JLabel { /** * */ private static final long serialVersionUID = -6967218815458151086L; public static final String CLICK = "click"; private boolean clickAble; private Color defaultForeground; private static final Color CLICKABLE_COLOR = Color.decode("#00286E"); private static final Color HOVERED_COLOR = CLICKABLE_COLOR.brighter().brighter(); private ActionListener l; public ClickableLabel(ActionListener l) { this.l = l; defaultForeground = getForeground(); enableEvents(AWTEvent.MOUSE_EVENT_MASK); setClickable(true); setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } protected void processMouseEvent(MouseEvent e) { if (e.getID() == MouseEvent.MOUSE_CLICKED && Platform.isLeftMouseButtonOnly(e)) { // click l.actionPerformed(new ActionEvent(this, 0, CLICK)); } else if (e.getID() == MouseEvent.MOUSE_ENTERED) { if (clickAble) setForeground(HOVERED_COLOR); } else if (e.getID() == MouseEvent.MOUSE_EXITED) { if (clickAble) setForeground(CLICKABLE_COLOR); } super.processMouseEvent(e); } public void setClickable(boolean enabled) { this.clickAble = enabled; if (clickAble) { setForeground(CLICKABLE_COLOR); } else { setForeground(defaultForeground); } } } protected void trySetConnectedState(boolean connect) { boolean no = false; if (connect && (!arePlugsConfigured())) { no = showSettings(); } if (no || (!arePlugsConfigured())) { tbConnect.setSelected(false); return; } try { synth.setConnected(connect); } catch (SynthException e) { tbConnect.setSelected(false); ExceptionDialog.showErrorDialog( Nomad.sharedInstance().getWindow().getRootPane(), e.getMessage(), "Connect/Disconnect", e); // TODO log error } } protected void addForms(SynthPropertiesDialog<S> spd) { spd.addSynthInfo(); spd.addPortSettings(); spd.addSynthSettings(); } protected SlotObject<S> createSlotObject(Slot slot) { return new SlotObject<S>(this, slot); } protected static class SlotObject<S extends Synthesizer> implements SlotListener, ActionListener, PropertyChangeListener, DropTargetListener { JComponent root; private Slot slot; private ClickableLabel lblSlotPatchName; private SynthObjectForm<S> form; private JToggleButton tbToggleSlotEnabledState; private DropTarget dt; public SlotObject(SynthObjectForm<S> form, Slot slot) { this.form = form; this.slot = slot; createRootComponent(); install(); } protected SynthObjectForm<S> getForm() { return form; } protected void install() { slot.addSlotListener(this); slot.addPropertyChangeListener(this); } public void uninstall() { slot.removePropertyChangeListener(this); slot.removeSlotListener(this); } public Slot getSlot() { return slot; } public void createRootComponent() { // slot box 1 Box slotBox = Box.createHorizontalBox(); this.dt = new DropTarget(slotBox, this); left(top(slotBox)); lblSlotPatchName = left(new ClickableLabel(this)); updateSlotPatchName(); slotBox.add(lblSlotPatchName); slotBox.add(Box.createHorizontalGlue()); if (slot.isPropertyModifiable(Slot.ENABLED_PROPERTY)) { JToggleButton tb = new JToggleButton(); right(tb); tb.setToolTipText("Enable/Disable Slot"); /* tb.setOpaque(false);*/ tb.setBorder(BorderFactory.createEmptyBorder(1,1,1,1)); tb.setBorderPainted(false); tbToggleSlotEnabledState = tb; tb.setSelected(slot.isEnabled()); tb.setIcon(slot.isEnabled()?icstop:icstart); tb.setActionCommand(Slot.ENABLED_PROPERTY); tb.addActionListener(this); slotBox.add(tb); } root = slotBox; } public void newPatchInSlot(SlotEvent e) { updateSlotPatchName(); } private void updateSlotPatchName() { String name = slot.getPatchName(); if (name == null) name = ""; name = "<html><body>"+slot.getName()+" : <u>"+name+"</u>"; if (slot.isSelected()) { name += " *"; lblSlotPatchName.setIcon(icfolderopen); } else { lblSlotPatchName.setIcon(icfolder); } name += "</body></html>"; lblSlotPatchName.setText(name); } public void actionPerformed(ActionEvent e) { if (Slot.ENABLED_PROPERTY.equals(e.getActionCommand())) { // received from toggle button tbToggleSlotEnabledState.setIcon(tbToggleSlotEnabledState.isSelected()?icstop:icstart); slot.setEnabled(tbToggleSlotEnabledState.isSelected()); } else if (ClickableLabel.CLICK.equals(e.getActionCommand())) { slot.setSelected(true); updateSlotPatchName(); } } public void propertyChange(PropertyChangeEvent evt) { if (Slot.ENABLED_PROPERTY.equals(evt.getPropertyName())) { // received from slot tbToggleSlotEnabledState.setIcon(slot.isEnabled()?icstop:icstart); tbToggleSlotEnabledState.setSelected(slot.isEnabled()); } else if (Slot.PATCHNAME_PROPERTY.equals(evt.getPropertyName())) { updateSlotPatchName(); } else if (Slot.SELECTED_PROPERTY.equals(evt.getPropertyName())) { updateSlotPatchName(); if (evt.getNewValue() != null && ((Boolean) evt.getNewValue()).booleanValue()) form.openOrSelectPatch(slot); } } public void dragEnter(DropTargetDragEvent dtde) { if (form.acceptsDropData(this, dtde.getCurrentDataFlavors())) { lblSlotPatchName.setIcon(icfolderDragAccept); dtde.acceptDrag(DnDConstants.ACTION_LINK); } else { dtde.rejectDrag(); } } public void dragExit(DropTargetEvent dte) { updateSlotPatchName(); // update label } public void dragOver(DropTargetDragEvent dtde) { if (form.acceptsDropData(this, dtde.getCurrentDataFlavors())) { lblSlotPatchName.setIcon(icfolderDragAccept); dtde.acceptDrag(DnDConstants.ACTION_LINK); } else { dtde.rejectDrag(); } } public void drop(DropTargetDropEvent dtde) { if (form.acceptsDropData(this, dtde.getCurrentDataFlavors())) { form.dropTransfer(this, dtde); } else { dtde.rejectDrop(); } } public void dropActionChanged(DropTargetDragEvent dtde) { // TODO Auto-generated method stub } } protected void dropTransfer(SlotObject<S> s, DropTargetDropEvent dtde) { dtde.rejectDrop(); } protected boolean acceptsDropData(SlotObject<S> s, DataFlavor[] flavors) { return false; } private static String titleForSlot(int index) { return String.valueOf((char)('A'+index-1)); } public void openOrSelectPatch(Slot slot) { // } protected boolean arePlugsConfigured() { for (Port port: synth.getPorts()) { if (port.getPlug() == null) { return false; } } return true; } protected boolean showSettings() { final SynthPropertiesDialog<S> spd = new SynthPropertiesDialog<S>(synth); addForms(spd); spd.setSelectedPath("connection"); final JDialog d = new JDialog(Nomad.sharedInstance().getWindow(), "Properties for "+synth.getDeviceName()) { /** * */ private static final long serialVersionUID = -8324075575952331093L; { enableEvents(WindowEvent.WINDOW_EVENT_MASK); } protected void processWindowEvent(WindowEvent e) { if (e.getID()==WindowEvent.WINDOW_CLOSED) { spd.dispose(); } super.processWindowEvent(e); } }; d.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); d.setModal(true); Dimension ss = Toolkit.getDefaultToolkit().getScreenSize(); Dimension ds = new Dimension(ss.width/2, ss.height*2/5); d.getContentPane().setLayout(new BorderLayout()); d.getContentPane().add(spd); d.setBounds((ss.width-ds.width)/2, (ss.height-ds.height)/2, ds.width, ds.height); spd.addButton(new AbstractAction(){ /** * */ private static final long serialVersionUID = 6856066575494473810L; { putValue(NAME, "Close"); } public void actionPerformed(ActionEvent e) { d.setVisible(false); d.dispose(); }}); d.setVisible(true); return true; } }