From 3077418fa958b0a2be67507b38aa57db78dcaf1e Mon Sep 17 00:00:00 2001 From: Sigmund Hansen Date: Tue, 25 Sep 2018 00:23:58 +0200 Subject: [PATCH 1/3] Some refactoring and linting. --- app/src/processing/app/contrib/ListPanel.java | 388 ++++++++---------- .../app/contrib/UpdateListPanel.java | 35 +- 2 files changed, 176 insertions(+), 247 deletions(-) diff --git a/app/src/processing/app/contrib/ListPanel.java b/app/src/processing/app/contrib/ListPanel.java index d9b36ce12..2acb690b2 100644 --- a/app/src/processing/app/contrib/ListPanel.java +++ b/app/src/processing/app/contrib/ListPanel.java @@ -45,8 +45,8 @@ import processing.app.ui.Toolkit; public class ListPanel extends JPanel implements Scrollable, ContributionListing.ChangeListener { ContributionTab contributionTab; - TreeMap panelByContribution = new TreeMap(ContributionListing.COMPARATOR); - Set visibleContributions = new TreeSet(ContributionListing.COMPARATOR); + TreeMap panelByContribution = new TreeMap<>(ContributionListing.COMPARATOR); + Set visibleContributions = new TreeSet<>(ContributionListing.COMPARATOR); private DetailPanel selectedPanel; protected Contribution.Filter filter; @@ -135,48 +135,11 @@ implements Scrollable, ContributionListing.ChangeListener { } }); - TableRowSorter sorter = new TableRowSorter(table.getModel()); + TableRowSorter sorter = new TableRowSorter<>(table.getModel()); table.setRowSorter(sorter); sorter.setComparator(1, ContributionListing.COMPARATOR); - sorter.setComparator(2, new Comparator() { - - @Override - public int compare(Contribution o1, Contribution o2) { - return getAuthorNameWithoutMarkup(o1.getAuthorList()) - .compareTo(getAuthorNameWithoutMarkup(o2.getAuthorList())); - } - }); - sorter.setComparator(0, new Comparator() { - - @Override - public int compare(Contribution o1, Contribution o2) { - int pos1 = 0; - if (o1.isInstalled()) { - pos1 = 1; - if (contribListing.hasUpdates(o1)) { - pos1 = 2; - } - if (!o1.isCompatible(Base.getRevision())) { - pos1 = 3; - } - } else { - pos1 = 4; - } - int pos2 = 0; - if (o2.isInstalled()) { - pos2 = 1; - if (contribListing.hasUpdates(o2)) { - pos2 = 2; - } - if (!o2.isCompatible(Base.getRevision())) { - pos2 = 3; - } - } else { - pos2 = 4; - } - return pos1 - pos2; - } - }); + sorter.setComparator(2, Comparator.comparing(o -> getAuthorNameWithoutMarkup(((Contribution) o).getAuthorList()))); + sorter.setComparator(0, Comparator.comparingInt(o -> getContributionStatusRank((Contribution) o))); table.getTableHeader().setDefaultRenderer(new ContribHeaderRenderer()); GroupLayout layout = new GroupLayout(this); @@ -187,6 +150,19 @@ implements Scrollable, ContributionListing.ChangeListener { table.setVisible(true); } + private int getContributionStatusRank(Contribution c) { + int pos = 4; + if (c.isInstalled()) { + pos = 1; + if (contribListing.hasUpdates(c)) { + pos = 2; + } + if (!c.isCompatible(Base.getRevision())) { + pos = 3; + } + } + return pos; + } class ContribHeaderRenderer extends DefaultTableCellRenderer { @@ -264,16 +240,11 @@ implements Scrollable, ContributionListing.ChangeListener { * @return the SortKey, or null if the column is unsorted */ protected SortKey getSortKey(JTable table, int column) { - RowSorter rowSorter = table.getRowSorter(); - if (rowSorter == null) { - return null; - } + return Optional.ofNullable(table.getRowSorter()) + .map(RowSorter::getSortKeys) + .map(columns -> columns.isEmpty() ? null : columns.get(0)) + .orElse(null); - List sortedColumns = rowSorter.getSortKeys(); - if (sortedColumns.size() > 0) { - return (SortKey) sortedColumns.get(0); - } - return null; } } @@ -298,96 +269,90 @@ implements Scrollable, ContributionListing.ChangeListener { // TODO this is now working, but the underlying issue is not fixed return label; } - if (column == 0) { - Icon icon = null; - label.setFont(ManagerFrame.NORMAL_PLAIN); - if (contribution.isInstalled()) { - icon = upToDateIcon; - if (contribListing.hasUpdates(contribution)) { - icon = updateAvailableIcon; - } - if (!contribution.isCompatible(Base.getRevision())) { - icon = incompatibleIcon; - } - } - if ((panelByContribution.get(contribution)).updateInProgress || - (panelByContribution.get(contribution)).installInProgress) { - // Display "Loading icon" if download/install in progress - label.setIcon(downloadingIcon); - } else { - label.setIcon(icon); - } - label.setHorizontalAlignment(SwingConstants.CENTER); - if (isSelected) { - label.setBackground(new Color(0xe0fffd)); - } - label.setOpaque(true); -// return table.getDefaultRenderer(Icon.class).getTableCellRendererComponent(table, icon, isSelected, false, row, column); - - } else if (column == 1) { - // Generating ellipses based on fontMetrics - final Font boldFont = ManagerFrame.NORMAL_BOLD; - String fontFace = ""; - FontMetrics fontMetrics = table.getFontMetrics(boldFont); //table.getFont()); - int colSize = table.getColumnModel().getColumn(1).getWidth(); - String sentence = contribution.getSentence(); - //int currentWidth = table.getFontMetrics(table.getFont().deriveFont(Font.BOLD)).stringWidth(contribution.getName() + " | "); - int currentWidth = table.getFontMetrics(boldFont).stringWidth(contribution.getName() + " | "); - int ellipsesWidth = fontMetrics.stringWidth("..."); - //String name = "" + contribution.getName(); - String name = "" + fontFace + contribution.getName(); - if (sentence == null) { - label.setText(name + ""); - } else { - sentence = " | " + sentence; - currentWidth += ellipsesWidth; - int i = 0; - for (i = 0; i < sentence.length(); i++) { - currentWidth += fontMetrics.charWidth(sentence.charAt(i)); - if (currentWidth >= colSize) { - break; - } - } - // Adding ellipses only if text doesn't fits into the column - if(i != sentence.length()){ - label.setText(name + sentence.substring(0, i) + "..."); - }else { - label.setText(name + sentence + ""); - } - } - if (!contribution.isCompatible(Base.getRevision())) { - label.setForeground(Color.LIGHT_GRAY); - } - if (table.isRowSelected(row)) { - label.setBackground(new Color(0xe0fffd)); - } - label.setFont(ManagerFrame.NORMAL_PLAIN); - label.setOpaque(true); - } else { - if (contribution.isSpecial()) { - label = new JLabel(foundationIcon); - } else { - label = new JLabel(); - } - String authorList = contribution.getAuthorList(); - String name = getAuthorNameWithoutMarkup(authorList); - label.setText(name); - label.setHorizontalAlignment(SwingConstants.LEFT); - if(!contribution.isCompatible(Base.getRevision())){ - label.setForeground(Color.LIGHT_GRAY); - }else{ - label.setForeground(Color.BLACK); - } - if (table.isRowSelected(row)) { - label.setBackground(new Color(0xe0fffd)); - } - label.setFont(ManagerFrame.NORMAL_BOLD); - label.setOpaque(true); + if (isSelected) { + label.setBackground(new Color(0xe0fffd)); } + if (column == 0) { + configureStatusColumnLabel(label, contribution); + } else if (column == 1) { + configureNameColumnLabel(table, label, contribution); + } else { + configureAuthorsColumnLabel(label, contribution); + } + + if(!contribution.isCompatible(Base.getRevision())){ + label.setForeground(Color.LIGHT_GRAY); + } + label.setOpaque(true); return label; } - } + private void configureStatusColumnLabel(JLabel label, Contribution contribution) { + Icon icon = null; + label.setFont(ManagerFrame.NORMAL_PLAIN); + if ((panelByContribution.get(contribution)).updateInProgress || + (panelByContribution.get(contribution)).installInProgress) { + // Display "Loading icon" if download/install in progress + icon = downloadingIcon; + } else if (contribution.isInstalled()) { + if (!contribution.isCompatible(Base.getRevision())) { + icon = incompatibleIcon; + } else if (contribListing.hasUpdates(contribution)) { + icon = updateAvailableIcon; + } else { + icon = upToDateIcon; + } + } + + label.setIcon(icon); + label.setHorizontalAlignment(SwingConstants.CENTER); + } + + private void configureNameColumnLabel(JTable table, JLabel label, Contribution contribution) { + // Generating ellipses based on fontMetrics + final Font boldFont = ManagerFrame.NORMAL_BOLD; + FontMetrics fontMetrics = table.getFontMetrics(boldFont); //table.getFont()); + int colSize = table.getColumnModel().getColumn(1).getWidth(); + int currentWidth = fontMetrics.stringWidth(contribution.getName() + " | ..."); + String sentence = contribution.getSentence(); + StringBuilder text = new StringBuilder("") + .append(contribution.getName()); + + if (sentence == null) { + text.append(""); + } else { + int i = 0; + for (i = 0; i < sentence.length(); i++) { + currentWidth += fontMetrics.charWidth(sentence.charAt(i)); + if (currentWidth >= colSize) { + break; + } + } + text.append(" | ").append(sentence, 0, i); + // Adding ellipses only if text doesn't fits into the column + if(i != sentence.length()) { + text.append("..."); + } + } + text.append(""); + label.setText(text.toString()); + label.setFont(ManagerFrame.NORMAL_PLAIN); + } + + private void configureAuthorsColumnLabel(JLabel label, Contribution contribution) { + if (contribution.isSpecial()) { + label.setIcon(foundationIcon); + } + String authorList = contribution.getAuthorList(); + String name = getAuthorNameWithoutMarkup(authorList); + label.setText(name); + label.setHorizontalAlignment(SwingConstants.LEFT); + label.setForeground(Color.BLACK); + label.setFont(ManagerFrame.NORMAL_BOLD); + } + } static private class ContribTableModel extends DefaultTableModel { @Override @@ -401,21 +366,20 @@ implements Scrollable, ContributionListing.ChangeListener { } } - String getAuthorNameWithoutMarkup(String authorList) { StringBuilder name = new StringBuilder(""); if (authorList != null) { + int parentheses = 0; for (int i = 0; i < authorList.length(); i++) { if (authorList.charAt(i) == '[' || authorList.charAt(i) == ']') { continue; } if (authorList.charAt(i) == '(') { - i++; - while (authorList.charAt(i) != ')') { - i++; - } - } else { + parentheses++; + } else if (authorList.charAt(i) == ')') { + parentheses--; + } else if (parentheses == 0) { name.append(authorList.charAt(i)); } } @@ -441,17 +405,15 @@ implements Scrollable, ContributionListing.ChangeListener { // Thread: EDT public void contributionAdded(final Contribution contribution) { - if (filter.matches(contribution)) { - if (!panelByContribution.containsKey(contribution)) { - DetailPanel newPanel = - new DetailPanel(ListPanel.this); - panelByContribution.put(contribution, newPanel); - visibleContributions.add(contribution); - newPanel.setContribution(contribution); - add(newPanel); - updatePanelOrdering(visibleContributions); - updateColors(); // XXX this is the place - } + if (filter.matches(contribution) && !panelByContribution.containsKey(contribution)) { + DetailPanel newPanel = + new DetailPanel(ListPanel.this); + panelByContribution.put(contribution, newPanel); + visibleContributions.add(contribution); + newPanel.setContribution(contribution); + add(newPanel); + updatePanelOrdering(visibleContributions); + updateColors(); // XXX this is the place } } @@ -497,14 +459,12 @@ implements Scrollable, ContributionListing.ChangeListener { public void filterLibraries(List filteredContributions) { visibleContributions.clear(); for (Contribution contribution : panelByContribution.keySet()) { - if (contribution.getType() == contributionTab.contribType) { + if (contribution.getType() == contributionTab.contribType + && filteredContributions.contains(contribution) + && panelByContribution.keySet().contains(contribution)) { // contains() uses equals() and there can be multiple instances, // so Contribution.equals() has to be overridden - if (filteredContributions.contains(contribution)) { - if (panelByContribution.keySet().contains(contribution)) { - visibleContributions.add(contribution); - } - } + visibleContributions.add(contribution); } } // TODO: Make the following loop work for optimization @@ -554,38 +514,35 @@ implements Scrollable, ContributionListing.ChangeListener { int count = 0; for (Entry entry : panelByContribution.entrySet()) { DetailPanel panel = entry.getValue(); + Border border = BorderFactory.createEmptyBorder(1, 1, 1, 1); - if (panel.isVisible() && panel.isSelected()) { - panel.setBackground(UIManager.getColor("List.selectionBackground")); - panel.setForeground(UIManager.getColor("List.selectionForeground")); - panel.setBorder(UIManager.getBorder("List.focusCellHighlightBorder")); + if (panel.isVisible()) { + boolean oddRow = count % 2 == 1; + Color bgColor = null; + Color fgColor = UIManager.getColor("List.foreground"); + + if (panel.isSelected()) { + bgColor = UIManager.getColor("List.selectionBackground"); + fgColor = UIManager.getColor("List.selectionForeground"); + border = UIManager.getBorder("List.focusCellHighlightBorder"); + } else if (Platform.isMacOS()) { + border = oddRow + ? UIManager.getBorder("List.oddRowBackgroundPainter") + : UIManager.getBorder("List.evenRowBackgroundPainter"); + } else { + bgColor = oddRow + ? new Color(219, 224, 229) + : new Color(241, 241, 241); + } + + panel.setForeground(fgColor); + if (bgColor != null) { + panel.setBackground(bgColor); + } count++; - - } else { - Border border = null; - if (panel.isVisible()) { - if (Platform.isMacOS()) { - if (count % 2 == 1) { - border = UIManager.getBorder("List.oddRowBackgroundPainter"); - } else { - border = UIManager.getBorder("List.evenRowBackgroundPainter"); - } - } else { - if (count % 2 == 1) { - panel.setBackground(new Color(219, 224, 229)); - } else { - panel.setBackground(new Color(241, 241, 241)); - } - } - count++; - } - - if (border == null) { - border = BorderFactory.createEmptyBorder(1, 1, 1, 1); - } - panel.setBorder(border); - panel.setForeground(UIManager.getColor("List.foreground")); } + + panel.setBorder(border); } } @@ -623,39 +580,38 @@ implements Scrollable, ContributionListing.ChangeListener { */ @Override public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { - if (orientation == SwingConstants.VERTICAL) { - int lastHeight = 0, height = 0; - int bottomOfScrollArea = visibleRect.y + visibleRect.height; + if (orientation != SwingConstants.VERTICAL) { + return 0; + } + int lastHeight = 0; + int height = 0; + int bottomOfScrollArea = visibleRect.y + visibleRect.height; - for (Component c : getComponents()) { - if (c.isVisible()) { - if (c instanceof DetailPanel) { - Dimension d = c.getPreferredSize(); + for (Component c : getComponents()) { + if (!(c.isVisible() && c instanceof DetailPanel)) { + continue; + } + Dimension d = c.getPreferredSize(); - int nextHeight = height + d.height; + int nextHeight = height + d.height; - if (direction > 0) { - // scrolling down - if (nextHeight > bottomOfScrollArea) { - return nextHeight - bottomOfScrollArea; - } - } else { - // scrolling up - if (nextHeight > visibleRect.y) { - if (visibleRect.y != height) { - return visibleRect.y - height; - } else { - return visibleRect.y - lastHeight; - } - } - } - - lastHeight = height; - height = nextHeight; - } + if (direction > 0) { + // scrolling down + if (nextHeight > bottomOfScrollArea) { + return nextHeight - bottomOfScrollArea; + } + } else if (nextHeight > visibleRect.y) { + if (visibleRect.y != height) { + return visibleRect.y - height; + } else { + return visibleRect.y - lastHeight; } } + + lastHeight = height; + height = nextHeight; } + return 0; } diff --git a/app/src/processing/app/contrib/UpdateListPanel.java b/app/src/processing/app/contrib/UpdateListPanel.java index 11b23bfd6..739927852 100644 --- a/app/src/processing/app/contrib/UpdateListPanel.java +++ b/app/src/processing/app/contrib/UpdateListPanel.java @@ -29,7 +29,7 @@ public class UpdateListPanel extends ListPanel { ContributionType.TOOL.getPluralTitle(), ContributionType.EXAMPLES.getPluralTitle(), }; - Set sectionNames = new HashSet(Arrays.asList(PLURAL_TYPES)); + Set sectionNames = new HashSet<>(Arrays.asList(PLURAL_TYPES)); public UpdateListPanel(ContributionTab contributionTab, Contribution.Filter filter) { @@ -134,18 +134,8 @@ public class UpdateListPanel extends ListPanel { setLayout(layout); table.setVisible(true); - panelByContribution = new TreeMap(new Comparator() { - @Override - public int compare(Contribution o1, Contribution o2) { - int diff = - ContributionManager.getTypeIndex(o1.getType()) - - ContributionManager.getTypeIndex(o2.getType()); - if (diff == 0) { - diff = o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase()); - } - return diff; - } - }); + panelByContribution = new TreeMap<>(Comparator.comparingInt(c -> ContributionManager.getTypeIndex(((Contribution) c).getType())) + .thenComparing(c -> ((Contribution) c).getName().toLowerCase())); } // Thread: EDT @@ -163,24 +153,7 @@ public class UpdateListPanel extends ListPanel { null, currentType.getPluralTitle(), null, null, null }); } - //TODO Make this into a function - StringBuilder name = new StringBuilder(""); - String authorList = entry.getAuthorList(); - if (authorList != null) { - for (int i = 0; i < authorList.length(); i++) { - if (authorList.charAt(i) == '[' || authorList.charAt(i) == ']') { - continue; - } - if (authorList.charAt(i) == '(') { - i++; - while (authorList.charAt(i) != ')') { - i++; - } - } else { - name.append(authorList.charAt(i)); - } - } - } + String name = getAuthorNameWithoutMarkup(entry.getAuthorList()); Icon icon = null; if (entry.isInstalled()) { icon = upToDateIcon; From 062774b119dd0a2f703fe939a8450617399a7b03 Mon Sep 17 00:00:00 2001 From: Sigmund Hansen Date: Mon, 29 Oct 2018 00:15:12 +0100 Subject: [PATCH 2/3] Fixes other panels except the update panel of #5524. --- .../app/contrib/ContributionListing.java | 59 +----- .../app/contrib/ContributionTab.java | 21 +- app/src/processing/app/contrib/ListPanel.java | 127 ++++++------ .../app/contrib/UpdateListPanel.java | 184 +----------------- 4 files changed, 78 insertions(+), 313 deletions(-) diff --git a/app/src/processing/app/contrib/ContributionListing.java b/app/src/processing/app/contrib/ContributionListing.java index e5fe94273..a4dbf813b 100644 --- a/app/src/processing/app/contrib/ContributionListing.java +++ b/app/src/processing/app/contrib/ContributionListing.java @@ -53,18 +53,18 @@ public class ContributionListing { Map librariesByImportHeader; // TODO: Every contribution is getting added twice // and nothing is replaced ever. - List allContributions; + Set allContributions; boolean listDownloaded; boolean listDownloadFailed; ReentrantLock downloadingListingLock; private ContributionListing() { - listeners = new ArrayList(); - advertisedContributions = new ArrayList(); - librariesByCategory = new HashMap>(); - librariesByImportHeader = new HashMap(); - allContributions = new ArrayList(); + listeners = new ArrayList<>(); + advertisedContributions = new ArrayList<>(); + librariesByCategory = new HashMap<>(); + librariesByImportHeader = new HashMap<>(); + allContributions = new LinkedHashSet<>(); downloadingListingLock = new ReentrantLock(); //listingFile = Base.getSettingsFile("contributions.txt"); @@ -96,7 +96,6 @@ public class ContributionListing { for (Contribution contribution : advertisedContributions) { addContribution(contribution); } - Collections.sort(allContributions, COMPARATOR); } @@ -139,11 +138,8 @@ public class ContributionListing { } } - for (int i = 0; i < allContributions.size(); i++) { - if (allContributions.get(i) == oldLib) { - allContributions.set(i, newLib); - } - } + allContributions.remove(oldLib); + allContributions.add(newLib); notifyChange(oldLib, newLib); } @@ -169,7 +165,6 @@ public class ContributionListing { } allContributions.add(contribution); notifyAdd(contribution); - Collections.sort(allContributions, COMPARATOR); } } @@ -234,43 +229,7 @@ public class ContributionListing { } -// public List getAllContributions() { -// return new ArrayList(allContributions); -// } - - -// public List getLibararies(String category) { -// ArrayList libinfos = -// new ArrayList(librariesByCategory.get(category)); -// Collections.sort(libinfos, nameComparator); -// return libinfos; -// } - - - protected List getFilteredLibraryList(String category, List filters) { - ArrayList filteredList = - new ArrayList(allContributions); - - Iterator it = filteredList.iterator(); - while (it.hasNext()) { - Contribution libInfo = it.next(); - //if (category != null && !category.equals(libInfo.getCategory())) { - if (category != null && !libInfo.hasCategory(category)) { - it.remove(); - } else { - for (String filter : filters) { - if (!matches(libInfo, filter)) { - it.remove(); - break; - } - } - } - } - return filteredList; - } - - - private boolean matches(Contribution contrib, String typed) { + public boolean matches(Contribution contrib, String typed) { int colon = typed.indexOf(":"); if (colon != -1) { String isText = typed.substring(0, colon); diff --git a/app/src/processing/app/contrib/ContributionTab.java b/app/src/processing/app/contrib/ContributionTab.java index 532d7f9ed..d00277cb2 100644 --- a/app/src/processing/app/contrib/ContributionTab.java +++ b/app/src/processing/app/contrib/ContributionTab.java @@ -73,11 +73,7 @@ public class ContributionTab extends JPanel { this.contribDialog = dialog; this.contribType = type; - filter = new Contribution.Filter() { - public boolean matches(Contribution contrib) { - return contrib.getType() == contribType; - } - }; + filter = contrib -> contrib.getType() == contribType; contribListing = ContributionListing.getInstance(); statusPanel = new StatusPanel(this, 650); @@ -85,12 +81,6 @@ public class ContributionTab extends JPanel { contribListing.addListener(contributionListPanel); } - -// public boolean hasUpdates(Base base) { -// return contribListing.hasUpdates(base); -// } - - public void showFrame(final Editor editor, boolean error, boolean loading) { this.editor = editor; @@ -277,9 +267,7 @@ public class ContributionTab extends JPanel { protected void filterLibraries(String category, List filters) { - List filteredLibraries = - contribListing.getFilteredLibraryList(category, filters); - contributionListPanel.filterLibraries(filteredLibraries); + contributionListPanel.filterLibraries(category, filters); } @@ -449,11 +437,8 @@ public class ContributionTab extends JPanel { contributionListPanel.panelByContribution.values(); for (DetailPanel detailPanel : collection) { detailPanel.update(); - - // Refreshing the ContributionUpdateTab's status icons - contributionListPanel.updatePanelOrdering(contributionListPanel - .panelByContribution.keySet()); } + contributionListPanel.model.fireTableDataChanged(); } diff --git a/app/src/processing/app/contrib/ListPanel.java b/app/src/processing/app/contrib/ListPanel.java index 2acb690b2..c83fc4773 100644 --- a/app/src/processing/app/contrib/ListPanel.java +++ b/app/src/processing/app/contrib/ListPanel.java @@ -46,13 +46,12 @@ public class ListPanel extends JPanel implements Scrollable, ContributionListing.ChangeListener { ContributionTab contributionTab; TreeMap panelByContribution = new TreeMap<>(ContributionListing.COMPARATOR); - Set visibleContributions = new TreeSet<>(ContributionListing.COMPARATOR); private DetailPanel selectedPanel; - protected Contribution.Filter filter; + protected ContributionRowFilter filter; protected ContributionListing contribListing = ContributionListing.getInstance(); protected JTable table; - DefaultTableModel model; + ContributionTableModel model; JScrollPane scrollPane; static Icon upToDateIcon; @@ -77,14 +76,15 @@ implements Scrollable, ContributionListing.ChangeListener { public ListPanel(final ContributionTab contributionTab, - Contribution.Filter filter) { + final Contribution.Filter filter) { + this(); this.contributionTab = contributionTab; - this.filter = filter; + this.filter = new ContributionRowFilter(filter); setLayout(new GridBagLayout()); setOpaque(true); setBackground(Color.WHITE); - model = new ContribTableModel(); + model = new ContributionTableModel(); table = new JTable(model) { @Override public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { @@ -99,8 +99,6 @@ implements Scrollable, ContributionListing.ChangeListener { }; // There is a space before Status - String[] colName = { " Status", "Name", "Author" }; - model.setColumnIdentifiers(colName); scrollPane = new JScrollPane(table); scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); scrollPane.setBorder(BorderFactory.createEmptyBorder()); @@ -135,8 +133,9 @@ implements Scrollable, ContributionListing.ChangeListener { } }); - TableRowSorter sorter = new TableRowSorter<>(table.getModel()); + TableRowSorter sorter = new TableRowSorter<>(model); table.setRowSorter(sorter); + sorter.setRowFilter(this.filter); sorter.setComparator(1, ContributionListing.COMPARATOR); sorter.setComparator(2, Comparator.comparing(o -> getAuthorNameWithoutMarkup(((Contribution) o).getAuthorList()))); sorter.setComparator(0, Comparator.comparingInt(o -> getContributionStatusRank((Contribution) o))); @@ -354,16 +353,62 @@ implements Scrollable, ContributionListing.ChangeListener { } } - static private class ContribTableModel extends DefaultTableModel { + protected class ContributionTableModel extends AbstractTableModel { @Override - public boolean isCellEditable(int row, int column) { - return false; + public int getRowCount() { + return contribListing.allContributions.size(); + } + + @Override + public int getColumnCount() { + return 3; + } + + @Override + public String getColumnName(int column) { + switch (column) { + case 0: return " Status"; // Note the space + case 1: return "Name"; + case 2: return "Author"; + default: return ""; + } } @Override public Class getColumnClass(int columnIndex) { return Contribution.class; } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return contribListing.allContributions.stream().skip(rowIndex).findFirst().get(); + } + } + + protected class ContributionRowFilter extends RowFilter { + Contribution.Filter contributionFilter; + Optional categoryFilter = Optional.empty(); + List stringFilters = Collections.emptyList(); + + ContributionRowFilter(Contribution.Filter contributionFilter) { + this.contributionFilter = contributionFilter; + } + + public void setCategoryFilter(String categoryFilter) { + this.categoryFilter = Optional.ofNullable(categoryFilter); + } + + public void setStringFilters(List filters) { + this.stringFilters = filters; + } + + @Override + public boolean include(Entry entry) { + Contribution contribution = (Contribution) entry.getValue(0); + return contributionFilter.matches(contribution) + && categoryFilter.map(contribution::hasCategory).orElse(true) + && stringFilters.stream().allMatch(pattern -> contribListing.matches(contribution, pattern)); + } } String getAuthorNameWithoutMarkup(String authorList) { @@ -387,32 +432,15 @@ implements Scrollable, ContributionListing.ChangeListener { return name.toString(); } - // Thread: EDT - void updatePanelOrdering(Set contributionsSet) { - model.getDataVector().removeAllElements(); - int rowCount = 0; - for (Contribution entry : contributionsSet) { - model.addRow(new Object[]{entry, entry, entry}); - if (selectedPanel != null && - entry.getName().equals(selectedPanel.getContrib().getName())) { - table.setRowSelectionInterval(rowCount, rowCount); - } - rowCount++; - } - model.fireTableDataChanged(); - } - - // Thread: EDT public void contributionAdded(final Contribution contribution) { - if (filter.matches(contribution) && !panelByContribution.containsKey(contribution)) { + if (!panelByContribution.containsKey(contribution)) { DetailPanel newPanel = new DetailPanel(ListPanel.this); panelByContribution.put(contribution, newPanel); - visibleContributions.add(contribution); newPanel.setContribution(contribution); add(newPanel); - updatePanelOrdering(visibleContributions); + model.fireTableDataChanged(); updateColors(); // XXX this is the place } } @@ -420,24 +448,20 @@ implements Scrollable, ContributionListing.ChangeListener { // Thread: EDT public void contributionRemoved(final Contribution contribution) { - if (filter.matches(contribution)) { DetailPanel panel = panelByContribution.get(contribution); if (panel != null) { remove(panel); panelByContribution.remove(contribution); } - visibleContributions.remove(contribution); - updatePanelOrdering(visibleContributions); + model.fireTableDataChanged(); updateColors(); updateUI(); - } } // Thread: EDT public void contributionChanged(final Contribution oldContrib, final Contribution newContrib) { - if (filter.matches(oldContrib) || filter.matches(newContrib)) { DetailPanel panel = panelByContribution.get(oldContrib); if (panel == null) { contributionAdded(newContrib); @@ -445,37 +469,16 @@ implements Scrollable, ContributionListing.ChangeListener { panelByContribution.remove(oldContrib); panel.setContribution(newContrib); panelByContribution.put(newContrib, panel); + model.fireTableDataChanged(); } - if (visibleContributions.contains(oldContrib)) { - visibleContributions.remove(oldContrib); - visibleContributions.add(newContrib); - } - updatePanelOrdering(visibleContributions); - } } // Thread: EDT - public void filterLibraries(List filteredContributions) { - visibleContributions.clear(); - for (Contribution contribution : panelByContribution.keySet()) { - if (contribution.getType() == contributionTab.contribType - && filteredContributions.contains(contribution) - && panelByContribution.keySet().contains(contribution)) { - // contains() uses equals() and there can be multiple instances, - // so Contribution.equals() has to be overridden - visibleContributions.add(contribution); - } - } - // TODO: Make the following loop work for optimization -// for (Contribution contribution : filteredContributions) { -// if (contribution.getType() == contributionTab.contribType) { -// if(panelByContribution.keySet().contains(contribution)){ -// visibleContributions.add(contribution); -// } -// } -// } - updatePanelOrdering(visibleContributions); + public void filterLibraries(String category, List filters) { + filter.setCategoryFilter(category); + filter.setStringFilters(filters); + model.fireTableDataChanged(); } diff --git a/app/src/processing/app/contrib/UpdateListPanel.java b/app/src/processing/app/contrib/UpdateListPanel.java index 739927852..60c7c36d0 100644 --- a/app/src/processing/app/contrib/UpdateListPanel.java +++ b/app/src/processing/app/contrib/UpdateListPanel.java @@ -33,188 +33,6 @@ public class UpdateListPanel extends ListPanel { public UpdateListPanel(ContributionTab contributionTab, Contribution.Filter filter) { - this.contributionTab = contributionTab; - this.filter = filter; - - setOpaque(true); - setBackground(Color.WHITE); - - model = new DefaultTableModel() { - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - - @Override - public Class getColumnClass(int columnIndex) { - return (columnIndex == 0) ? Icon.class : String.class; - } - }; - - model.setColumnIdentifiers(new String[] { - "", "Name", "Author", "Installed", "Available" - }); - - table = new JTable(model) { - @Override - public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { - Component c = super.prepareRenderer(renderer, row, column); - String title = (String) getValueAt(row, 1); - if (sectionNames.contains(title)) { - c.setBackground(SECTION_COLOR); - } else { - c.setBackground(Color.WHITE); - } - return c; - } - - @Override - public void changeSelection(int rowIndex, int columnIndex, - boolean toggle, boolean extend) { - String title = (String) getValueAt(rowIndex, 1); - // Disallow selection on the fake rows - if (!sectionNames.contains(title)) { - super.changeSelection(rowIndex, columnIndex, toggle, extend); - } - } - }; - - scrollPane = new JScrollPane(table); - scrollPane.setBorder(BorderFactory.createEmptyBorder()); - - table.setFillsViewportHeight(true); - table.setSelectionBackground(new Color(0xe0fffd)); - table.setSelectionForeground(table.getForeground()); - table.setFont(ManagerFrame.NORMAL_PLAIN); - table.setRowHeight(30); - table.setRowMargin(6); - table.getColumnModel().setColumnMargin(-1); - table.getColumnModel().getColumn(0).setMaxWidth(60); - table.setShowGrid(false); - table.setCellSelectionEnabled(false); - table.setRowSelectionAllowed(true); - table.setAutoCreateColumnsFromModel(true); - table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - - table.setDefaultRenderer(String.class, new DefaultTableCellRenderer() { - @Override - public Component getTableCellRendererComponent(JTable table, - Object value, - boolean isSelected, - boolean hasFocus, - int row, int column) { - return super.getTableCellRendererComponent(table, value, isSelected, - false, row, column); - } - }); - - table.getTableHeader().setDefaultRenderer(new ContribHeaderRenderer()); /* { - @Override - public Component getTableCellRendererComponent(JTable table, - Object value, - boolean isSelected, - boolean hasFocus, int row, - int column) { - super.getTableCellRendererComponent(table, value, isSelected, - hasFocus, row, column); - JTableHeader tableHeader = table.getTableHeader(); - if (tableHeader != null) { - setForeground(tableHeader.getForeground()); - } - setIcon(getSortIcon(table, column)); - setBackground(new Color(0xebebeb)); - return this; - } - });*/ - - GroupLayout layout = new GroupLayout(this); - layout.setHorizontalGroup(layout.createParallelGroup().addComponent(scrollPane)); - layout.setVerticalGroup(layout.createSequentialGroup().addComponent(scrollPane)); - - setLayout(layout); - table.setVisible(true); - - panelByContribution = new TreeMap<>(Comparator.comparingInt(c -> ContributionManager.getTypeIndex(((Contribution) c).getType())) - .thenComparing(c -> ((Contribution) c).getName().toLowerCase())); - } - - // Thread: EDT - @Override - void updatePanelOrdering(Set contributionsSet) { - model.getDataVector().removeAllElements(); - ContributionType currentType = null; - - String fontFace = ""; - - for (Contribution entry : contributionsSet) { - if (entry.getType() != currentType) { - currentType = entry.getType(); - model.addRow(new Object[] { - null, currentType.getPluralTitle(), null, null, null - }); - } - String name = getAuthorNameWithoutMarkup(entry.getAuthorList()); - Icon icon = null; - if (entry.isInstalled()) { - icon = upToDateIcon; - if (contribListing.hasUpdates(entry)) { - icon = updateAvailableIcon; - } - if (!entry.isCompatible(Base.getRevision())) { - icon = incompatibleIcon; - } - } - if ((panelByContribution.get(entry)).updateInProgress || - (panelByContribution.get(entry)).installInProgress) { - // Display "Loading icon" if download/install in progress - icon = downloadingIcon; - } - model.addRow(new Object[] { - icon, - "" + fontFace + entry.getName() + "", - name, - entry.getBenignVersion(), - contributionTab.contribListing.getLatestPrettyVersion(entry) - }); - } - model.fireTableDataChanged(); - UpdateContributionTab tab = (UpdateContributionTab) contributionTab; - ((UpdateStatusPanel) tab.statusPanel).update(); - } - - - // Thread: EDT - @Override - public void contributionAdded(final Contribution contribution) { - if (filter.matches(contribution)) { - // TODO make this longer and more contorted [fry] - DetailPanel newPanel = - contributionTab.contribDialog.getTab(contribution.getType()).contributionListPanel.panelByContribution.get(contribution); - if (newPanel == null) { - newPanel = new DetailPanel(UpdateListPanel.this); - } - if (!panelByContribution.containsKey(contribution)) { - panelByContribution.put(contribution, newPanel); - } - visibleContributions.add(contribution); - newPanel.setContribution(contribution); - add(newPanel); - updatePanelOrdering(panelByContribution.keySet()); - updateColors(); // XXX this is the place - } - } - - // Thread: EDT - @Override - public void contributionChanged(final Contribution oldContrib, - final Contribution newContrib) { - DetailPanel panel = panelByContribution.get(oldContrib); - if (panel == null) { - contributionAdded(newContrib); - } else if (newContrib.isInstalled()) { - panelByContribution.remove(oldContrib); - visibleContributions.remove(oldContrib); - } - updatePanelOrdering(visibleContributions); + super(contributionTab, filter); } } From 213a9e4bd62b1fa04029e43e255d553ef02cc19f Mon Sep 17 00:00:00 2001 From: Sigmund Hansen Date: Sun, 30 Dec 2018 14:47:10 +0100 Subject: [PATCH 3/3] Fixes update panel in #5524. --- .../app/contrib/ContributionListing.java | 6 +- .../app/contrib/ContributionTab.java | 6 +- app/src/processing/app/contrib/ListPanel.java | 196 ++++++++++++++---- .../processing/app/contrib/ManagerFrame.java | 2 +- .../app/contrib/UpdateContributionTab.java | 21 +- .../app/contrib/UpdateListPanel.java | 72 ++++--- 6 files changed, 223 insertions(+), 80 deletions(-) diff --git a/app/src/processing/app/contrib/ContributionListing.java b/app/src/processing/app/contrib/ContributionListing.java index a4dbf813b..c20b4dc40 100644 --- a/app/src/processing/app/contrib/ContributionListing.java +++ b/app/src/processing/app/contrib/ContributionListing.java @@ -560,11 +560,7 @@ public class ContributionListing { } - static public Comparator COMPARATOR = new Comparator() { - public int compare(Contribution o1, Contribution o2) { - return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase()); - } - }; + static public Comparator COMPARATOR = Comparator.comparing(o -> o.getName().toLowerCase()); public interface ChangeListener { diff --git a/app/src/processing/app/contrib/ContributionTab.java b/app/src/processing/app/contrib/ContributionTab.java index d00277cb2..9028e0644 100644 --- a/app/src/processing/app/contrib/ContributionTab.java +++ b/app/src/processing/app/contrib/ContributionTab.java @@ -77,7 +77,7 @@ public class ContributionTab extends JPanel { contribListing = ContributionListing.getInstance(); statusPanel = new StatusPanel(this, 650); - contributionListPanel = new ListPanel(this, filter); + contributionListPanel = new ListPanel(this, filter, false); contribListing.addListener(contributionListPanel); } @@ -445,4 +445,8 @@ public class ContributionTab extends JPanel { protected boolean hasUpdates() { return contributionListPanel.getRowCount() > 0; } + + public boolean filterHasFocus() { + return filterField != null && filterField.hasFocus(); + } } diff --git a/app/src/processing/app/contrib/ListPanel.java b/app/src/processing/app/contrib/ListPanel.java index c83fc4773..cf73db21d 100644 --- a/app/src/processing/app/contrib/ListPanel.java +++ b/app/src/processing/app/contrib/ListPanel.java @@ -35,6 +35,7 @@ import javax.swing.table.*; import processing.app.Base; import processing.app.Platform; import processing.app.ui.Toolkit; +import sun.swing.SwingUtilities2; // The "Scrollable" implementation and its methods here take care of preventing @@ -49,8 +50,8 @@ implements Scrollable, ContributionListing.ChangeListener { private DetailPanel selectedPanel; protected ContributionRowFilter filter; - protected ContributionListing contribListing = ContributionListing.getInstance(); protected JTable table; + protected TableRowSorter sorter; ContributionTableModel model; JScrollPane scrollPane; @@ -62,7 +63,15 @@ implements Scrollable, ContributionListing.ChangeListener { // Should this be in theme.txt? Of course! Is it? No. static final Color HEADER_BGCOLOR = new Color(0xffEBEBEB); + static final Color SECTION_COLOR = new Color(0xFFf8f8f8); + static final Color SELECTION_COLOR = new Color(0xffe0fffd); + static final SectionHeaderContribution[] sections = { + new SectionHeaderContribution(ContributionType.LIBRARY), + new SectionHeaderContribution(ContributionType.MODE), + new SectionHeaderContribution(ContributionType.TOOL), + new SectionHeaderContribution(ContributionType.EXAMPLES) + }; public ListPanel() { if (upToDateIcon == null) { @@ -76,7 +85,9 @@ implements Scrollable, ContributionListing.ChangeListener { public ListPanel(final ContributionTab contributionTab, - final Contribution.Filter filter) { + final Contribution.Filter filter, + final boolean enableSections, + final ContributionColumn... columns) { this(); this.contributionTab = contributionTab; this.filter = new ContributionRowFilter(filter); @@ -84,18 +95,29 @@ implements Scrollable, ContributionListing.ChangeListener { setLayout(new GridBagLayout()); setOpaque(true); setBackground(Color.WHITE); - model = new ContributionTableModel(); + model = new ContributionTableModel(columns); + model.enableSections(enableSections); table = new JTable(model) { @Override public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { Component c = super.prepareRenderer(renderer, row, column); - if (isRowSelected(row)) { - c.setBackground(new Color(0xe0fffd)); + Object rowValue = getValueAt(row, column); + if (rowValue instanceof SectionHeaderContribution) { + c.setBackground(SECTION_COLOR); + } else if (isRowSelected(row)) { + c.setBackground(SELECTION_COLOR); } else { c.setBackground(Color.white); } return c; } + + @Override + public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) { + if (!(getValueAt(rowIndex, columnIndex) instanceof SectionHeaderContribution)) { + super.changeSelection(rowIndex, columnIndex, toggle, extend); + } + } }; // There is a space before Status @@ -126,19 +148,22 @@ implements Scrollable, ContributionListing.ChangeListener { setSelectedPanel(panelByContribution.get(table.getValueAt(table .getSelectedRow(), 0))); // Preventing the focus to move out of filterField after typing every character - if (!contributionTab.filterField.hasFocus()) { + if (!contributionTab.filterHasFocus()) { table.requestFocusInWindow(); } } } }); - TableRowSorter sorter = new TableRowSorter<>(model); + sorter = new TableRowSorter<>(model); table.setRowSorter(sorter); sorter.setRowFilter(this.filter); - sorter.setComparator(1, ContributionListing.COMPARATOR); - sorter.setComparator(2, Comparator.comparing(o -> getAuthorNameWithoutMarkup(((Contribution) o).getAuthorList()))); - sorter.setComparator(0, Comparator.comparingInt(o -> getContributionStatusRank((Contribution) o))); + for (int i=0; i < model.getColumnCount(); i++) { + if (model.columns[i] == ContributionColumn.NAME) { + sorter.setSortKeys(Collections.singletonList(new SortKey(i, SortOrder.ASCENDING))); + } + sorter.setComparator(i, model.columns[i].getComparator()); + } table.getTableHeader().setDefaultRenderer(new ContribHeaderRenderer()); GroupLayout layout = new GroupLayout(this); @@ -149,11 +174,11 @@ implements Scrollable, ContributionListing.ChangeListener { table.setVisible(true); } - private int getContributionStatusRank(Contribution c) { + private static int getContributionStatusRank(Contribution c) { int pos = 4; if (c.isInstalled()) { pos = 1; - if (contribListing.hasUpdates(c)) { + if (ContributionListing.getInstance().hasUpdates(c)) { pos = 2; } if (!c.isCompatible(Base.getRevision())) { @@ -262,27 +287,41 @@ implements Scrollable, ContributionListing.ChangeListener { int column) { Contribution contribution = (Contribution) value; JLabel label = new JLabel(); + ContributionColumn col = model.columns[column]; if (value == null) { // Working on https://github.com/processing/processing/issues/3667 //System.err.println("null value seen in getTableCellRendererComponent()"); // TODO this is now working, but the underlying issue is not fixed return label; } - if (isSelected) { - label.setBackground(new Color(0xe0fffd)); + + label.setOpaque(true); + + if (value instanceof SectionHeaderContribution && col != ContributionColumn.NAME) { + return label; } - if (column == 0) { - configureStatusColumnLabel(label, contribution); - } else if (column == 1) { - configureNameColumnLabel(table, label, contribution); - } else { - configureAuthorsColumnLabel(label, contribution); + switch (col) { + case STATUS: + case STATUS_NO_HEADER: + configureStatusColumnLabel(label, contribution); + break; + case NAME: + configureNameColumnLabel(table, label, contribution); + break; + case AUTHOR: + configureAuthorsColumnLabel(label, contribution); + break; + case INSTALLED_VERSION: + label.setText(contribution.getBenignVersion()); + break; + case AVAILABLE_VERSION: + label.setText(ContributionListing.getInstance().getLatestPrettyVersion(contribution)); + break; } if(!contribution.isCompatible(Base.getRevision())){ label.setForeground(Color.LIGHT_GRAY); } - label.setOpaque(true); return label; } @@ -296,8 +335,11 @@ implements Scrollable, ContributionListing.ChangeListener { } else if (contribution.isInstalled()) { if (!contribution.isCompatible(Base.getRevision())) { icon = incompatibleIcon; - } else if (contribListing.hasUpdates(contribution)) { + } else if (ContributionListing.getInstance().hasUpdates(contribution)) { icon = updateAvailableIcon; + } else if (panelByContribution.get(contribution).installInProgress + || panelByContribution.get(contribution).updateInProgress) { + icon = downloadingIcon; } else { icon = upToDateIcon; } @@ -353,25 +395,64 @@ implements Scrollable, ContributionListing.ChangeListener { } } + protected enum ContributionColumn { + STATUS(" Status"), + NAME("Name"), + AUTHOR("Author"), + INSTALLED_VERSION("Installed"), + AVAILABLE_VERSION("Available"), + STATUS_NO_HEADER(""); + + final String name; + + ContributionColumn(String name) { + this.name = name; + } + + Comparator getComparator() { + Comparator comparator = Comparator.comparing(Contribution::getType) + .thenComparingInt(contribution -> contribution instanceof SectionHeaderContribution ? 0 : 1); + switch (this) { + case STATUS: + case STATUS_NO_HEADER: + return comparator.thenComparingInt(ListPanel::getContributionStatusRank); + case AUTHOR: + return comparator.thenComparing(contribution -> getAuthorNameWithoutMarkup(contribution.getAuthorList())); + case NAME: + default: + return comparator.thenComparing(Contribution::getName); + } + } + } + protected class ContributionTableModel extends AbstractTableModel { + + ContributionColumn[] columns = { ContributionColumn.STATUS, ContributionColumn.NAME, ContributionColumn.AUTHOR }; + boolean sectionsEnabled; + + ContributionTableModel(ContributionColumn... columns) { + if (columns.length > 0) { + this.columns = columns; + } + } + @Override public int getRowCount() { - return contribListing.allContributions.size(); + return ContributionListing.getInstance().allContributions.size() + (sectionsEnabled ? 4 : 0); } @Override public int getColumnCount() { - return 3; + return columns.length; } @Override public String getColumnName(int column) { - switch (column) { - case 0: return " Status"; // Note the space - case 1: return "Name"; - case 2: return "Author"; - default: return ""; + if (column < 0 || column > columns.length) { + return ""; } + + return columns[column].name; } @Override @@ -381,7 +462,19 @@ implements Scrollable, ContributionListing.ChangeListener { @Override public Object getValueAt(int rowIndex, int columnIndex) { - return contribListing.allContributions.stream().skip(rowIndex).findFirst().get(); + if (rowIndex >= ContributionListing.getInstance().allContributions.size()) { + return sections[rowIndex - ContributionListing.getInstance().allContributions.size()]; + } + + return ContributionListing.getInstance().allContributions.stream().skip(rowIndex).findFirst().orElse(null); + } + + public void setColumns(ContributionColumn[] columns) { + this.columns = columns; + } + + public void enableSections(boolean enable) { + this.sectionsEnabled = enable; } } @@ -405,14 +498,46 @@ implements Scrollable, ContributionListing.ChangeListener { @Override public boolean include(Entry entry) { Contribution contribution = (Contribution) entry.getValue(0); + if (contribution instanceof SectionHeaderContribution) { + return includeSection((SectionHeaderContribution) contribution); + } + return includeContribution(contribution); + } + + private boolean includeContribution(Contribution contribution) { return contributionFilter.matches(contribution) && categoryFilter.map(contribution::hasCategory).orElse(true) - && stringFilters.stream().allMatch(pattern -> contribListing.matches(contribution, pattern)); + && stringFilters.stream().allMatch(pattern -> ContributionListing.getInstance().matches(contribution, pattern)); + } + + private boolean includeSection(SectionHeaderContribution section) { + return ContributionListing.getInstance().allContributions.stream() + .filter(contribution -> contribution.getType() == section.getType()) + .anyMatch(this::includeContribution); } } - String getAuthorNameWithoutMarkup(String authorList) { - StringBuilder name = new StringBuilder(""); + protected static class SectionHeaderContribution extends Contribution { + ContributionType type; + + SectionHeaderContribution(ContributionType type) { + this.type = type; + this.name = getTypeName(); + } + + @Override + public ContributionType getType() { + return type; + } + + @Override + public boolean isInstalled() { + return false; + } + } + + static String getAuthorNameWithoutMarkup(String authorList) { + StringBuilder name = new StringBuilder(); if (authorList != null) { int parentheses = 0; for (int i = 0; i < authorList.length(); i++) { @@ -436,7 +561,7 @@ implements Scrollable, ContributionListing.ChangeListener { public void contributionAdded(final Contribution contribution) { if (!panelByContribution.containsKey(contribution)) { DetailPanel newPanel = - new DetailPanel(ListPanel.this); + new DetailPanel(this); panelByContribution.put(contribution, newPanel); newPanel.setContribution(contribution); add(newPanel); @@ -632,6 +757,7 @@ implements Scrollable, ContributionListing.ChangeListener { public int getRowCount() { - return panelByContribution.size(); + // This will count section headers, but it is only used to check if any rows are shown + return sorter.getViewRowCount(); } } diff --git a/app/src/processing/app/contrib/ManagerFrame.java b/app/src/processing/app/contrib/ManagerFrame.java index 85c36353e..3e25531bf 100644 --- a/app/src/processing/app/contrib/ManagerFrame.java +++ b/app/src/processing/app/contrib/ManagerFrame.java @@ -73,7 +73,7 @@ public class ManagerFrame { modesTab = new ContributionTab(this, ContributionType.MODE); toolsTab = new ContributionTab(this, ContributionType.TOOL); examplesTab = new ContributionTab(this, ContributionType.EXAMPLES); - updatesTab = new UpdateContributionTab(this, null); + updatesTab = new UpdateContributionTab(this); } diff --git a/app/src/processing/app/contrib/UpdateContributionTab.java b/app/src/processing/app/contrib/UpdateContributionTab.java index af4a8d288..a3de07f38 100644 --- a/app/src/processing/app/contrib/UpdateContributionTab.java +++ b/app/src/processing/app/contrib/UpdateContributionTab.java @@ -11,18 +11,18 @@ import processing.app.ui.Toolkit; public class UpdateContributionTab extends ContributionTab { - public UpdateContributionTab(ManagerFrame dialog, ContributionType type) { + public UpdateContributionTab(ManagerFrame dialog) { super(); this.contribDialog = dialog; - this.contribType = type; - filter = new Contribution.Filter() { - public boolean matches(Contribution contrib) { - if (contrib instanceof LocalContribution) { - return ContributionListing.getInstance().hasUpdates(contrib); - } - return false; + filter = contrib -> { + if (contrib instanceof ListPanel.SectionHeaderContribution) { + return true; } + if (contrib instanceof LocalContribution) { + return ContributionListing.getInstance().hasUpdates(contrib); + } + return false; }; contributionListPanel = new UpdateListPanel(this, filter); // contributionListPanel.setBorder(new EmptyBorder(8, 8, 8, 8)); @@ -67,4 +67,9 @@ public class UpdateContributionTab extends ContributionTab { setBackground(Color.WHITE); } + + @Override + public void updateStatusPanel(DetailPanel contributionPanel) { + // Do nothing + } } diff --git a/app/src/processing/app/contrib/UpdateListPanel.java b/app/src/processing/app/contrib/UpdateListPanel.java index 60c7c36d0..75bcca3b6 100644 --- a/app/src/processing/app/contrib/UpdateListPanel.java +++ b/app/src/processing/app/contrib/UpdateListPanel.java @@ -1,38 +1,50 @@ package processing.app.contrib; -import java.awt.Color; -import java.awt.Component; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Set; -import java.util.TreeMap; - -import javax.swing.BorderFactory; -import javax.swing.GroupLayout; -import javax.swing.Icon; -import javax.swing.JScrollPane; -import javax.swing.JTable; -import javax.swing.ListSelectionModel; -import javax.swing.table.DefaultTableCellRenderer; -import javax.swing.table.DefaultTableModel; -import javax.swing.table.TableCellRenderer; - -import processing.app.Base; - - public class UpdateListPanel extends ListPanel { - static final Color SECTION_COLOR = new Color(0xFFf8f8f8); - static final String[] PLURAL_TYPES = { - ContributionType.LIBRARY.getPluralTitle(), - ContributionType.MODE.getPluralTitle(), - ContributionType.TOOL.getPluralTitle(), - ContributionType.EXAMPLES.getPluralTitle(), - }; - Set sectionNames = new HashSet<>(Arrays.asList(PLURAL_TYPES)); + + Contribution.Filter filter; public UpdateListPanel(ContributionTab contributionTab, Contribution.Filter filter) { - super(contributionTab, filter); + super(contributionTab, filter, true, + ContributionColumn.STATUS_NO_HEADER, + ContributionColumn.NAME, + ContributionColumn.AUTHOR, + ContributionColumn.INSTALLED_VERSION, + ContributionColumn.AVAILABLE_VERSION); + + this.filter = filter; + table.getTableHeader().setEnabled(false); } + + // Thread: EDT + @Override + public void contributionAdded(final Contribution contribution) { + // Ensures contributionAdded in ListPanel is only run on LocalContributions + if (filter.matches(contribution)) { + super.contributionAdded(contribution); + ((UpdateStatusPanel) contributionTab.statusPanel).update(); // Enables update button + } + } + + // Thread: EDT + @Override + public void contributionRemoved(final Contribution contribution) { + super.contributionRemoved(contribution); + ((UpdateStatusPanel) contributionTab.statusPanel).update(); // Disables update button on last contribution + } + + // Thread: EDT + @Override + public void contributionChanged(final Contribution oldContrib, + final Contribution newContrib) { + DetailPanel panel = panelByContribution.get(oldContrib); + if (panel == null) { + contributionAdded(newContrib); + } else if (newContrib.isInstalled()) { + panelByContribution.remove(oldContrib); + } + model.fireTableDataChanged(); + } + }