Author: psmith Date: Fri Feb 10 21:12:35 2006 New Revision: 376931 URL: http://svn.apache.org/viewcvs?rev=376931&view=rev Log: Changed the way the ZeroConfPlugin renders it's model, decided to use a JTable instead because of the ease of coding in the auto-connect selection.
Added the ZeroConfDeviceModel to be able to easily serialize the model to disk. Added: logging/chainsaw/trunk/zeroconf/org/apache/log4j/chainsaw/zeroconf/ZeroConfDeviceModel.java Modified: logging/chainsaw/trunk/zeroconf/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java Added: logging/chainsaw/trunk/zeroconf/org/apache/log4j/chainsaw/zeroconf/ZeroConfDeviceModel.java URL: http://svn.apache.org/viewcvs/logging/chainsaw/trunk/zeroconf/org/apache/log4j/chainsaw/zeroconf/ZeroConfDeviceModel.java?rev=376931&view=auto ============================================================================== --- logging/chainsaw/trunk/zeroconf/org/apache/log4j/chainsaw/zeroconf/ZeroConfDeviceModel.java (added) +++ logging/chainsaw/trunk/zeroconf/org/apache/log4j/chainsaw/zeroconf/ZeroConfDeviceModel.java Fri Feb 10 21:12:35 2006 @@ -0,0 +1,130 @@ +package org.apache.log4j.chainsaw.zeroconf; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.jmdns.ServiceEvent; +import javax.jmdns.ServiceInfo; +import javax.jmdns.ServiceListener; +import javax.swing.ImageIcon; +import javax.swing.table.AbstractTableModel; + +import org.apache.log4j.chainsaw.icons.ChainsawIcons; + +public class ZeroConfDeviceModel extends AbstractTableModel implements ServiceListener { + + private List deviceList = new ArrayList(); + private ZeroConfPreferenceModel zeroConfPreferenceModel; + private transient ZeroConfPlugin plugin; + + public ZeroConfDeviceModel() { + } + + public int getRowCount() { + return deviceList.size(); + } + + public int getColumnCount() { + return 4; + } + + public ServiceInfo getServiceInfoAtRow(int row) { + return (ServiceInfo) deviceList.get(row); + } + public Object getValueAt(int rowIndex, int columnIndex) { + ServiceInfo info = (ServiceInfo) deviceList.get(rowIndex); + if(info == null) { + return ""; + } + switch(columnIndex) { + case 0: + return getAutoConnectHandle(info); + case 1: + return info.getAddress().getHostName() + ":" + info.getPort(); + case 2: + return zeroConfPreferenceModel.getAutoConnectDevices().contains(getAutoConnectHandle(info))?Boolean.TRUE:Boolean.FALSE; + case 3: + return plugin.isConnectedTo(info)?"Connected":"Not Connected"; +// return plugin.isConnectedTo(info)?new ImageIcon(ChainsawIcons.ANIM_NET_CONNECT):new ImageIcon(); + default: + return ""; + } + } + + private String getAutoConnectHandle(ServiceInfo info) { + return info.getName(); + } + + public void serviceAdded(ServiceEvent event) { + } + + public void serviceRemoved(ServiceEvent event) { + for (Iterator iter = deviceList.iterator(); iter.hasNext();) { + ServiceInfo info = (ServiceInfo) iter.next(); + if(info.getName().equals(event.getName())) { + iter.remove(); + } + } + fireTableDataChanged(); + } + + public void serviceResolved(ServiceEvent event) { + deviceList.add(event.getInfo()); + fireTableDataChanged(); + } + + public void setZeroConfPreferenceModel( + ZeroConfPreferenceModel zeroConfPreferenceModel) { + this.zeroConfPreferenceModel = zeroConfPreferenceModel; + } + + public String getColumnName(int column) { + switch(column) { + case 0: + return "ZeroConf name"; + case 1: + return "Address:Port"; + case 2: + return "Auto-connect"; + case 3: + return "Connection Status"; + default: + return ""; + } + } + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return columnIndex == 2; + } + + public Class getColumnClass(int columnIndex) { + switch(columnIndex) { + case 2: + return Boolean.class; + default: + return super.getColumnClass(columnIndex); + } + } + + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + if(columnIndex!=2 || !(aValue instanceof Boolean)) { + return; + } + boolean autoConnect = ((Boolean)aValue).booleanValue(); + Object device = this.deviceList.get(rowIndex); + String autoConnectHandle = getAutoConnectHandle((ServiceInfo) device); + if(autoConnect) { + zeroConfPreferenceModel.getAutoConnectDevices().add(autoConnectHandle); + }else { + zeroConfPreferenceModel.getAutoConnectDevices().remove(autoConnectHandle); + } + fireTableDataChanged(); + } + + void setZeroConfPluginParent(ZeroConfPlugin parent) { + this.plugin = parent; + } + + +} Modified: logging/chainsaw/trunk/zeroconf/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java URL: http://svn.apache.org/viewcvs/logging/chainsaw/trunk/zeroconf/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java?rev=376931&r1=376930&r2=376931&view=diff ============================================================================== --- logging/chainsaw/trunk/zeroconf/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java (original) +++ logging/chainsaw/trunk/zeroconf/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java Fri Feb 10 21:12:35 2006 @@ -3,7 +3,6 @@ import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; -import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -19,32 +18,28 @@ import javax.jmdns.ServiceInfo; import javax.jmdns.ServiceListener; import javax.swing.AbstractAction; -import javax.swing.BorderFactory; -import javax.swing.Box; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JCheckBox; +import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; -import javax.swing.JList; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; -import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; +import javax.swing.JTable; import javax.swing.JToolBar; -import javax.swing.ListCellRenderer; -import javax.swing.ListModel; import javax.swing.SwingUtilities; -import javax.swing.event.ListDataEvent; -import javax.swing.event.ListDataListener; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.DefaultTableCellRenderer; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; -import org.apache.log4j.chainsaw.ModifiableListModel; import org.apache.log4j.chainsaw.SmallButton; import org.apache.log4j.chainsaw.help.HelpManager; import org.apache.log4j.chainsaw.icons.ChainsawIcons; @@ -52,6 +47,7 @@ import org.apache.log4j.chainsaw.prefs.SettingsManager; import org.apache.log4j.net.SocketHubReceiver; import org.apache.log4j.net.ZeroConfSocketHubAppender; +import org.apache.log4j.net.ZeroConfSocketHubAppenderTestBed; import org.apache.log4j.net.Zeroconf4log4j; import org.apache.log4j.plugins.Plugin; import org.apache.log4j.plugins.PluginEvent; @@ -66,7 +62,6 @@ * whatever people are calling it) and allow the user to double click on * 'devices' to try and connect to them with no configuration needed. * - * TODO add autoConnect visuals, and save it in a model * TODO need to handle * NON-log4j devices that may be broadcast in the interested zones * TODO add the @@ -84,11 +79,11 @@ private static final Icon DEVICE_DISCOVERED_ICON = new ImageIcon(ChainsawIcons.ANIM_RADIO_TOWER); - private ModifiableListModel discoveredDevices = new ModifiableListModel(); + private ZeroConfDeviceModel discoveredDevices = new ZeroConfDeviceModel(); - private final JList listBox = new JList(discoveredDevices); - - private final JScrollPane scrollPane = new JScrollPane(listBox); + private JTable deviceTable = new JTable(discoveredDevices); + + private final JScrollPane scrollPane = new JScrollPane(deviceTable); private JmDNS jmDNS; @@ -139,12 +134,11 @@ ZeroConfSocketHubAppender.DEFAULT_ZEROCONF_ZONE, new ZeroConfServiceListener()); - listBox.setCellRenderer(new ServiceInfoListCellRenderer()); - listBox.setLayoutOrientation(JList.HORIZONTAL_WRAP); - listBox.setFixedCellHeight(75); - listBox.setFixedCellWidth(200); - listBox.setVisibleRowCount(-1); - listBox.addMouseListener(new ConnectorMouseListener()); + jmDNS.addServiceListener(ZeroConfSocketHubAppender.DEFAULT_ZEROCONF_ZONE, discoveredDevices); + + deviceTable.addMouseListener(new ConnectorMouseListener()); + + JToolBar toolbar = new JToolBar(); SmallButton helpButton = new SmallButton(helpItem.getAction()); helpButton.setText(helpItem.getText()); @@ -167,17 +161,12 @@ for (Iterator iter = serviceInfoToReceiveMap.entrySet().iterator(); iter.hasNext();) { Map.Entry entry = (Map.Entry) iter.next(); if(entry.getValue() == plugin) { - serviceInfoToReceiveMap.remove(entry.getKey()); + iter.remove(); } } } // need to make sure that the menu item tracking this item has it's icon and enabled state updade - JMenuItem item = locateMatchingMenuItem(plugin.getName()); - if (item!=null) { - item.setEnabled(true); - item.setIcon(null); - } - discoveredDevices.fireContentsChanged(); + discoveredDevices.fireTableDataChanged(); }}); File fileLocation = getPreferenceFileLocation(); @@ -192,20 +181,8 @@ }else { this.preferenceModel = new ZeroConfPreferenceModel(); } - - discoveredDevices.addListDataListener(new ListDataListener() { - - public void intervalAdded(ListDataEvent e) { - setIconIfNeeded(); - } - - public void intervalRemoved(ListDataEvent e) { - setIconIfNeeded(); - } - - public void contentsChanged(ListDataEvent e) { - setIconIfNeeded(); - }}); + discoveredDevices.setZeroConfPreferenceModel(preferenceModel); + discoveredDevices.setZeroConfPluginParent(this); } /** @@ -216,7 +193,7 @@ Container container = this.getParent(); if(container instanceof JTabbedPane) { JTabbedPane tabbedPane = (JTabbedPane) container; - Icon icon = discoveredDevices.getSize()==0?null:DEVICE_DISCOVERED_ICON; + Icon icon = discoveredDevices.getRowCount()==0?null:DEVICE_DISCOVERED_ICON; tabbedPane.setIconAt(tabbedPane.indexOfTab(getName()), icon); }else { LOG.warn("Parent is not a TabbedPane, not setting icon: " + container.getClass().getName()); @@ -241,22 +218,15 @@ insertToLeftOfHelp(menuBar, connectToMenu); connectToMenu.add(nothingToConnectTo); - discoveredDevices.addListDataListener(new ListDataListener() { - - public void intervalAdded(ListDataEvent e) { - if(discoveredDevices.getSize()>0) { - connectToMenu.remove(nothingToConnectTo); - } - } + discoveredDevices.addTableModelListener(new TableModelListener (){ - public void intervalRemoved(ListDataEvent e) { - if(discoveredDevices.getSize()==0) { + public void tableChanged(TableModelEvent e) { + if(discoveredDevices.getRowCount()==0) { connectToMenu.add(nothingToConnectTo,0); + }else if(discoveredDevices.getRowCount()>0) { + connectToMenu.remove(nothingToConnectTo); } - } - - public void contentsChanged(ListDataEvent e) { }}); nothingToConnectTo.setEnabled(false); @@ -266,6 +236,12 @@ } } + /** + * Hack method to locate the JMenu that is the Help menu, and inserts the new menu + * just to the left of it. + * @param menuBar + * @param item + */ private void insertToLeftOfHelp(JMenuBar menuBar, JMenu item) { for (int i = 0; i < menuBar.getMenuCount(); i++) { JMenu menu = menuBar.getMenu(i); @@ -276,6 +252,12 @@ LOG.warn("menu '" + item.getText() + "' was NOT added because the 'Help' menu could not be located"); } + /** + * When a device is discovered, we create a menu item for it so it can be connected to via that + * GUI mechanism, and also if the device is one of the auto-connect devices then a background thread + * is created to connect the device. + * @param info + */ private void deviceDiscovered(final ServiceInfo info) { final String name = info.getName(); // TODO currently adding ALL devices to autoConnectlist @@ -288,13 +270,7 @@ connectTo(info); }}); - if(discoveredDevices.getSize()>0) { - for (int i = 0; i < discoveredDevices.getSize(); i++) { - if (name.compareToIgnoreCase(((ServiceInfo) discoveredDevices - .elementAt(i)).getName()) < 0) { - discoveredDevices.insertElementAt(info, i); - } - } + if(discoveredDevices.getRowCount()>0) { Component[] menuComponents = connectToMenu.getMenuComponents(); boolean located = false; for (int i = 0; i < menuComponents.length; i++) { @@ -312,7 +288,6 @@ connectToMenu.insert(connectToDeviceMenuItem,0); } }else { - discoveredDevices.addElement(info); connectToMenu.insert(connectToDeviceMenuItem,0); } // if the device name is one of the autoconnect devices, then connect immediately @@ -327,13 +302,11 @@ } } + /** + * When a device is removed or disappears we need to remove any JMenu item associated with it. + * @param name + */ private void deviceRemoved(String name) { - for (int i = 0; i < discoveredDevices.getSize(); i++) { - if (name.compareToIgnoreCase(((ServiceInfo) discoveredDevices - .elementAt(i)).getName()) == 0) { - discoveredDevices.remove(i); - } - } Component[] menuComponents = connectToMenu.getMenuComponents(); for (int i = 0; i < menuComponents.length; i++) { Component c = menuComponents[i]; @@ -347,6 +320,11 @@ } } + /** + * Listens out on the JmDNS/ZeroConf network for new devices that appear + * and adds/removes these device information from the list/model. + * + */ private class ZeroConfServiceListener implements ServiceListener { public void serviceAdded(final ServiceEvent event) { @@ -380,76 +358,21 @@ } - private class ServiceInfoListCellRenderer implements - ListCellRenderer { - - private JPanel panel = new JPanel(new BorderLayout(15, 15)); - - private final ImageIcon ICON = new ImageIcon( - ChainsawIcons.ANIM_RADIO_TOWER); - - private JLabel iconLabel = new JLabel(ICON); - - private JLabel nameLabel = new JLabel(); - - private JLabel detailLabel = new JLabel(); - - private JCheckBox autoConnect = new JCheckBox(); - - private Box southBox = Box.createVerticalBox(); - private JCheckBox checkBox = new JCheckBox(); - - private ServiceInfoListCellRenderer() { - Font font = nameLabel.getFont(); - font = font.deriveFont(font.getSize() + 6); - nameLabel.setFont(font); - panel.setLayout(new BorderLayout()); - panel.add(iconLabel, BorderLayout.WEST); - - JPanel centerPanel = new JPanel(new BorderLayout(3, 3)); - - centerPanel.add(nameLabel, BorderLayout.CENTER); - centerPanel.add(southBox, BorderLayout.SOUTH); - panel.add(centerPanel, BorderLayout.CENTER); - - southBox.add(detailLabel); - Box hBox = Box.createHorizontalBox(); - hBox.add(Box.createHorizontalGlue()); - hBox.add(new JLabel("Auto-connect:")); - hBox.add(checkBox); - - southBox.add(hBox); - - panel.setBorder(BorderFactory.createEtchedBorder()); - } - - public Component getListCellRendererComponent(JList list, Object value, - int index, boolean isSelected, boolean cellHasFocus) { - if (isSelected) { - panel.setBackground(list.getSelectionBackground()); - panel.setForeground(list.getSelectionForeground()); - } else { - panel.setBackground(list.getBackground()); - panel.setForeground(list.getForeground()); - } - ServiceInfo info = (ServiceInfo) value; - nameLabel.setText(info.getName()); - detailLabel.setText(info.getHostAddress() + ":" + info.getPort()); - iconLabel.setIcon(isConnectedTo(info)?ICON:null); - checkBox.setSelected(preferenceModel.getAutoConnectDevices().contains(info.getName())); - return panel; - } - - } + /** + * When the user double clicks on a row, then the device is connected to, + * the only exception is when clicking in the check box column for auto connect. + */ private class ConnectorMouseListener extends MouseAdapter { public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { - int index = listBox.locationToIndex(e.getPoint()); - ListModel dlm = discoveredDevices; - ServiceInfo info = (ServiceInfo) dlm.getElementAt(index); - listBox.ensureIndexIsVisible(index); + int row = deviceTable.rowAtPoint(e.getPoint()); + if(deviceTable.columnAtPoint(e.getPoint())==2) { + return; + } + ServiceInfo info = discoveredDevices.getServiceInfoAtRow(row); + if (!isConnectedTo(info)) { connectTo(info); } else { @@ -463,24 +386,24 @@ * This methodh handles when the user clicks the * auto-connect */ - int index = listBox.locationToIndex(e.getPoint()); - - if (index != -1) { -// Point p = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), ) - Component c = SwingUtilities.getDeepestComponentAt(ZeroConfPlugin.this, e.getX(), e.getY()); - if (c instanceof JCheckBox) { - ServiceInfo info = (ServiceInfo) listBox.getModel() - .getElementAt(index); - String name = info.getName(); - if (preferenceModel.getAutoConnectDevices().contains(name)) { - preferenceModel.removeAutoConnectDevice(name); - } else { - preferenceModel.addAutoConnectDevice(name); - } - discoveredDevices.fireContentsChanged(); - repaint(); - } - } +// int index = listBox.locationToIndex(e.getPoint()); +// +// if (index != -1) { +//// Point p = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), ) +// Component c = SwingUtilities.getDeepestComponentAt(ZeroConfPlugin.this, e.getX(), e.getY()); +// if (c instanceof JCheckBox) { +// ServiceInfo info = (ServiceInfo) listBox.getModel() +// .getElementAt(index); +// String name = info.getName(); +// if (preferenceModel.getAutoConnectDevices().contains(name)) { +// preferenceModel.removeAutoConnectDevice(name); +// } else { +// preferenceModel.addAutoConnectDevice(name); +// } +// discoveredDevices.fireContentsChanged(); +// repaint(); +// } +// } } } @@ -493,13 +416,19 @@ plugin = (Plugin) serviceInfoToReceiveMap.get(info); } ((LoggerRepositoryEx)LogManager.getLoggerRepository()).getPluginRegistry().stopPlugin(plugin.getName()); + + JMenuItem item = locateMatchingMenuItem(info.getName()); + if (item!=null) { + item.setIcon(null); + item.setEnabled(true); + } } /** * returns true if the serviceInfo record already has a matching connected receiver * @param info * @return */ - private boolean isConnectedTo(ServiceInfo info) { + boolean isConnectedTo(ServiceInfo info) { return serviceInfoToReceiveMap.containsKey(info); } /** @@ -532,8 +461,8 @@ item.setIcon(new ImageIcon(ChainsawIcons.ANIM_NET_CONNECT)); item.setEnabled(false); } - // now notify the list model has changed, it needs redrawing of the receiver icon now it's connected - discoveredDevices.fireContentsChanged(); +// // now notify the list model has changed, it needs redrawing of the receiver icon now it's connected +// discoveredDevices.fireContentsChanged(); } /** --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]