Java tutorial
/** * JHylaFax - A java client for HylaFAX. * * Copyright (C) 2005 by Steffen Pingel <steffenp@gmx.de> * * This program 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package net.sf.jhylafax.addressbook; import static net.sf.jhylafax.JHylaFAX.i18n; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Insets; import java.awt.datatransfer.Transferable; import java.awt.event.ActionEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import javax.swing.Action; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.JToolBar; import javax.swing.JTree; import javax.swing.ListSelectionModel; import javax.swing.WindowConstants; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import net.sf.jhylafax.JHylaFAX; import net.sf.jhylafax.LocaleChangeListener; import net.sf.jhylafax.Settings; import net.wimpi.pim.Pim; import net.wimpi.pim.contact.db.ContactDatabase; import net.wimpi.pim.contact.db.ContactGroup; import net.wimpi.pim.contact.facades.SimpleContact; import net.wimpi.pim.contact.io.ContactMarshaller; import net.wimpi.pim.contact.io.ContactUnmarshaller; import net.wimpi.pim.contact.model.Contact; import net.wimpi.pim.factory.ContactIOFactory; import net.wimpi.pim.factory.ContactModelFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.xnap.commons.gui.Builder; import org.xnap.commons.gui.ColoredTable; import org.xnap.commons.gui.Dialogs; import org.xnap.commons.gui.EraseTextFieldAction; import org.xnap.commons.gui.ErrorDialog; import org.xnap.commons.gui.ToolBarButton; import org.xnap.commons.gui.action.AbstractXNapAction; import org.xnap.commons.gui.table.StringCellRenderer; import org.xnap.commons.gui.table.TableLayoutManager; import org.xnap.commons.gui.table.TableSorter; import org.xnap.commons.gui.util.DoubleClickListener; import org.xnap.commons.gui.util.GUIHelper; import org.xnap.commons.gui.util.IconHelper; import org.xnap.commons.gui.util.PopupListener; import org.xnap.commons.io.FileExtensionFilter; import org.xnap.commons.settings.SettingStore; import com.jgoodies.forms.builder.DefaultFormBuilder; import com.jgoodies.forms.layout.FormLayout; public class AddressBook extends JFrame implements ListSelectionListener, LocaleChangeListener { private final static Log logger = LogFactory.getLog(AddressBook.class); private static final String[] DEFAULT_CONTACT_TABLE_COLUMNS = new String[] { "displayName", "company", "faxNumber" }; /** * @param args */ public static void main(String[] args) { final AddressBook app = new AddressBook(); app.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); app.restoreLayout(new SettingStore(Settings.backstore)); try { File file = JHylaFAX.getAddressBookFile(); if (file.exists()) { app.load(file); } } catch (Exception e) { ErrorDialog.showError(null, i18n.tr("Could not load address book"), i18n.tr("JHylaFAX Error"), e); } app.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent event) { try { File file = JHylaFAX.getAddressBookFile(); app.store(file); } catch (Exception e) { ErrorDialog.showError(null, i18n.tr("Could not store address book"), i18n.tr("JHylaFAX Error"), e); } } }); app.setVisible(true); } private JMenu addressBookMenu; private JTree addressBookTree; private DefaultTreeModel addressBookTreeModel; private CloseAction closeAction; private JTable contactTable; private AddressTableModel contactTableModel; private DeleteAction deleteAction; private Action doubleClickAction; private EditAction editAction; private ExportAction exportAction; private FilterAction filterAction; private ImportAction importAction; private ContactCollection localAddressBook; private JToolBar mainToolBar; private NewAction newAction; private DefaultMutableTreeNode rootNode; private JTextField searchTextField; private JSplitPane horizontalSplitPane; private JLabel filterLabel; private TableLayoutManager contactTableLayoutManager; public AddressBook() { ContactModelFactory cmf = Pim.getContactModelFactory(); JHylaFAX.initializeToolkit(); initialize(); ContactDatabase contactDatabase = Pim.getContactDBFactory().createContactDatabase(); // initialize tree content DefaultMutableTreeNode localAddressBookTreeNode = new DefaultMutableTreeNode(); localAddressBook = new ContactCollection(contactDatabase, i18n.tr("Local Address Book")); localAddressBookTreeNode.setUserObject(localAddressBook); rootNode.add(localAddressBookTreeNode); addressBookTree.expandPath(new TreePath(rootNode)); addressBookTree.setSelectionRow(0); updateActions(); } public void exportContacts(File file, SimpleContact[] contacts) throws IOException { FileOutputStream out = new FileOutputStream(file); try { ContactIOFactory factory = Pim.getContactIOFactory(); ContactMarshaller marshaller = factory.createContactMarshaller(); marshaller.setEncoding("UTF-8"); for (SimpleContact contact : contacts) { marshaller.marshallContact(out, contact.getContact()); } } finally { out.close(); } } public SimpleContact[] getAlllContacts() { TableSorter sorter = (TableSorter) contactTable.getModel(); SimpleContact[] result = new SimpleContact[sorter.getRowCount()]; for (int i = 0; i < result.length; i++) { int row = sorter.mapToIndex(i); result[i] = contactTableModel.getContact(row); } return result; } public ContactCollection getSelectedContactCollection() { DefaultMutableTreeNode node = (DefaultMutableTreeNode) addressBookTree.getSelectionPath() .getLastPathComponent(); return (ContactCollection) node.getUserObject(); } public SimpleContact[] getSelectedContacts() { int[] rows = contactTable.getSelectedRows(); if (rows.length == 0) { return new SimpleContact[0]; } SimpleContact[] result = new SimpleContact[rows.length]; for (int i = 0; i < rows.length; i++) { int row = ((TableSorter) contactTable.getModel()).mapToIndex(rows[i]); result[i] = contactTableModel.getContact(row); } return result; } public SimpleContact[] importVCardContacts(File file) throws IOException { FileInputStream in = new FileInputStream(file); try { ContactIOFactory factory = Pim.getContactIOFactory(); ContactUnmarshaller unmarshaller = factory.createContactUnmarshaller(); unmarshaller.setEncoding("UTF-8"); Contact[] contacts = unmarshaller.unmarshallContacts(in); if (contacts != null) { SimpleContact[] result = new SimpleContact[contacts.length]; for (int i = 0; i < contacts.length; i++) { SimpleContact contact = new SimpleContact(contacts[i]); getSelectedContactCollection().add(contact); result[i] = contact; } return result; } return new SimpleContact[0]; } finally { in.close(); } } public SimpleContact[] importCSVContacts(File file, String separator) throws IOException { BufferedReader in = new BufferedReader(new FileReader(file)); try { List<SimpleContact> contacts = new ArrayList<SimpleContact>(); String line; while ((line = in.readLine()) != null) { SimpleContact contact = new SimpleContact(); StringTokenizer t = new StringTokenizer(line, separator); if (t.hasMoreTokens()) contact.setFirstname(t.nextToken()); if (t.hasMoreTokens()) contact.setLastname(t.nextToken()); if (t.hasMoreTokens()) contact.setFaxNumber(t.nextToken()); if (t.hasMoreTokens()) contact.setCompany(t.nextToken()); getSelectedContactCollection().add(contact); contacts.add(contact); } return contacts.toArray(new SimpleContact[0]); } finally { in.close(); } } private void initialize() { initializeActions(); initializeShortCuts(); initializeMenuBar(); initializeContent(); initializeToolBar(); updateLabels(); } private void initializeActions() { newAction = new NewAction(); editAction = new EditAction(); deleteAction = new DeleteAction(); importAction = new ImportAction(); exportAction = new ExportAction(); closeAction = new CloseAction(); filterAction = new FilterAction(); } private void initializeContent() { horizontalSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); horizontalSplitPane.setBorder(GUIHelper.createEmptyBorder(5)); rootNode = new DefaultMutableTreeNode(); addressBookTreeModel = new DefaultTreeModel(rootNode); addressBookTree = new JTree(addressBookTreeModel); addressBookTree.setRootVisible(false); addressBookTree.setCellRenderer(new ContactCollectionCellRenderer()); horizontalSplitPane.add(new JScrollPane(addressBookTree)); JPanel contactPanel = new JPanel(); contactPanel.setLayout(new BorderLayout(0, 10)); horizontalSplitPane.add(contactPanel); DefaultFormBuilder builder = new DefaultFormBuilder( new FormLayout("min, 3dlu, min, 3dlu, pref:grow, 3dlu, min", "")); contactPanel.add(builder.getPanel(), BorderLayout.NORTH); searchTextField = new JTextField(10); EraseTextFieldAction eraseAction = new EraseTextFieldAction(searchTextField) { public void actionPerformed(ActionEvent event) { super.actionPerformed(event); filterAction.actionPerformed(event); }; }; builder.append(new TabTitleButton(eraseAction)); filterLabel = new JLabel(); builder.append(filterLabel); builder.append(searchTextField); GUIHelper.bindEnterKey(searchTextField, filterAction); builder.append(Builder.createButton(filterAction)); JPopupMenu tablePopupMenu = new JPopupMenu(); tablePopupMenu.add(Builder.createMenuItem(newAction)); tablePopupMenu.addSeparator(); tablePopupMenu.add(Builder.createMenuItem(editAction)); tablePopupMenu.addSeparator(); tablePopupMenu.add(Builder.createMenuItem(deleteAction)); contactTableModel = new AddressTableModel(); TableSorter sorter = new TableSorter(contactTableModel); contactTable = new ColoredTable(sorter); contactTableLayoutManager = new TableLayoutManager(contactTable); contactTableLayoutManager.addColumnProperties("displayName", "", 180, true); contactTableLayoutManager.addColumnProperties("company", "", 80, true); contactTableLayoutManager.addColumnProperties("faxNumber", "", 60, true); contactTableLayoutManager.initializeTableLayout(); contactPanel.add(new JScrollPane(contactTable), BorderLayout.CENTER); contactTable.setShowVerticalLines(true); contactTable.setShowHorizontalLines(false); contactTable.setAutoCreateColumnsFromModel(true); contactTable.setIntercellSpacing(new java.awt.Dimension(2, 1)); contactTable.setBounds(0, 0, 50, 50); contactTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); contactTable.getSelectionModel().addListSelectionListener(this); contactTable.addMouseListener(new PopupListener(tablePopupMenu)); contactTable.addMouseListener(new DoubleClickListener(new TableDoubleClickAction())); contactTable.setTransferHandler(new ContactTransferHandler()); contactTable.setDragEnabled(true); contactTable.setDefaultRenderer(String.class, new StringCellRenderer()); getContentPane().setLayout(new BorderLayout()); getContentPane().add(horizontalSplitPane, BorderLayout.CENTER); } private void initializeMenuBar() { JMenuBar menuBar = new JMenuBar(); setJMenuBar(menuBar); addressBookMenu = new JMenu(); menuBar.add(addressBookMenu); addressBookMenu.add(Builder.createMenuItem(newAction)); addressBookMenu.addSeparator(); addressBookMenu.add(Builder.createMenuItem(editAction)); addressBookMenu.addSeparator(); addressBookMenu.add(Builder.createMenuItem(deleteAction)); addressBookMenu.addSeparator(); addressBookMenu.add(Builder.createMenuItem(importAction)); addressBookMenu.add(Builder.createMenuItem(exportAction)); addressBookMenu.addSeparator(); addressBookMenu.add(Builder.createMenuItem(closeAction)); } private void initializeShortCuts() { } private void initializeToolBar() { mainToolBar = new JToolBar(); //mainToolBar.setBorderPainted(false); //mainToolBar.setRollover(true); getContentPane().add(mainToolBar, BorderLayout.NORTH); mainToolBar.add(Builder.createToolBarButton(newAction)); mainToolBar.addSeparator(); mainToolBar.add(Builder.createToolBarButton(editAction)); mainToolBar.add(Builder.createToolBarButton(deleteAction)); } public void load(File file) throws IOException, ClassNotFoundException { ObjectInputStream in = new ObjectInputStream(new FileInputStream(file)); try { ContactDatabase contactDatabase = (ContactDatabase) in.readObject(); localAddressBook.setDatabase(contactDatabase); } finally { in.close(); } } public void saveLayout(SettingStore store) { contactTableLayoutManager.saveLayout(store, "addressbook.contact"); store.saveWindow("addressbook.window", this); store.saveSplitPane("addressbook.horizontalSplit", horizontalSplitPane); } public void restoreLayout(SettingStore store) { contactTableLayoutManager.restoreLayout(store, "addressbook.contact"); store.restoreWindow("addressbook.window", 40, 40, 550, 300, this); store.restoreSplitPane("addressbook.horizontalSplit", 150, horizontalSplitPane); } public void setDoubleClickAction(Action doubleClickAction) { this.doubleClickAction = doubleClickAction; } public void store(File file) throws IOException { if (!localAddressBook.isChanged()) { logger.info("Address book unchanged"); return; } ObjectOutputStream in = new ObjectOutputStream(new FileOutputStream(file)); try { in.writeObject(localAddressBook.getDatabase()); logger.info("Stored address book in " + file.getAbsolutePath()); } finally { in.close(); } } public void updateLabels() { setTitle(i18n.tr("JHylaFAX Address Book")); addressBookMenu.setText(i18n.tr("Address Book")); newAction.putValue(Action.NAME, i18n.tr("New Contact...")); editAction.putValue(Action.NAME, i18n.tr("Edit Contact...")); deleteAction.putValue(Action.NAME, i18n.tr("Delete Contact")); importAction.putValue(Action.NAME, i18n.tr("Import...")); exportAction.putValue(Action.NAME, i18n.tr("Export...")); closeAction.putValue(Action.NAME, i18n.tr("Close")); filterLabel.setText(i18n.tr("Search for")); filterAction.putValue(Action.NAME, i18n.tr("Go")); contactTableLayoutManager.getTableLayout() .setColumnNames(new String[] { i18n.tr("Name"), i18n.tr("Company"), i18n.tr("Fax"), }); GUIHelper.setMnemonics(getJMenuBar()); } public void valueChanged(ListSelectionEvent e) { updateActions(); } public void updateActions() { boolean selected = (contactTable.getSelectedRow() != -1); editAction.setEnabled(selected); deleteAction.setEnabled(selected); } private static class AddressTableModel extends AbstractTableModel { private static final Class[] columnClasses = { String.class, String.class, String.class, }; private List<SimpleContact> data = new ArrayList<SimpleContact>(); public AddressTableModel() { } public void add(SimpleContact contact) { data.add(contact); fireTableRowsInserted(data.size() - 1, data.size() - 1); } public Class<?> getColumnClass(int column) { return columnClasses[column]; } public int getColumnCount() { return columnClasses.length; } public SimpleContact getContact(int row) { return data.get(row); } public int getRowCount() { return data.size(); } public Object getValueAt(int row, int column) { SimpleContact contact = data.get(row); switch (column) { case 0: return contact.getFirstname() + " " + contact.getLastname(); case 1: return contact.getCompany(); case 2: return contact.getFaxNumber(); default: return null; } } public int indexOf(SimpleContact contact) { for (int i = 0; i < data.size(); i++) { if (data.get(i).getContact().equals(contact.getContact())) { return i; } } return -1; } public void remove(SimpleContact contact) { // XXX work around broken SimpleContant.equals() method int i = indexOf(contact); if (i != -1) { data.remove(i); fireTableRowsDeleted(i, i); } } public void setData(List<SimpleContact> data) { this.data = data; fireTableDataChanged(); } public void update(SimpleContact contact) { // XXX work around broken SimpleContant.equals() method int i = indexOf(contact); if (i != -1) { fireTableRowsUpdated(i, i); } } } private class CloseAction extends AbstractXNapAction { public CloseAction() { } public void actionPerformed(ActionEvent event) { AddressBook.this.setVisible(false); } } private class ContactCollection { private ContactDatabase database; private String filterText; private ContactGroup group; private String name; private ContactCollection parent; private boolean changed; public ContactCollection(ContactCollection parent, ContactGroup group) { this.parent = parent; this.group = group; } public ContactCollection(ContactDatabase database, String name) { this.database = database; this.name = name; } public void add(SimpleContact contact) { getDatabase().getContactCollection().add(contact.getContact()); if (group != null) { group.addContact(contact.getContact()); } if (matches(contact)) { contactTableModel.add(contact); } changed = true; } public void changed(SimpleContact contact) { if (!matches(contact)) { contactTableModel.remove(contact); } else { contactTableModel.update(contact); } changed = true; } public ContactDatabase getDatabase() { return (parent != null) ? parent.getDatabase() : database; } public ContactGroup getGroup() { return group; } public boolean isChanged() { return changed; } private boolean matches(SimpleContact contact) { if (filterText == null || filterText.length() == 0) { return true; } return contact.getFirstname().toLowerCase().contains(filterText) || contact.getLastname().toLowerCase().contains(filterText) || contact.getCompany().toLowerCase().contains(filterText) || contact.getFaxNumber().toLowerCase().contains(filterText); } public void remove(SimpleContact contact) { getDatabase().getContactCollection().remove(contact.getContact()); if (group != null) { group.removeContact(contact.getContact()); } if (matches(contact)) { contactTableModel.remove(contact); } changed = true; } public void resync() { Contact[] contacts = (group != null) ? group.listContacts() : database.getContactCollection().toArray(); List<SimpleContact> data = new ArrayList<SimpleContact>(contacts.length); for (int i = 0; i < contacts.length; i++) { SimpleContact contact = new SimpleContact(contacts[i]); if (matches(contact)) { data.add(contact); } } contactTableModel.setData(data); valueChanged(null); } public void setDatabase(ContactDatabase database) { this.database = database; changed = false; resync(); } public void setFilterText(String filterText) { this.filterText = filterText.toLowerCase(); resync(); } @Override public String toString() { return (group != null) ? group.getName() : name; } } private static class ContactCollectionCellRenderer extends DefaultTreeCellRenderer { Icon bookIcon = IconHelper.getTreeIcon("contents.png"); Icon groupIcon = IconHelper.getTreeIcon("kdmconfig.png"); @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; if (node.getUserObject() instanceof ContactCollection) { ContactCollection collection = (ContactCollection) node.getUserObject(); setIcon((collection.getGroup() != null) ? groupIcon : bookIcon); } return this; } } private class DeleteAction extends AbstractXNapAction { public DeleteAction() { putValue(ICON_FILENAME, "editdelete.png"); } public void actionPerformed(ActionEvent e) { SimpleContact[] contacts = getSelectedContacts(); if (Dialogs.showConfirmDialog(AddressBook.this, i18n.tr("Do you really want to delete the selected contacts?"), i18n.tr("Delete Contacts"), JOptionPane.YES_NO_OPTION, Settings.CONFIRM_DELETE) == JOptionPane.YES_OPTION) { for (int i = 0; i < contacts.length; i++) { getSelectedContactCollection().remove(contacts[i]); } } } } private class EditAction extends AbstractXNapAction { public EditAction() { putValue(ICON_FILENAME, "edit.png"); } public void actionPerformed(ActionEvent e) { SimpleContact[] contact = getSelectedContacts(); EditContactDialog dialog = new EditContactDialog(AddressBook.this, contact[0]); dialog.setModal(true); dialog.setLocationRelativeTo(AddressBook.this); dialog.setVisible(true); if (dialog.isOkay()) { getSelectedContactCollection().changed(contact[0]); } } } private class ExportAction extends AbstractXNapAction { public ExportAction() { putValue(ICON_FILENAME, "fileexport.png"); } public void actionPerformed(ActionEvent event) { if (contactTableModel.getRowCount() == 0) { Dialogs.showInfo(AddressBook.this, i18n.tr("No data to export"), i18n.tr("JHylaFAX Addressbook Error")); } JFileChooser fileChooser = new JFileChooser(); fileChooser.addChoosableFileFilter(new FileExtensionFilter(i18n.tr("vCards (*.vcf)"), ".vcf")); if (fileChooser.showSaveDialog(AddressBook.this) == JFileChooser.APPROVE_OPTION) { try { SimpleContact[] contacts = getSelectedContacts(); if (contacts.length == 0) { contacts = getAlllContacts(); } exportContacts(fileChooser.getSelectedFile(), contacts); Dialogs.showInfo(AddressBook.this, i18n.tr("Exported {0} contacts", contacts.length), i18n.tr("JHylaFAX Address Book")); } catch (Exception e) { ErrorDialog.showError(AddressBook.this, i18n.tr("Could not export to file \"{0}\""), i18n.tr("JHylaFAX Error"), e); } } } } private class FilterAction extends AbstractXNapAction { public FilterAction() { putValue(ICON_FILENAME, "filter.png"); } public void actionPerformed(ActionEvent e) { getSelectedContactCollection().setFilterText(searchTextField.getText()); } } private class ImportAction extends AbstractXNapAction { public ImportAction() { putValue(ICON_FILENAME, "fileimport.png"); } /* public void actionPerformed1(ActionEvent event) { JFileChooser fileChooser = new JFileChooser(); fileChooser.addChoosableFileFilter(new FileExtensionFilter(I18n.tr("vCards (*.vcf)"), ".vcf")); if (fileChooser.showOpenDialog(AddressBook.this) == JFileChooser.APPROVE_OPTION) { try { SimpleContact[] contacts = importContacts(fileChooser.getSelectedFile()); Dialogs.showInfo(AddressBook.this, I18n.tr("Imported {0} contacts", contacts.length), I18n.tr("JHylaFAX Address Book")); } catch (Exception e) { ErrorDialog.showError(AddressBook.this, I18n.tr("Could not import from file \"{0}\""), I18n.tr("JHylaFAX Addressbook Error"), e); } } } */ public void actionPerformed(ActionEvent e) { ImportWizard wizard = new ImportWizard(AddressBook.this); wizard.setLocationRelativeTo(AddressBook.this); wizard.setVisible(true); } } private class NewAction extends AbstractXNapAction { public NewAction() { putValue(ICON_FILENAME, "filenew.png"); } public void actionPerformed(ActionEvent e) { SimpleContact contact = new SimpleContact(); EditContactDialog dialog = new EditContactDialog(AddressBook.this, contact); dialog.setModal(true); dialog.setLocationRelativeTo(AddressBook.this); dialog.setVisible(true); if (dialog.isOkay()) { getSelectedContactCollection().add(contact); } } } private class TableDoubleClickAction extends AbstractXNapAction { public TableDoubleClickAction() { } public void actionPerformed(ActionEvent event) { if (doubleClickAction == null) { if (editAction.isEnabled()) { editAction.actionPerformed(event); } } else if (doubleClickAction.isEnabled()) { doubleClickAction.actionPerformed(event); } } } private class TabTitleButton extends ToolBarButton { public TabTitleButton(Action action) { super(action); String iconName = (String) action.getValue(AbstractXNapAction.ICON_FILENAME); setIcon(IconHelper.getTabTitleIcon(iconName)); setMargin(new Insets(0, 0, 0, 0)); } } private class ContactTransferHandler extends AbstractContactTransferHandler { @Override protected Transferable createTransferable(JComponent c) { SimpleContact[] contacts = getSelectedContacts(); if (contacts.length == 0) { return super.createTransferable(c); } ByteArrayOutputStream out = new ByteArrayOutputStream(); ContactIOFactory factory = Pim.getContactIOFactory(); ContactMarshaller marshaller = factory.createContactMarshaller(); marshaller.setEncoding("UTF-8"); for (SimpleContact contact : contacts) { marshaller.marshallContact(out, contact.getContact()); } return new ContactTransferable(new ByteArrayInputStream(out.toByteArray())); } @Override public void importData(Contact[] contacts) { for (int i = 0; i < contacts.length; i++) { SimpleContact contact = new SimpleContact(contacts[i]); getSelectedContactCollection().add(contact); } } } }