/* * Copyright 2004 - 2008 Christian Sprajc. All rights reserved. * * This file is part of PowerFolder. * * PowerFolder 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. * * PowerFolder 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 PowerFolder. If not, see <http://www.gnu.org/licenses/>. * * $Id$ */ package de.dal33t.powerfolder.ui.model; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.TableModel; import com.jgoodies.binding.list.LinkedListModel; import com.jgoodies.binding.list.ObservableList; import de.dal33t.powerfolder.Controller; import de.dal33t.powerfolder.Member; import de.dal33t.powerfolder.ui.PFUIComponent; import de.dal33t.powerfolder.event.NodeManagerAdapter; import de.dal33t.powerfolder.event.NodeManagerEvent; import de.dal33t.powerfolder.security.SecurityManagerEvent; import de.dal33t.powerfolder.security.SecurityManagerListener; import de.dal33t.powerfolder.util.Reject; import de.dal33t.powerfolder.util.Translation; import de.dal33t.powerfolder.util.Util; import de.dal33t.powerfolder.util.compare.MemberComparator; import de.dal33t.powerfolder.util.compare.ReverseComparator; import de.dal33t.powerfolder.ui.util.UIUtil; /** * A table model which contains the search result. * * @author <A HREF="mailto:schaatser@powerfolder.com">Jan van Oosterom</A> * @author <a href="mailto:totmacher@powerfolder.com">Christian Sprajc</a> * @version $Revision: 1.2 $ */ public class SearchNodeTableModel extends PFUIComponent implements TableModel, SortedTableModel { private List<TableModelListener> listeners = new LinkedList<TableModelListener>(); private final ObservableList<Member> members = new LinkedListModel<Member>(); /** * The comparators for the columns, initalized in constructor */ private Comparator[] columComparators = new Comparator[COLUMN_NAMES.length]; private boolean sortAscending; private int sortColumn; private Comparator comparator; private static final String[] COLUMN_NAMES = { Translation.getTranslation("friend_search.node_table.name"), Translation.getTranslation("friend_search.node_table.account"), Translation.getTranslation("friend_search.node_table.last_seen_online"), Translation.getTranslation("friend_search.node_table.ip"), Translation.getTranslation("friend_search.node_table.on_local_network")}; /** * Initalizes the node table model which contains user/nodes * * @param controller */ public SearchNodeTableModel(Controller controller) { super(controller); // Add listener to nodemanager controller.getNodeManager().addNodeManagerListener( new MyNodeManagerListener()); controller.getSecurityManager().addListener( new MySecurityManagerListener()); members.addListDataListener(new ListModelListener()); columComparators[0] = MemberComparator.NICK; columComparators[1] = MemberComparator.DISPLAY_NAME; columComparators[2] = MemberComparator.BY_LAST_CONNECT_DATE; columComparators[3] = MemberComparator.IP; columComparators[4] = MemberComparator.BY_CONNECTION_TYPE; } /** * Clears the model and displays "No users found" text in the first row. */ public void clear() { members.clear(); } /** add a member */ public void add(Member member) { Reject.ifNull(member, "Member is null"); logFine("add member id: '" + member.getId() + '\''); members.add(member); sort(); } /** * Sorts the filelist */ private boolean sort() { if (comparator != null) { synchronized (members) { if (sortAscending) { Collections.sort(members, comparator); } else { Collections .sort(members, new ReverseComparator(comparator)); } } fireModelChanged(); return true; } return false; } /** * Sorts the model by a column * * @param columnIndex * @return if the model was sorted freshly */ public boolean sortBy(int columnIndex) { // Do not sort if no comparator given for that column if (columnIndex < 0 && columnIndex > columComparators.length || columComparators[columnIndex] == null) { comparator = null; sortColumn = -1; return false; } sortColumn = columnIndex; return sortBy(columComparators[columnIndex]); } /** * Reverses the sorting of the table */ public void reverseList() { sortAscending = !sortAscending; sort(); } /** * Re-sorts the folder list with the new comparator only if comparator * differs from old one * * @param newComparator * @return if the table was freshly sorted */ private boolean sortBy(Comparator newComparator) { Comparator oldComparator = comparator; comparator = newComparator; if (!Util.equals(oldComparator, newComparator)) { return sort(); } return false; } /** * @param member * @return if the member is contained in the model. */ public boolean contains(Member member) { return members.contains(member); } /** removes the first occurence of a member */ public void remove(Member member) { Reject.ifNull(member, "Member is null"); members.remove(member); } /** * @return if there are no users found */ public boolean containsNoUsers() { return members.isEmpty(); } // Exposing *************************************************************** /** * Returns the listmodel containing the nodes of the tablemodel. Changes in * the model will be reflected in the list. * * @return the listmodel containing the nodes. */ public ObservableList<Member> getListModel() { return members; } // TableModel interface *************************************************** public int getRowCount() { return Math.max(members.size(), 1); } public Object getDataAt(int rowIndex) { if (members.isEmpty()) { return ""; } return members.get(rowIndex); } public Object getValueAt(int rowIndex, int columnIndex) { return getDataAt(rowIndex); } public Class<Member> getColumnClass(int columnIndex) { return Member.class; } public int getColumnCount() { return COLUMN_NAMES.length; } public String getColumnName(int columnIndex) { return COLUMN_NAMES[columnIndex]; } public void setValueAt(Object aValue, int rowIndex, int columnIndex) { throw new IllegalStateException("not editable"); } public boolean isCellEditable(int rowIndex, int columnIndex) { return false; } public void addTableModelListener(TableModelListener listener) { listeners.add(listener); } public void removeTableModelListener(TableModelListener listener) { listeners.remove(listener); } private void updateNode(Member node) { int row = members.indexOf(node); if (row < 0) { return; } TableModelEvent te = new TableModelEvent(this, row, row, TableModelEvent.ALL_COLUMNS, TableModelEvent.UPDATE); fireTableModelEvent(te); } private void fireModelChanged() { TableModelEvent te = new TableModelEvent(this, 0, getRowCount(), TableModelEvent.ALL_COLUMNS, TableModelEvent.UPDATE); fireTableModelEvent(te); } private void fireModelStructureChanged() { TableModelEvent te = new TableModelEvent(this); fireTableModelEvent(te); } private void fireTableModelEvent(final TableModelEvent te) { Runnable runner = new Runnable() { public void run() { for (TableModelListener listener : listeners) { listener.tableChanged(te); } } }; UIUtil.invokeLaterInEDT(runner); } public int getSortColumn() { return sortColumn; } public boolean isSortAscending() { return sortAscending; } public void setAscending(boolean ascending) { sortAscending = ascending; } // //////////////// // Inner classes // // //////////////// /** * Listens for changes on the listmodel and fires the appropriate table * model events. */ private class ListModelListener implements ListDataListener { public void intervalAdded(ListDataEvent e) { fireModelStructureChanged(); } public void intervalRemoved(ListDataEvent e) { fireModelStructureChanged(); } public void contentsChanged(ListDataEvent e) { fireModelChanged(); } } /** * Adapter between TableModel and NodeManager. Listens on changes of the * nodes and fires tablemodel events. */ private class MyNodeManagerListener extends NodeManagerAdapter { public void nodeConnected(NodeManagerEvent e) { updateNode(e.getNode()); } public void nodeDisconnected(NodeManagerEvent e) { updateNode(e.getNode()); } public void nodeOffline(NodeManagerEvent e) { updateNode(e.getNode()); } public void nodeOnline(NodeManagerEvent e) { updateNode(e.getNode()); } public void friendAdded(NodeManagerEvent e) { updateNode(e.getNode()); } public void friendRemoved(NodeManagerEvent e) { updateNode(e.getNode()); } public void settingsChanged(NodeManagerEvent e) { updateNode(e.getNode()); } public boolean fireInEventDispatchThread() { return false; } } private class MySecurityManagerListener implements SecurityManagerListener { public void nodeAccountStateChanged(SecurityManagerEvent e) { updateNode(e.getNode()); } public boolean fireInEventDispatchThread() { return true; } } }