1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package net.sf.jhylafax.addressbook;
21
22 import static net.sf.jhylafax.JHylaFAX.i18n;
23 import java.awt.BorderLayout;
24 import java.awt.Component;
25 import java.awt.Insets;
26 import java.awt.datatransfer.Transferable;
27 import java.awt.event.ActionEvent;
28 import java.awt.event.WindowAdapter;
29 import java.awt.event.WindowEvent;
30 import java.io.BufferedReader;
31 import java.io.ByteArrayInputStream;
32 import java.io.ByteArrayOutputStream;
33 import java.io.File;
34 import java.io.FileInputStream;
35 import java.io.FileOutputStream;
36 import java.io.FileReader;
37 import java.io.IOException;
38 import java.io.ObjectInputStream;
39 import java.io.ObjectOutputStream;
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.StringTokenizer;
43 import javax.swing.Action;
44 import javax.swing.Icon;
45 import javax.swing.JComponent;
46 import javax.swing.JFileChooser;
47 import javax.swing.JFrame;
48 import javax.swing.JLabel;
49 import javax.swing.JMenu;
50 import javax.swing.JMenuBar;
51 import javax.swing.JOptionPane;
52 import javax.swing.JPanel;
53 import javax.swing.JPopupMenu;
54 import javax.swing.JScrollPane;
55 import javax.swing.JSplitPane;
56 import javax.swing.JTable;
57 import javax.swing.JTextField;
58 import javax.swing.JToolBar;
59 import javax.swing.JTree;
60 import javax.swing.ListSelectionModel;
61 import javax.swing.WindowConstants;
62 import javax.swing.event.ListSelectionEvent;
63 import javax.swing.event.ListSelectionListener;
64 import javax.swing.table.AbstractTableModel;
65 import javax.swing.tree.DefaultMutableTreeNode;
66 import javax.swing.tree.DefaultTreeCellRenderer;
67 import javax.swing.tree.DefaultTreeModel;
68 import javax.swing.tree.TreePath;
69 import net.sf.jhylafax.JHylaFAX;
70 import net.sf.jhylafax.LocaleChangeListener;
71 import net.sf.jhylafax.Settings;
72 import net.wimpi.pim.Pim;
73 import net.wimpi.pim.contact.db.ContactDatabase;
74 import net.wimpi.pim.contact.db.ContactGroup;
75 import net.wimpi.pim.contact.facades.SimpleContact;
76 import net.wimpi.pim.contact.io.ContactMarshaller;
77 import net.wimpi.pim.contact.io.ContactUnmarshaller;
78 import net.wimpi.pim.contact.model.Contact;
79 import net.wimpi.pim.factory.ContactIOFactory;
80 import net.wimpi.pim.factory.ContactModelFactory;
81 import org.apache.commons.logging.Log;
82 import org.apache.commons.logging.LogFactory;
83 import org.xnap.commons.gui.Builder;
84 import org.xnap.commons.gui.ColoredTable;
85 import org.xnap.commons.gui.Dialogs;
86 import org.xnap.commons.gui.EraseTextFieldAction;
87 import org.xnap.commons.gui.ErrorDialog;
88 import org.xnap.commons.gui.ToolBarButton;
89 import org.xnap.commons.gui.action.AbstractXNapAction;
90 import org.xnap.commons.gui.table.StringCellRenderer;
91 import org.xnap.commons.gui.table.TableLayoutManager;
92 import org.xnap.commons.gui.table.TableSorter;
93 import org.xnap.commons.gui.util.DoubleClickListener;
94 import org.xnap.commons.gui.util.GUIHelper;
95 import org.xnap.commons.gui.util.IconHelper;
96 import org.xnap.commons.gui.util.PopupListener;
97 import org.xnap.commons.io.FileExtensionFilter;
98 import org.xnap.commons.settings.SettingStore;
99 import com.jgoodies.forms.builder.DefaultFormBuilder;
100 import com.jgoodies.forms.layout.FormLayout;
101
102 public class AddressBook extends JFrame implements ListSelectionListener,
103 LocaleChangeListener {
104
105 private final static Log logger = LogFactory.getLog(AddressBook.class);
106 private static final String[] DEFAULT_CONTACT_TABLE_COLUMNS
107 = new String[] { "displayName", "company", "faxNumber" };
108
109
110
111
112 public static void main(String[] args)
113 {
114 final AddressBook app = new AddressBook();
115 app.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
116 app.restoreLayout(new SettingStore(Settings.backstore));
117
118 try {
119 File file = JHylaFAX.getAddressBookFile();
120 if (file.exists()) {
121 app.load(file);
122 }
123 }
124 catch (Exception e) {
125 ErrorDialog.showError(null,
126 i18n.tr("Could not load address book"),
127 i18n.tr("JHylaFAX Error"), e);
128 }
129
130 app.addWindowListener(new WindowAdapter() {
131 public void windowClosing(WindowEvent event) {
132 try {
133 File file = JHylaFAX.getAddressBookFile();
134 app.store(file);
135 }
136 catch (Exception e) {
137 ErrorDialog.showError(null,
138 i18n.tr("Could not store address book"),
139 i18n.tr("JHylaFAX Error"), e);
140 }
141 }
142 });
143
144 app.setVisible(true);
145 }
146
147 private JMenu addressBookMenu;
148 private JTree addressBookTree;
149 private DefaultTreeModel addressBookTreeModel;
150 private CloseAction closeAction;
151 private JTable contactTable;
152 private AddressTableModel contactTableModel;
153 private DeleteAction deleteAction;
154 private Action doubleClickAction;
155 private EditAction editAction;
156 private ExportAction exportAction;
157 private FilterAction filterAction;
158 private ImportAction importAction;
159 private ContactCollection localAddressBook;
160 private JToolBar mainToolBar;
161 private NewAction newAction;
162 private DefaultMutableTreeNode rootNode;
163 private JTextField searchTextField;
164 private JSplitPane horizontalSplitPane;
165 private JLabel filterLabel;
166 private TableLayoutManager contactTableLayoutManager;
167
168 public AddressBook() {
169 ContactModelFactory cmf = Pim.getContactModelFactory();
170
171 JHylaFAX.initializeToolkit();
172 initialize();
173
174 ContactDatabase contactDatabase = Pim.getContactDBFactory().createContactDatabase();
175
176
177 DefaultMutableTreeNode localAddressBookTreeNode = new DefaultMutableTreeNode();
178 localAddressBook = new ContactCollection(contactDatabase, i18n.tr("Local Address Book"));
179 localAddressBookTreeNode.setUserObject(localAddressBook);
180 rootNode.add(localAddressBookTreeNode);
181 addressBookTree.expandPath(new TreePath(rootNode));
182 addressBookTree.setSelectionRow(0);
183
184 updateActions();
185 }
186
187 public void exportContacts(File file, SimpleContact[] contacts) throws IOException
188 {
189 FileOutputStream out = new FileOutputStream(file);
190 try {
191 ContactIOFactory factory = Pim.getContactIOFactory();
192 ContactMarshaller marshaller = factory.createContactMarshaller();
193 marshaller.setEncoding("UTF-8");
194 for (SimpleContact contact : contacts) {
195 marshaller.marshallContact(out, contact.getContact());
196 }
197 }
198 finally {
199 out.close();
200 }
201 }
202
203 public SimpleContact[] getAlllContacts()
204 {
205 TableSorter sorter = (TableSorter)contactTable.getModel();
206 SimpleContact[] result = new SimpleContact[sorter.getRowCount()];
207 for (int i = 0; i < result.length; i++) {
208 int row = sorter.mapToIndex(i);
209 result[i] = contactTableModel.getContact(row);
210 }
211 return result;
212 }
213
214 public ContactCollection getSelectedContactCollection()
215 {
216 DefaultMutableTreeNode node = (DefaultMutableTreeNode)addressBookTree.getSelectionPath().getLastPathComponent();
217 return (ContactCollection)node.getUserObject();
218 }
219
220 public SimpleContact[] getSelectedContacts()
221 {
222 int[] rows = contactTable.getSelectedRows();
223 if (rows.length == 0) {
224 return new SimpleContact[0];
225 }
226 SimpleContact[] result = new SimpleContact[rows.length];
227 for (int i = 0; i < rows.length; i++) {
228 int row = ((TableSorter)contactTable.getModel()).mapToIndex(rows[i]);
229 result[i] = contactTableModel.getContact(row);
230 }
231 return result;
232 }
233
234 public SimpleContact[] importVCardContacts(File file) throws IOException
235 {
236 FileInputStream in = new FileInputStream(file);
237 try {
238 ContactIOFactory factory = Pim.getContactIOFactory();
239 ContactUnmarshaller unmarshaller = factory.createContactUnmarshaller();
240 unmarshaller.setEncoding("UTF-8");
241 Contact[] contacts = unmarshaller.unmarshallContacts(in);
242 if (contacts != null) {
243 SimpleContact[] result = new SimpleContact[contacts.length];
244 for (int i = 0; i < contacts.length; i++) {
245 SimpleContact contact = new SimpleContact(contacts[i]);
246 getSelectedContactCollection().add(contact);
247 result[i] = contact;
248 }
249 return result;
250 }
251 return new SimpleContact[0];
252 }
253 finally {
254 in.close();
255 }
256 }
257
258 public SimpleContact[] importCSVContacts(File file, String separator) throws IOException
259 {
260 BufferedReader in = new BufferedReader(new FileReader(file));
261 try {
262 List<SimpleContact> contacts = new ArrayList<SimpleContact>();
263 String line;
264 while ((line = in.readLine()) != null) {
265 SimpleContact contact = new SimpleContact();
266 StringTokenizer t = new StringTokenizer(line, separator);
267 if (t.hasMoreTokens()) contact.setFirstname(t.nextToken());
268 if (t.hasMoreTokens()) contact.setLastname(t.nextToken());
269 if (t.hasMoreTokens()) contact.setFaxNumber(t.nextToken());
270 if (t.hasMoreTokens()) contact.setCompany(t.nextToken());
271 getSelectedContactCollection().add(contact);
272 contacts.add(contact);
273 }
274 return contacts.toArray(new SimpleContact[0]);
275 }
276 finally {
277 in.close();
278 }
279 }
280
281 private void initialize() {
282 initializeActions();
283 initializeShortCuts();
284 initializeMenuBar();
285 initializeContent();
286 initializeToolBar();
287
288 updateLabels();
289 }
290
291 private void initializeActions()
292 {
293 newAction = new NewAction();
294 editAction = new EditAction();
295 deleteAction = new DeleteAction();
296 importAction = new ImportAction();
297 exportAction = new ExportAction();
298 closeAction = new CloseAction();
299 filterAction = new FilterAction();
300 }
301
302 private void initializeContent()
303 {
304 horizontalSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
305 horizontalSplitPane.setBorder(GUIHelper.createEmptyBorder(5));
306
307 rootNode = new DefaultMutableTreeNode();
308 addressBookTreeModel = new DefaultTreeModel(rootNode);
309 addressBookTree = new JTree(addressBookTreeModel);
310 addressBookTree.setRootVisible(false);
311 addressBookTree.setCellRenderer(new ContactCollectionCellRenderer());
312 horizontalSplitPane.add(new JScrollPane(addressBookTree));
313
314 JPanel contactPanel = new JPanel();
315 contactPanel.setLayout(new BorderLayout(0, 10));
316 horizontalSplitPane.add(contactPanel);
317
318 DefaultFormBuilder builder = new DefaultFormBuilder(new FormLayout("min, 3dlu, min, 3dlu, pref:grow, 3dlu, min", ""));
319 contactPanel.add(builder.getPanel(), BorderLayout.NORTH);
320
321 searchTextField = new JTextField(10);
322 EraseTextFieldAction eraseAction = new EraseTextFieldAction(searchTextField) {
323 public void actionPerformed(ActionEvent event) {
324 super.actionPerformed(event);
325 filterAction.actionPerformed(event);
326 };
327 };
328 builder.append(new TabTitleButton(eraseAction));
329 filterLabel = new JLabel();
330 builder.append(filterLabel);
331 builder.append(searchTextField);
332 GUIHelper.bindEnterKey(searchTextField, filterAction);
333
334 builder.append(Builder.createButton(filterAction));
335
336 JPopupMenu tablePopupMenu = new JPopupMenu();
337 tablePopupMenu.add(Builder.createMenuItem(newAction));
338 tablePopupMenu.addSeparator();
339 tablePopupMenu.add(Builder.createMenuItem(editAction));
340 tablePopupMenu.addSeparator();
341 tablePopupMenu.add(Builder.createMenuItem(deleteAction));
342
343 contactTableModel = new AddressTableModel();
344 TableSorter sorter = new TableSorter(contactTableModel);
345 contactTable = new ColoredTable(sorter);
346 contactTableLayoutManager = new TableLayoutManager(contactTable);
347 contactTableLayoutManager.addColumnProperties("displayName", "", 180, true);
348 contactTableLayoutManager.addColumnProperties("company", "", 80, true);
349 contactTableLayoutManager.addColumnProperties("faxNumber", "", 60, true);
350 contactTableLayoutManager.initializeTableLayout();
351 contactPanel.add(new JScrollPane(contactTable), BorderLayout.CENTER);
352
353 contactTable.setShowVerticalLines(true);
354 contactTable.setShowHorizontalLines(false);
355 contactTable.setAutoCreateColumnsFromModel(true);
356 contactTable.setIntercellSpacing(new java.awt.Dimension(2, 1));
357 contactTable.setBounds(0, 0, 50, 50);
358 contactTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
359 contactTable.getSelectionModel().addListSelectionListener(this);
360 contactTable.addMouseListener(new PopupListener(tablePopupMenu));
361 contactTable.addMouseListener(new DoubleClickListener(new TableDoubleClickAction()));
362 contactTable.setTransferHandler(new ContactTransferHandler());
363 contactTable.setDragEnabled(true);
364
365 contactTable.setDefaultRenderer(String.class, new StringCellRenderer());
366
367 getContentPane().setLayout(new BorderLayout());
368 getContentPane().add(horizontalSplitPane, BorderLayout.CENTER);
369 }
370
371 private void initializeMenuBar()
372 {
373 JMenuBar menuBar = new JMenuBar();
374 setJMenuBar(menuBar);
375
376 addressBookMenu = new JMenu();
377 menuBar.add(addressBookMenu);
378 addressBookMenu.add(Builder.createMenuItem(newAction));
379 addressBookMenu.addSeparator();
380 addressBookMenu.add(Builder.createMenuItem(editAction));
381 addressBookMenu.addSeparator();
382 addressBookMenu.add(Builder.createMenuItem(deleteAction));
383 addressBookMenu.addSeparator();
384 addressBookMenu.add(Builder.createMenuItem(importAction));
385 addressBookMenu.add(Builder.createMenuItem(exportAction));
386 addressBookMenu.addSeparator();
387 addressBookMenu.add(Builder.createMenuItem(closeAction));
388 }
389
390 private void initializeShortCuts()
391 {
392 }
393
394 private void initializeToolBar()
395 {
396 mainToolBar = new JToolBar();
397
398
399 getContentPane().add(mainToolBar, BorderLayout.NORTH);
400
401 mainToolBar.add(Builder.createToolBarButton(newAction));
402 mainToolBar.addSeparator();
403 mainToolBar.add(Builder.createToolBarButton(editAction));
404 mainToolBar.add(Builder.createToolBarButton(deleteAction));
405 }
406
407 public void load(File file) throws IOException, ClassNotFoundException
408 {
409 ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
410 try {
411 ContactDatabase contactDatabase = (ContactDatabase)in.readObject();
412 localAddressBook.setDatabase(contactDatabase);
413 }
414 finally {
415 in.close();
416 }
417 }
418
419 public void saveLayout(SettingStore store) {
420 contactTableLayoutManager.saveLayout(store, "addressbook.contact");
421 store.saveWindow("addressbook.window", this);
422 store.saveSplitPane("addressbook.horizontalSplit", horizontalSplitPane);
423 }
424
425 public void restoreLayout(SettingStore store) {
426 contactTableLayoutManager.restoreLayout(store, "addressbook.contact");
427 store.restoreWindow("addressbook.window", 40, 40, 550, 300, this);
428 store.restoreSplitPane("addressbook.horizontalSplit", 150, horizontalSplitPane);
429 }
430
431 public void setDoubleClickAction(Action doubleClickAction)
432 {
433 this.doubleClickAction = doubleClickAction;
434 }
435
436 public void store(File file) throws IOException
437 {
438 if (!localAddressBook.isChanged()) {
439 logger.info("Address book unchanged");
440 return;
441 }
442
443 ObjectOutputStream in = new ObjectOutputStream(new FileOutputStream(file));
444 try {
445 in.writeObject(localAddressBook.getDatabase());
446 logger.info("Stored address book in " + file.getAbsolutePath());
447 }
448 finally {
449 in.close();
450 }
451 }
452
453 public void updateLabels() {
454 setTitle(i18n.tr("JHylaFAX Address Book"));
455
456 addressBookMenu.setText(i18n.tr("Address Book"));
457
458 newAction.putValue(Action.NAME, i18n.tr("New Contact..."));
459 editAction.putValue(Action.NAME, i18n.tr("Edit Contact..."));
460 deleteAction.putValue(Action.NAME, i18n.tr("Delete Contact"));
461
462 importAction.putValue(Action.NAME, i18n.tr("Import..."));
463 exportAction.putValue(Action.NAME, i18n.tr("Export..."));
464
465 closeAction.putValue(Action.NAME, i18n.tr("Close"));
466
467 filterLabel.setText(i18n.tr("Search for"));
468 filterAction.putValue(Action.NAME, i18n.tr("Go"));
469
470 contactTableLayoutManager.getTableLayout().setColumnNames(new String[] {
471 i18n.tr("Name"),
472 i18n.tr("Company"),
473 i18n.tr("Fax"),});
474
475 GUIHelper.setMnemonics(getJMenuBar());
476 }
477
478 public void valueChanged(ListSelectionEvent e) {
479 updateActions();
480 }
481
482 public void updateActions() {
483 boolean selected = (contactTable.getSelectedRow() != -1);
484 editAction.setEnabled(selected);
485 deleteAction.setEnabled(selected);
486 }
487
488 private static class AddressTableModel extends AbstractTableModel {
489
490 private static final Class[] columnClasses= {
491 String.class,
492 String.class,
493 String.class,
494 };
495
496 private List<SimpleContact> data = new ArrayList<SimpleContact>();
497
498 public AddressTableModel()
499 {
500 }
501
502 public void add(SimpleContact contact)
503 {
504 data.add(contact);
505 fireTableRowsInserted(data.size() - 1, data.size() - 1);
506 }
507
508 public Class<?> getColumnClass(int column) {
509 return columnClasses[column];
510 }
511
512 public int getColumnCount()
513 {
514 return columnClasses.length;
515 }
516
517 public SimpleContact getContact(int row) {
518 return data.get(row);
519 }
520
521 public int getRowCount()
522 {
523 return data.size();
524 }
525
526 public Object getValueAt(int row, int column)
527 {
528 SimpleContact contact = data.get(row);
529 switch (column) {
530 case 0:
531 return contact.getFirstname() + " " + contact.getLastname();
532 case 1:
533 return contact.getCompany();
534 case 2:
535 return contact.getFaxNumber();
536 default:
537 return null;
538 }
539 }
540
541 public int indexOf(SimpleContact contact)
542 {
543 for (int i = 0; i < data.size(); i++) {
544 if (data.get(i).getContact().equals(contact.getContact())) {
545 return i;
546 }
547 }
548 return -1;
549 }
550
551 public void remove(SimpleContact contact)
552 {
553
554 int i = indexOf(contact);
555 if (i != -1) {
556 data.remove(i);
557 fireTableRowsDeleted(i, i);
558 }
559 }
560
561 public void setData(List<SimpleContact> data)
562 {
563 this.data = data;
564 fireTableDataChanged();
565 }
566
567 public void update(SimpleContact contact)
568 {
569
570 int i = indexOf(contact);
571 if (i != -1) {
572 fireTableRowsUpdated(i, i);
573 }
574 }
575
576 }
577
578 private class CloseAction extends AbstractXNapAction {
579
580 public CloseAction() {
581 }
582
583 public void actionPerformed(ActionEvent event)
584 {
585 AddressBook.this.setVisible(false);
586 }
587 }
588
589 private class ContactCollection
590 {
591
592 private ContactDatabase database;
593 private String filterText;
594 private ContactGroup group;
595 private String name;
596 private ContactCollection parent;
597 private boolean changed;
598
599 public ContactCollection(ContactCollection parent, ContactGroup group)
600 {
601 this.parent = parent;
602 this.group = group;
603 }
604
605 public ContactCollection(ContactDatabase database, String name)
606 {
607 this.database = database;
608 this.name = name;
609 }
610
611 public void add(SimpleContact contact)
612 {
613 getDatabase().getContactCollection().add(contact.getContact());
614 if (group != null) {
615 group.addContact(contact.getContact());
616 }
617 if (matches(contact)) {
618 contactTableModel.add(contact);
619 }
620 changed = true;
621 }
622
623 public void changed(SimpleContact contact)
624 {
625 if (!matches(contact)) {
626 contactTableModel.remove(contact);
627 }
628 else {
629 contactTableModel.update(contact);
630 }
631 changed = true;
632 }
633
634 public ContactDatabase getDatabase()
635 {
636 return (parent != null) ? parent.getDatabase() : database;
637 }
638
639 public ContactGroup getGroup()
640 {
641 return group;
642 }
643
644 public boolean isChanged()
645 {
646 return changed;
647 }
648
649 private boolean matches(SimpleContact contact)
650 {
651 if (filterText == null || filterText.length() == 0) {
652 return true;
653 }
654 return contact.getFirstname().toLowerCase().contains(filterText)
655 || contact.getLastname().toLowerCase().contains(filterText)
656 || contact.getCompany().toLowerCase().contains(filterText)
657 || contact.getFaxNumber().toLowerCase().contains(filterText);
658 }
659
660 public void remove(SimpleContact contact)
661 {
662 getDatabase().getContactCollection().remove(contact.getContact());
663 if (group != null) {
664 group.removeContact(contact.getContact());
665 }
666 if (matches(contact)) {
667 contactTableModel.remove(contact);
668 }
669 changed = true;
670 }
671
672 public void resync()
673 {
674 Contact[] contacts = (group != null)
675 ? group.listContacts()
676 : database.getContactCollection().toArray();
677 List<SimpleContact> data = new ArrayList<SimpleContact>(contacts.length);
678 for (int i = 0; i < contacts.length; i++) {
679 SimpleContact contact = new SimpleContact(contacts[i]);
680 if (matches(contact)) {
681 data.add(contact);
682 }
683 }
684 contactTableModel.setData(data);
685 valueChanged(null);
686 }
687
688 public void setDatabase(ContactDatabase database)
689 {
690 this.database = database;
691 changed = false;
692 resync();
693 }
694
695 public void setFilterText(String filterText)
696 {
697 this.filterText = filterText.toLowerCase();
698 resync();
699 }
700
701 @Override
702 public String toString()
703 {
704 return (group != null) ? group.getName() : name;
705 }
706
707 }
708
709 private static class ContactCollectionCellRenderer extends DefaultTreeCellRenderer {
710 Icon bookIcon = IconHelper.getTreeIcon("contents.png");
711 Icon groupIcon = IconHelper.getTreeIcon("kdmconfig.png");
712
713 @Override
714 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus)
715 {
716 super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
717 row, hasFocus);
718
719 DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
720 if (node.getUserObject() instanceof ContactCollection) {
721 ContactCollection collection = (ContactCollection)node.getUserObject();
722 setIcon((collection.getGroup() != null) ? groupIcon : bookIcon);
723 }
724
725 return this;
726 }
727 }
728
729 private class DeleteAction extends AbstractXNapAction {
730
731 public DeleteAction() {
732 putValue(ICON_FILENAME, "editdelete.png");
733 }
734
735 public void actionPerformed(ActionEvent e)
736 {
737 SimpleContact[] contacts = getSelectedContacts();
738 if (Dialogs.showConfirmDialog(AddressBook.this,
739 i18n.tr("Do you really want to delete the selected contacts?"),
740 i18n.tr("Delete Contacts"),
741 JOptionPane.YES_NO_OPTION,
742 Settings.CONFIRM_DELETE) == JOptionPane.YES_OPTION) {
743 for (int i = 0; i < contacts.length; i++) {
744 getSelectedContactCollection().remove(contacts[i]);
745 }
746 }
747 }
748
749 }
750
751 private class EditAction extends AbstractXNapAction {
752
753 public EditAction() {
754 putValue(ICON_FILENAME, "edit.png");
755 }
756
757 public void actionPerformed(ActionEvent e)
758 {
759 SimpleContact[] contact = getSelectedContacts();
760 EditContactDialog dialog = new EditContactDialog(AddressBook.this, contact[0]);
761 dialog.setModal(true);
762 dialog.setLocationRelativeTo(AddressBook.this);
763 dialog.setVisible(true);
764 if (dialog.isOkay()) {
765 getSelectedContactCollection().changed(contact[0]);
766 }
767 }
768
769 }
770
771 private class ExportAction extends AbstractXNapAction {
772
773 public ExportAction() {
774 putValue(ICON_FILENAME, "fileexport.png");
775 }
776
777 public void actionPerformed(ActionEvent event)
778 {
779 if (contactTableModel.getRowCount() == 0) {
780 Dialogs.showInfo(AddressBook.this, i18n.tr("No data to export"), i18n.tr("JHylaFAX Addressbook Error"));
781 }
782
783 JFileChooser fileChooser = new JFileChooser();
784 fileChooser.addChoosableFileFilter(new FileExtensionFilter(i18n.tr("vCards (*.vcf)"), ".vcf"));
785 if (fileChooser.showSaveDialog(AddressBook.this) == JFileChooser.APPROVE_OPTION) {
786 try {
787 SimpleContact[] contacts = getSelectedContacts();
788 if (contacts.length == 0) {
789 contacts = getAlllContacts();
790 }
791 exportContacts(fileChooser.getSelectedFile(), contacts);
792 Dialogs.showInfo(AddressBook.this,
793 i18n.tr("Exported {0} contacts", contacts.length),
794 i18n.tr("JHylaFAX Address Book"));
795 }
796 catch (Exception e) {
797 ErrorDialog.showError(AddressBook.this,
798 i18n.tr("Could not export to file \"{0}\""),
799 i18n.tr("JHylaFAX Error"), e);
800 }
801 }
802 }
803 }
804
805 private class FilterAction extends AbstractXNapAction {
806
807 public FilterAction() {
808 putValue(ICON_FILENAME, "filter.png");
809 }
810
811 public void actionPerformed(ActionEvent e)
812 {
813 getSelectedContactCollection().setFilterText(searchTextField.getText());
814 }
815
816 }
817
818 private class ImportAction extends AbstractXNapAction {
819
820 public ImportAction() {
821 putValue(ICON_FILENAME, "fileimport.png");
822 }
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844 public void actionPerformed(ActionEvent e)
845 {
846 ImportWizard wizard = new ImportWizard(AddressBook.this);
847 wizard.setLocationRelativeTo(AddressBook.this);
848 wizard.setVisible(true);
849 }
850
851 }
852
853 private class NewAction extends AbstractXNapAction {
854
855 public NewAction() {
856 putValue(ICON_FILENAME, "filenew.png");
857 }
858
859 public void actionPerformed(ActionEvent e)
860 {
861 SimpleContact contact = new SimpleContact();
862 EditContactDialog dialog = new EditContactDialog(AddressBook.this, contact);
863 dialog.setModal(true);
864 dialog.setLocationRelativeTo(AddressBook.this);
865 dialog.setVisible(true);
866 if (dialog.isOkay()) {
867 getSelectedContactCollection().add(contact);
868 }
869 }
870
871 }
872
873 private class TableDoubleClickAction extends AbstractXNapAction {
874
875 public TableDoubleClickAction() {
876 }
877
878 public void actionPerformed(ActionEvent event)
879 {
880 if (doubleClickAction == null) {
881 if (editAction.isEnabled()) {
882 editAction.actionPerformed(event);
883 }
884 }
885 else if (doubleClickAction.isEnabled()){
886 doubleClickAction.actionPerformed(event);
887 }
888 }
889
890 }
891
892 private class TabTitleButton extends ToolBarButton
893 {
894 public TabTitleButton(Action action)
895 {
896 super(action);
897 String iconName = (String)action.getValue(AbstractXNapAction.ICON_FILENAME);
898 setIcon(IconHelper.getTabTitleIcon(iconName));
899 setMargin(new Insets(0, 0, 0, 0));
900 }
901 }
902
903 private class ContactTransferHandler extends AbstractContactTransferHandler {
904
905 @Override
906 protected Transferable createTransferable(JComponent c)
907 {
908 SimpleContact[] contacts = getSelectedContacts();
909 if (contacts.length == 0) {
910 return super.createTransferable(c);
911 }
912
913 ByteArrayOutputStream out = new ByteArrayOutputStream();
914 ContactIOFactory factory = Pim.getContactIOFactory();
915 ContactMarshaller marshaller = factory.createContactMarshaller();
916 marshaller.setEncoding("UTF-8");
917 for (SimpleContact contact : contacts) {
918 marshaller.marshallContact(out, contact.getContact());
919 }
920 return new ContactTransferable(new ByteArrayInputStream(out.toByteArray()));
921 }
922
923 @Override
924 public void importData(Contact[] contacts)
925 {
926 for (int i = 0; i < contacts.length; i++) {
927 SimpleContact contact = new SimpleContact(contacts[i]);
928 getSelectedContactCollection().add(contact);
929 }
930 }
931
932 }
933
934 }