package org.limewire.ui.swing.library.navigator; import java.awt.Color; import java.awt.Dimension; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Comparator; import javax.swing.DropMode; import javax.swing.ListSelectionModel; import javax.swing.event.ChangeEvent; import javax.swing.table.TableCellEditor; import org.jdesktop.application.Resource; import org.limewire.collection.glazedlists.GlazedListsFactory; import org.limewire.core.api.library.LibraryManager; import org.limewire.core.api.library.LocalFileList; import org.limewire.core.api.library.SharedFileList; import org.limewire.core.api.library.SharedFileListManager; import org.limewire.inject.LazySingleton; import org.limewire.ui.swing.library.LibraryMediator; import org.limewire.ui.swing.library.navigator.LibraryNavItem.NavType; import org.limewire.ui.swing.nav.NavCategory; import org.limewire.ui.swing.nav.NavItem; import org.limewire.ui.swing.nav.Navigator; import org.limewire.ui.swing.table.GlazedJXTable; import org.limewire.ui.swing.table.SingleColumnTableFormat; import org.limewire.ui.swing.table.TablePopupHandler; import org.limewire.ui.swing.util.GuiUtils; import org.limewire.ui.swing.util.SwingHacks; import ca.odell.glazedlists.CompositeList; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FunctionList; import ca.odell.glazedlists.SortedList; import ca.odell.glazedlists.impl.swing.SwingThreadProxyEventList; import ca.odell.glazedlists.swing.DefaultEventTableModel; import com.google.inject.Inject; import com.google.inject.Provider; @LazySingleton public class LibraryNavigatorTable extends GlazedJXTable { @Resource private Color backgroundColor; private TablePopupHandler popupHandler; private final Provider<Navigator> navigatorProvider; private SwingThreadProxyEventList<LibraryNavItem> stpl; @Inject public LibraryNavigatorTable(LibraryNavTransferHandler libraryNavTransferHandler, LibraryManager libraryManager, SharedFileListManager sharedFileListManager, Provider<Navigator> navigatorProvider) { this.navigatorProvider = navigatorProvider; GuiUtils.assignResources(this); initialize(); EventList<SharedFileList> privateLists = sharedFileListManager.getModel(); FunctionList<SharedFileList, LibraryNavItem> shareToNav = GlazedListsFactory.functionList(privateLists, new FunctionList.AdvancedFunction<SharedFileList, LibraryNavItem>() { @Override public void dispose(SharedFileList sourceValue, LibraryNavItem transformedValue) { // TODO: sourceValue.dispose necessary? } @Override public LibraryNavItem evaluate(SharedFileList sourceValue) { return new LibraryNavItem(sourceValue); } @Override public LibraryNavItem reevaluate(SharedFileList sourceValue, LibraryNavItem transformedValue) { return transformedValue; } }); CompositeList<LibraryNavItem> compositeList = new CompositeList<LibraryNavItem>(privateLists.getPublisher(), privateLists.getReadWriteLock()); compositeList.getReadWriteLock().writeLock().lock(); try { // Create a fake EventList to hold the library list & add it to the composite list. EventList<LibraryNavItem> libraryList = compositeList.createMemberList(); libraryList.add(new LibraryNavItem(libraryManager.getLibraryManagedList())); compositeList.addMemberList(libraryList); compositeList.addMemberList(shareToNav); } finally { compositeList.getReadWriteLock().writeLock().unlock(); } SortedList<LibraryNavItem> sortedList = GlazedListsFactory.sortedList(compositeList, new LibraryNavItemComparator()); stpl = GlazedListsFactory.swingThreadProxyEventList(sortedList); setModel(new DefaultEventTableModel<LibraryNavItem>(stpl, new SingleColumnTableFormat<LibraryNavItem>(""))); setDropMode(DropMode.ON); setTransferHandler(libraryNavTransferHandler); SwingHacks.fixDnDforKDE(this); setEditable(false); } public void selectLibraryNavItem(int id) { showNavTableIfHidden(); for(int i = 0; i < getModel().getRowCount(); i++) { Object value = getModel().getValueAt(i, 0); if(value instanceof LibraryNavItem) { if( ((LibraryNavItem) value).getId() == id) { getSelectionModel().setSelectionInterval(i,i); break; } } } } public void selectLibraryNavItem(LocalFileList sharedFileList) { showNavTableIfHidden(); for(int i = 0; i < getModel().getRowCount(); i++) { Object value = getModel().getValueAt(i, 0); if(value instanceof LibraryNavItem) { if( ((LibraryNavItem) value).getLocalFileList() == sharedFileList) { getSelectionModel().setSelectionInterval(i,i); break; } } } } private void showNavTableIfHidden(){ if (!isShowing()) { NavItem item = navigatorProvider.get().getNavItem(NavCategory.LIBRARY, LibraryMediator.NAME); item.select(); } } public LibraryNavItem getSelectedItem() { int selected = getSelectedRow(); if(selected < 0) { getSelectionModel().setSelectionInterval(0, 0); selected = 0; } return (LibraryNavItem)getModel().getValueAt(selected, 0); } private void initialize() { setFillsViewportHeight(true); setBackground(backgroundColor); setShowGrid(false, false); setTableHeader(null); setRowHeight(24); setSelectionMode(ListSelectionModel.SINGLE_SELECTION); addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) {//adding this to editor messes up popups // // int col = columnAtPoint(e.getPoint()); // int row = rowAtPoint(e.getPoint()); // // if (row >= 0 && col >= 0) { // if (rowDoubleClickHandler != null || columnDoubleClickHandler != null) { // Component component = e.getComponent(); // //launch file on double click unless the click is on a button // if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e) // && !(component.getComponentAt(e.getPoint()) instanceof JButton)) { // if (rowDoubleClickHandler != null) { // rowDoubleClickHandler.handleDoubleClick(row); // } // if (columnDoubleClickHandler != null) { // columnDoubleClickHandler.handleDoubleClick(col); // } // } // } // } } @Override public void mouseExited(MouseEvent e) { // maybeCancelEditing(); } @Override public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } @Override public void mousePressed(MouseEvent e) { // int col = columnAtPoint(e.getPoint()); // int row = rowAtPoint(e.getPoint()); // if (isEditing() && isCellEditable(row, col)) { // TableCellEditor editor = getCellEditor(row, col); // if (editor != null) { // // force update editor colors // prepareEditor(editor, row, col); // } // } maybeShowPopup(e); } private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger() && popupHandler != null) { int col = columnAtPoint(e.getPoint()); int row = rowAtPoint(e.getPoint()); if (row >= 0 && col >= 0) { popupHandler.maybeShowPopup( e.getComponent(), e.getX(), e.getY()); TableCellEditor editor = getCellEditor(); if (editor != null) { editor.cancelCellEditing(); } } } } }); } @Override public Dimension getPreferredScrollableViewportSize() { return new Dimension(super.getPreferredScrollableViewportSize().width, getModel().getRowCount() * getRowHeight()); } public void setPopupHandler(TablePopupHandler popupHandler) { this.popupHandler = popupHandler; } @Override public void editingStopped(ChangeEvent e) { TableCellEditor editor = getCellEditor(); if (editor != null) { Object value = editor.getCellEditorValue(); if(value instanceof String) { handleRename((String)value); } removeEditor(); } setEditable(false); } /** * Renames the selected LibraryNavItem if the new Name * is a valid String. */ private void handleRename(String newName) { if(newName == null || newName.length() == 0) return; LibraryNavItem item = getSelectedItem(); LocalFileList fileList = item.getLocalFileList(); if(fileList instanceof SharedFileList) { SharedFileList sharedFileList = (SharedFileList) fileList; if(sharedFileList.isNameChangeAllowed() && !sharedFileList.getCollectionName().equals(newName)) { sharedFileList.setCollectionName(newName); } } } @Override public boolean isCellEditable(int row, int col) { if (!isEditable() || row >= getRowCount() || col >= getColumnCount() || row < 2 || col < 0) { return false; } return true; } @Override public boolean editCellAt(int row, int column) { if(super.editCellAt(row, column)) { LibraryNavTableEditor editor = (LibraryNavTableEditor)getCellEditor(); editor.prepareForEditing(); return true; } else { return false; } } public int getPrivateSharedLibraryCount() { int numberOfPrivateSharedLibraries = 0; for ( LibraryNavItem item : stpl ) { if ( item.getType() == LibraryNavItem.NavType.LIST ) { numberOfPrivateSharedLibraries++; } } return numberOfPrivateSharedLibraries; } /** * Technically shouldn't be necessary but ensures that Library and Public Shared * always appear first and second in the table. The other items appear as they are * loaded. */ private static class LibraryNavItemComparator implements Comparator<LibraryNavItem> { @Override public int compare(LibraryNavItem nav1, LibraryNavItem nav2) { NavType type1 = nav1.getType(); NavType type2 = nav2.getType(); if(type1 == NavType.LIBRARY) return -1; else if(type2 == NavType.LIBRARY) return 1; else if(type1 == NavType.PUBLIC_SHARED) return -1; else if(type2 == NavType.PUBLIC_SHARED) return 1; return 0; } } }