From d5f39ee20e389c3b7727c5c165a96e8efd374633 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 22 Sep 2015 08:30:24 -0400 Subject: [PATCH] more scrubbing before redoing ContributionManagerDialog --- .../app/contrib/ContributionListing.java | 289 +++++++++--------- .../contrib/ContributionManagerDialog.java | 65 ++-- .../app/contrib/ContributionTab.java | 2 +- app/src/processing/app/contrib/ListPanel.java | 17 +- .../processing/app/contrib/StatusPanel.java | 4 +- .../app/contrib/UpdateContributionTab.java | 2 +- java/src/processing/mode/java/JavaEditor.java | 12 +- 7 files changed, 190 insertions(+), 201 deletions(-) diff --git a/app/src/processing/app/contrib/ContributionListing.java b/app/src/processing/app/contrib/ContributionListing.java index 1217ad792..d89087fed 100644 --- a/app/src/processing/app/contrib/ContributionListing.java +++ b/app/src/processing/app/contrib/ContributionListing.java @@ -36,20 +36,22 @@ import processing.data.StringDict; public class ContributionListing { - // Stable URL that will redirect to wherever we're hosting the file + static volatile ContributionListing singleInstance; + + /** Stable URL that will redirect to wherever the file is hosted */ static final String LISTING_URL = "http://download.processing.org/contribs"; static final String LOCAL_FILENAME = "contribs.txt"; - static volatile ContributionListing singleInstance; - + /** Location of the listing file on disk, will be read and written. */ File listingFile; + List listeners; List advertisedContributions; Map> librariesByCategory; - public Map librariesByImportHeader; + Map librariesByImportHeader; List allContributions; - boolean hasDownloadedLatestList; - boolean hasListDownloadFailed; + boolean listDownloaded; + boolean listDownloadFailed; ReentrantLock downloadingListingLock; @@ -70,7 +72,7 @@ public class ContributionListing { } - public static ContributionListing getInstance() { + static public ContributionListing getInstance() { if (singleInstance == null) { synchronized (ContributionListing.class) { if (singleInstance == null) { @@ -82,7 +84,7 @@ public class ContributionListing { } - void setAdvertisedList(File file) { + private void setAdvertisedList(File file) { listingFile = file; advertisedContributions.clear(); @@ -127,8 +129,8 @@ public class ContributionListing { if (oldLib.getImports() != null) { for (String importName : oldLib.getImports()) { - if (librariesByImportHeader.containsKey(importName)) { - librariesByImportHeader.put(importName, newLib); + if (getLibrariesByImportHeader().containsKey(importName)) { + getLibrariesByImportHeader().put(importName, newLib); } } } @@ -147,7 +149,7 @@ public class ContributionListing { private void addContribution(Contribution contribution) { if (contribution.getImports() != null) { for (String importName : contribution.getImports()) { - librariesByImportHeader.put(importName, contribution); + getLibrariesByImportHeader().put(importName, contribution); } } for (String category : contribution.getCategories()) { @@ -176,7 +178,7 @@ public class ContributionListing { } if (contribution.getImports() != null) { for (String importName : contribution.getImports()) { - librariesByImportHeader.remove(importName); + getLibrariesByImportHeader().remove(importName); } } allContributions.remove(contribution); @@ -196,9 +198,7 @@ public class ContributionListing { protected AvailableContribution getAvailableContribution(Contribution info) { - Iterator iter = advertisedContributions.iterator(); - while(iter.hasNext()) { - AvailableContribution advertised = iter.next(); + for (AvailableContribution advertised : advertisedContributions) { if (advertised.getType() == info.getType() && advertised.getName().equals(info.getName())) { return advertised; @@ -217,7 +217,7 @@ public class ContributionListing { if (filter.matches(contrib)) { // TODO still not sure why category would be coming back null [fry] // http://code.google.com/p/processing/issues/detail?id=1387 - if (categoryName != null && categoryName.trim().length() != 0) { + if (categoryName != null && !categoryName.trim().isEmpty()) { outgoing.add(categoryName); } break; @@ -264,11 +264,11 @@ public class ContributionListing { } - private boolean matches(Contribution contrib, String filter) { - int colon = filter.indexOf(":"); + private boolean matches(Contribution contrib, String typed) { + int colon = typed.indexOf(":"); if (colon != -1) { - String isText = filter.substring(0, colon); - String property = filter.substring(colon + 1); + String isText = typed.substring(0, colon); + String property = typed.substring(colon + 1); // Chances are the person is still typing the property, so rather than // make the list flash empty (because nothing contains "is:" or "has:", @@ -278,28 +278,37 @@ public class ContributionListing { } if ("is".equals(isText) || "has".equals(isText)) { - return hasProperty(contrib, filter.substring(colon + 1)); + return hasProperty(contrib, typed.substring(colon + 1)); } else if ("not".equals(isText)) { - return !hasProperty(contrib, filter.substring(colon + 1)); + return !hasProperty(contrib, typed.substring(colon + 1)); } } - filter = ".*" + filter.toLowerCase() + ".*"; + typed = ".*" + typed.toLowerCase() + ".*"; - return contrib.getAuthorList() != null && deAccent(contrib.getAuthorList().toLowerCase()).matches(filter) - || contrib.getSentence() != null && deAccent(contrib.getSentence().toLowerCase()).matches(filter) - || contrib.getParagraph() != null && deAccent(contrib.getParagraph().toLowerCase()).matches(filter) - || contrib.hasCategory(filter) - || contrib.getName() != null && deAccent(contrib.getName().toLowerCase()).matches(filter); + return (matchField(contrib.getName(), typed) || + matchField(contrib.getAuthorList(), typed) || + matchField(contrib.getSentence(), typed) || + matchField(contrib.getParagraph(), typed) || + contrib.hasCategory(typed)); } - public String deAccent(String str) { + + static private boolean matchField(String field, String typed) { + return (field != null) && + removeAccents(field.toLowerCase()).matches(typed); + } + + + // TODO is this removing characters with accents, not ascii normalizing them? [fry] + static private String removeAccents(String str) { String nfdNormalizedString = Normalizer.normalize(str, Normalizer.Form.NFD); Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); return pattern.matcher(nfdNormalizedString).replaceAll(""); } - private boolean isProperty(String property) { + + static private boolean isProperty(String property) { return property.startsWith("updat") || property.startsWith("upgrad") || property.startsWith("instal") && !property.startsWith("installabl") || property.equals("tool") || property.startsWith("lib") @@ -324,20 +333,15 @@ public class ContributionListing { } if (property.startsWith("lib")) { return contrib.getType() == ContributionType.LIBRARY; -// return contrib.getType() == Contribution.Type.LIBRARY -// || contrib.getType() == Contribution.Type.LIBRARY_COMPILATION; } if (property.equals("mode")) { return contrib.getType() == ContributionType.MODE; } -// if (property.equals("compilation")) { -// return contrib.getType() == Contribution.Type.LIBRARY_COMPILATION; -// } - return false; } + /* protected List listCompatible(List contribs, boolean filter) { List filteredList = new ArrayList(contribs); @@ -353,6 +357,7 @@ public class ContributionListing { } return filteredList; } + */ private void notifyRemove(Contribution contribution) { @@ -376,7 +381,7 @@ public class ContributionListing { } - protected void addContributionListener(ChangeListener listener) { + protected void addListener(ChangeListener listener) { for (Contribution contrib : allContributions) { listener.contributionAdded(contrib); } @@ -384,18 +389,6 @@ public class ContributionListing { } - /* - private void removeContributionListener(ContributionChangeListener listener) { - listeners.remove(listener); - } - - - private ArrayList getContributionListeners() { - return new ArrayList(listeners); - } - */ - - /** * Starts a new thread to download the advertised list of contributions. * Only one instance will run at a time. @@ -430,11 +423,11 @@ public class ContributionListing { listingFile.delete(); // may silently fail, but below may still work } if (tempContribFile.renameTo(listingFile)) { - hasDownloadedLatestList = true; - hasListDownloadFailed = false; + listDownloaded = true; + listDownloadFailed = false; setAdvertisedList(listingFile); } else { - hasListDownloadFailed = true; + listDownloadFailed = true; } } @@ -449,9 +442,19 @@ public class ContributionListing { /* - boolean hasUpdates() { - for (Contribution info : allContributions) { - if (hasUpdates(info)) { + boolean hasUpdates(Base base) { + for (ModeContribution mc : base.getModeContribs()) { + if (hasUpdates(mc)) { + return true; + } + } + for (Library lib : base.getActiveEditor().getMode().contribLibraries) { + if (hasUpdates(lib)) { + return true; + } + } + for (ToolContribution tc : base.getToolContribs()) { + if (hasUpdates(tc)) { return true; } } @@ -460,6 +463,80 @@ public class ContributionListing { */ + protected boolean hasUpdates(Contribution contribution) { + if (contribution.isInstalled()) { + Contribution advertised = getAvailableContribution(contribution); + if (advertised == null) { + return false; + } + return advertised.getVersion() > contribution.getVersion() + && advertised.isCompatible(Base.getRevision()); + } + return false; + } + + + protected String getLatestVersion(Contribution contribution) { + Contribution newestContrib = getAvailableContribution(contribution); + if (newestContrib == null) { + return null; + } + return newestContrib.getPrettyVersion(); + } + + + + protected boolean hasDownloadedLatestList() { + return listDownloaded; + } + + + protected boolean hasListDownloadFailed() { + return listDownloadFailed; + } + + + private List parseContribList(File file) { + List outgoing = + new ArrayList(); + + if (file != null && file.exists()) { + String[] lines = PApplet.loadStrings(file); + + int start = 0; + while (start < lines.length) { + String type = lines[start]; + ContributionType contribType = ContributionType.fromName(type); + if (contribType == null) { + System.err.println("Error in contribution listing file on line " + (start+1)); + // Scan forward for the next blank line + int end = ++start; + while (end < lines.length && !lines[end].trim().isEmpty()) { + end++; + } + start = end + 1; + + } else { + // Scan forward for the next blank line + int end = ++start; + while (end < lines.length && !lines[end].trim().isEmpty()) { + end++; + } + + String[] contribLines = PApplet.subset(lines, start, end-start); + StringDict contribParams = Util.readSettings(file.getName(), contribLines); + outgoing.add(new AvailableContribution(contribType, contribParams)); + start = end + 1; + } + } + } + return outgoing; + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + /** * TODO This needs to be called when the listing loads, and also whenever * the contribs list has been updated (for whatever reason). In addition, @@ -467,7 +544,7 @@ public class ContributionListing { * correct information on the number of items available. * @return The number of contributions that have available updates. */ - int countUpdates(Base base) { + public int countUpdates(Base base) { int count = 0; for (ModeContribution mc : base.getModeContribs()) { if (hasUpdates(mc)) { @@ -488,106 +565,12 @@ public class ContributionListing { } - boolean hasUpdates(Base base) { - for (ModeContribution mc : base.getModeContribs()) { - if (hasUpdates(mc)) { - return true; - } - } - for (Library lib : base.getActiveEditor().getMode().contribLibraries) { - if (hasUpdates(lib)) { - return true; - } - } - for (ToolContribution tc : base.getToolContribs()) { - if (hasUpdates(tc)) { - return true; - } - } - return false; + /** Used by JavaEditor to auto-import */ + public Map getLibrariesByImportHeader() { + return librariesByImportHeader; } - boolean hasUpdates(Contribution contribution) { - if (contribution.isInstalled()) { - Contribution advertised = getAvailableContribution(contribution); - if (advertised == null) { - return false; - } - return advertised.getVersion() > contribution.getVersion() - && advertised.isCompatible(Base.getRevision()); - } - return false; - } - - - String getLatestVersion(Contribution contribution) { - Contribution newestContrib = getAvailableContribution(contribution); - if (newestContrib == null) { - return null; - } - return newestContrib.getPrettyVersion(); - } - - - - boolean hasDownloadedLatestList() { - return hasDownloadedLatestList; - } - - - boolean hasListDownloadFailed() { - return hasListDownloadFailed; - } - - - List parseContribList(File file) { - List outgoing = new ArrayList(); - - if (file != null && file.exists()) { - String[] lines = PApplet.loadStrings(file); - - int start = 0; - while (start < lines.length) { - String type = lines[start]; - ContributionType contribType = ContributionType.fromName(type); - if (contribType == null) { - System.err.println("Error in contribution listing file on line " + (start+1)); - // Scan forward for the next blank line - int end = ++start; - while (end < lines.length && lines[end].trim().length() != 0) { - end++; - } - start = end + 1; - - } else { - // Scan forward for the next blank line - int end = ++start; - while (end < lines.length && lines[end].trim().length() != 0) { - end++; - } - - String[] contribLines = PApplet.subset(lines, start, end-start); - StringDict contribParams = Util.readSettings(file.getName(), contribLines); - outgoing.add(new AvailableContribution(contribType, contribParams)); - start = end + 1; - } - } - } - return outgoing; - } - - -// boolean isDownloadingListing() { -// return downloadingListingLock.isLocked(); -// } - - -// public Comparator getComparator() { -// return COMPARATOR; -// } - - static public Comparator COMPARATOR = new Comparator() { public int compare(Contribution o1, Contribution o2) { return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase()); diff --git a/app/src/processing/app/contrib/ContributionManagerDialog.java b/app/src/processing/app/contrib/ContributionManagerDialog.java index d84530306..2de241577 100644 --- a/app/src/processing/app/contrib/ContributionManagerDialog.java +++ b/app/src/processing/app/contrib/ContributionManagerDialog.java @@ -56,11 +56,11 @@ public class ContributionManagerDialog { // the calling editor, so updates can be applied Editor editor; - ContributionTab toolsContributionTab; - ContributionTab librariesContributionTab; - ContributionTab examplesContributionTab; - ContributionTab modesContributionTab; - UpdateContributionTab updatesContributionTab; + ContributionTab librariesTab; + ContributionTab modesTab; + ContributionTab toolsTab; + ContributionTab examplesTab; + UpdateContributionTab updatesTab; JLabel numberLabel; ContributionListing contributionListing = ContributionListing.getInstance(); @@ -69,17 +69,14 @@ public class ContributionManagerDialog { private JPanel updateTabPanel; private JLabel updateTabLabel; - static Font font; - public ContributionManagerDialog() { - font = Toolkit.getSansFont(14, Font.PLAIN); numberLabel = new JLabel(Toolkit.getLibIconX("manager/notification")); - librariesContributionTab = new ContributionTab(ContributionType.LIBRARY, this); - modesContributionTab = new ContributionTab(ContributionType.MODE, this); - toolsContributionTab = new ContributionTab(ContributionType.TOOL, this); - examplesContributionTab = new ContributionTab(ContributionType.EXAMPLES, this); - updatesContributionTab = new UpdateContributionTab(null, this); + librariesTab = new ContributionTab(ContributionType.LIBRARY, this); + modesTab = new ContributionTab(ContributionType.MODE, this); + toolsTab = new ContributionTab(ContributionType.TOOL, this); + examplesTab = new ContributionTab(ContributionType.EXAMPLES, this); + updatesTab = new UpdateContributionTab(null, this); } @@ -109,17 +106,17 @@ public class ContributionManagerDialog { } - ContributionTab getTab(ContributionType contributionType) { + protected ContributionTab getTab(ContributionType contributionType) { if (contributionType == ContributionType.LIBRARY) { - return librariesContributionTab; + return librariesTab; } else if (contributionType == ContributionType.MODE) { - return modesContributionTab; + return modesTab; } else if (contributionType == ContributionType.TOOL) { - return toolsContributionTab; + return toolsTab; } else if (contributionType == ContributionType.EXAMPLES) { - return examplesContributionTab; + return examplesTab; } - return updatesContributionTab; + return updatesTab; } @@ -130,19 +127,19 @@ public class ContributionManagerDialog { makeAndShowTab(false, true); - tabbedPane.addTab("Libraries", null, librariesContributionTab, "Libraries"); + tabbedPane.addTab("Libraries", null, librariesTab, "Libraries"); tabbedPane.setMnemonicAt(0, KeyEvent.VK_1); - tabbedPane.addTab("Modes", null, modesContributionTab, "Modes"); + tabbedPane.addTab("Modes", null, modesTab, "Modes"); tabbedPane.setMnemonicAt(1, KeyEvent.VK_2); - tabbedPane.addTab("Tools", null, toolsContributionTab, "Tools"); + tabbedPane.addTab("Tools", null, toolsTab, "Tools"); tabbedPane.setMnemonicAt(2, KeyEvent.VK_3); - tabbedPane.addTab("Examples", null, examplesContributionTab, "Examples"); + tabbedPane.addTab("Examples", null, examplesTab, "Examples"); tabbedPane.setMnemonicAt(3, KeyEvent.VK_4); - tabbedPane.addTab("Updates", null, updatesContributionTab, "Updates"); + tabbedPane.addTab("Updates", null, updatesTab, "Updates"); tabbedPane.setMnemonicAt(4, KeyEvent.VK_5); tabbedPane.setUI(new SpacedTabbedPaneUI()); @@ -476,26 +473,26 @@ public class ContributionManagerDialog { void makeAndShowTab(boolean activateErrorPanel, boolean isLoading) { - librariesContributionTab.showFrame(editor, activateErrorPanel, isLoading); - modesContributionTab.showFrame(editor, activateErrorPanel, isLoading); - toolsContributionTab.showFrame(editor, activateErrorPanel, isLoading); - examplesContributionTab.showFrame(editor, activateErrorPanel, isLoading); - updatesContributionTab.showFrame(editor, activateErrorPanel, isLoading); + librariesTab.showFrame(editor, activateErrorPanel, isLoading); + modesTab.showFrame(editor, activateErrorPanel, isLoading); + toolsTab.showFrame(editor, activateErrorPanel, isLoading); + examplesTab.showFrame(editor, activateErrorPanel, isLoading); + updatesTab.showFrame(editor, activateErrorPanel, isLoading); } ContributionTab getActiveTab() { switch (tabbedPane.getSelectedIndex()) { case 0: - return librariesContributionTab; + return librariesTab; case 1: - return modesContributionTab; + return modesTab; case 2: - return toolsContributionTab; + return toolsTab; case 3: - return examplesContributionTab; + return examplesTab; default: - return updatesContributionTab; + return updatesTab; } } } diff --git a/app/src/processing/app/contrib/ContributionTab.java b/app/src/processing/app/contrib/ContributionTab.java index c15577959..06dae746b 100644 --- a/app/src/processing/app/contrib/ContributionTab.java +++ b/app/src/processing/app/contrib/ContributionTab.java @@ -100,7 +100,7 @@ public class ContributionTab extends JPanel { contribListing = ContributionListing.getInstance(); statusPanel = new StatusPanel(650, this); contributionListPanel = new ListPanel(this, filter); - contribListing.addContributionListener(contributionListPanel); + contribListing.addListener(contributionListPanel); } diff --git a/app/src/processing/app/contrib/ListPanel.java b/app/src/processing/app/contrib/ListPanel.java index 17b22b4c4..8a33018fb 100644 --- a/app/src/processing/app/contrib/ListPanel.java +++ b/app/src/processing/app/contrib/ListPanel.java @@ -57,6 +57,10 @@ implements Scrollable, ContributionListing.ChangeListener { static Icon upToDateIcon; static Icon updateAvailableIcon; static Icon incompatibleIcon; + static Icon foundationIcon; + + static Font plainFont; + static Font boldFont; public ListPanel() { @@ -64,6 +68,10 @@ implements Scrollable, ContributionListing.ChangeListener { upToDateIcon = Toolkit.getLibIconX("manager/up-to-date"); updateAvailableIcon = Toolkit.getLibIconX("manager/update-available"); incompatibleIcon = Toolkit.getLibIconX("manager/incompatible"); + foundationIcon = Toolkit.getLibIconX("icons/foundation", 16); + + plainFont = Toolkit.getSansFont(14, Font.PLAIN); + boldFont = Toolkit.getSansFont(14, Font.BOLD); } } @@ -103,7 +111,7 @@ implements Scrollable, ContributionListing.ChangeListener { table.setFillsViewportHeight(true); // table.setBorder(); table.setDefaultRenderer(Contribution.class, new ContribStatusRenderer()); - table.setFont(Toolkit.getSansFont(14, Font.PLAIN)); + table.setFont(plainFont); table.setRowHeight(28); table.setRowMargin(6); table.getColumnModel().setColumnMargin(0); @@ -294,7 +302,7 @@ implements Scrollable, ContributionListing.ChangeListener { } if (column == 0) { Icon icon = null; - label.setFont(Toolkit.getSansFont(14, Font.PLAIN)); + label.setFont(plainFont); if (contribution.isInstalled()) { icon = upToDateIcon; if (contribListing.hasUpdates(contribution)) { @@ -314,7 +322,6 @@ implements Scrollable, ContributionListing.ChangeListener { } else if (column == 1) { // Generating ellipses based on fontMetrics - Font boldFont = Toolkit.getSansFont(14, Font.BOLD); String fontFace = ""; FontMetrics fontMetrics = table.getFontMetrics(boldFont); //table.getFont()); int colSize = table.getColumnModel().getColumn(1).getWidth(); @@ -349,11 +356,11 @@ implements Scrollable, ContributionListing.ChangeListener { if (table.isRowSelected(row)) { label.setBackground(new Color(0xe0fffd)); } - label.setFont(ContributionManagerDialog.font); + label.setFont(plainFont); label.setOpaque(true); } else { if (contribution.isSpecial()) { - label = new JLabel(Toolkit.getLibIconX("icons/foundation", 16)); + label = new JLabel(foundationIcon); } else { label = new JLabel(); } diff --git a/app/src/processing/app/contrib/StatusPanel.java b/app/src/processing/app/contrib/StatusPanel.java index d661454f0..7f2cfa7ef 100644 --- a/app/src/processing/app/contrib/StatusPanel.java +++ b/app/src/processing/app/contrib/StatusPanel.java @@ -91,8 +91,8 @@ class StatusPanel extends JPanel { label.setEditable(false); label.setOpaque(false); label.setContentType("text/html"); - bodyRule = "a, body { font-family: " + ContributionManagerDialog.font.getFamily() + "; " + - "font-size: " + ContributionManagerDialog.font.getSize() + "pt; color: black; text-decoration: none;}"; + bodyRule = "a, body { font-family: " + buttonFont.getFamily() + "; " + + "font-size: " + buttonFont.getSize() + "pt; color: black; text-decoration: none;}"; label.addHyperlinkListener(new HyperlinkListener() { @Override diff --git a/app/src/processing/app/contrib/UpdateContributionTab.java b/app/src/processing/app/contrib/UpdateContributionTab.java index 6990f81e0..100b1b176 100644 --- a/app/src/processing/app/contrib/UpdateContributionTab.java +++ b/app/src/processing/app/contrib/UpdateContributionTab.java @@ -29,7 +29,7 @@ public class UpdateContributionTab extends ContributionTab { this.contributionType = type; this.contributionManagerDialog = contributionManagerDialog; contribListing = ContributionListing.getInstance(); - contribListing.addContributionListener(contributionListPanel); + contribListing.addListener(contributionListPanel); } diff --git a/java/src/processing/mode/java/JavaEditor.java b/java/src/processing/mode/java/JavaEditor.java index b1dd060a2..110a161ef 100644 --- a/java/src/processing/mode/java/JavaEditor.java +++ b/java/src/processing/mode/java/JavaEditor.java @@ -1924,16 +1924,18 @@ public class JavaEditor extends Editor { * @param importHeaders */ private List getNotInstalledAvailableLibs(ArrayList importHeadersList) { - Map importMap = ContributionListing.getInstance().librariesByImportHeader; - ArrayList libList = new ArrayList(); + Map importMap = + ContributionListing.getInstance().getLibrariesByImportHeader(); + List libList = new ArrayList(); for (String importHeaders : importHeadersList) { int dot = importHeaders.lastIndexOf('.'); String entry = (dot == -1) ? importHeaders : importHeaders.substring(0, dot); - if (entry.startsWith("java.") || entry.startsWith("javax.") - || entry.startsWith("processing.")) { - continue;// null; + if (entry.startsWith("java.") || + entry.startsWith("javax.") || + entry.startsWith("processing.")) { + continue; } Library library = null;