diff --git a/src/main/java/org/wikipedia/Caches.java b/src/main/java/org/wikipedia/Caches.java index ee575af7..f280c4e8 100644 --- a/src/main/java/org/wikipedia/Caches.java +++ b/src/main/java/org/wikipedia/Caches.java @@ -10,7 +10,7 @@ public final class Caches { public static final CacheAccess API_RESPONSES = JCSCacheManager.getCache( "api", 1, - 1_000, + 10_000, new File(Config.getDirs().getCacheDirectory(false), "plugin/wikipedia").getAbsolutePath() ); diff --git a/src/main/java/org/wikipedia/gui/ProgressJPanel.java b/src/main/java/org/wikipedia/gui/ProgressJPanel.java new file mode 100644 index 00000000..9020d8f7 --- /dev/null +++ b/src/main/java/org/wikipedia/gui/ProgressJPanel.java @@ -0,0 +1,30 @@ +package org.wikipedia.gui; + +import java.awt.BorderLayout; +import javax.swing.JPanel; +import javax.swing.JProgressBar; + +public class ProgressJPanel extends JPanel { + private final JProgressBar PROGRESS_BAR = new JProgressBar(); + + ProgressJPanel() { + setLayout(new BorderLayout()); + PROGRESS_BAR.setStringPainted(true); + } + + protected synchronized void showProgress(final String message) { + if (!isAncestorOf(PROGRESS_BAR)) { + add(PROGRESS_BAR, BorderLayout.NORTH); + } + PROGRESS_BAR.setIndeterminate(true); + PROGRESS_BAR.setString(message); + revalidate(); + repaint(); + } + + protected synchronized void hideProgress() { + remove(PROGRESS_BAR); + revalidate(); + repaint(); + } +} diff --git a/src/main/java/org/wikipedia/gui/WikidataInfoClaimPanel.java b/src/main/java/org/wikipedia/gui/WikidataInfoClaimPanel.java new file mode 100644 index 00000000..1c6457c0 --- /dev/null +++ b/src/main/java/org/wikipedia/gui/WikidataInfoClaimPanel.java @@ -0,0 +1,53 @@ +package org.wikipedia.gui; + +import java.awt.BorderLayout; +import java.awt.GridLayout; +import java.io.IOException; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import org.openstreetmap.josm.gui.Notification; +import org.openstreetmap.josm.tools.I18n; +import org.wikipedia.WikipediaPlugin; +import org.wikipedia.api.ApiQueryClient; +import org.wikipedia.api.wikidata_action.WikidataActionApiQuery; +import org.wikipedia.api.wikidata_action.json.WbgetclaimsResult; + +class WikidataInfoClaimPanel extends ProgressJPanel { + + private final JPanel mainPanel; + private String qIdBeingDownloaded; + + WikidataInfoClaimPanel() { + super(); + this.mainPanel = new JPanel(); + add(new JScrollPane(mainPanel), BorderLayout.CENTER); + } + + void downloadStatementsFor(final String qId) { + this.qIdBeingDownloaded = qId; + new Thread(() -> { + try { + mainPanel.removeAll(); + showProgress(I18n.tr("Download statements for {0}…", qId)); + final WbgetclaimsResult result = ApiQueryClient.query(WikidataActionApiQuery.wbgetclaims(qId)); + if (qIdBeingDownloaded != null && qIdBeingDownloaded.equals(qId)) { + synchronized (mainPanel) { + mainPanel.removeAll(); + mainPanel.setLayout(new GridLayout(result.getClaims().size(), 1)); + result.getClaims().forEach(claim -> { + final WbgetclaimsResult.Claim.MainSnak.DataValue value = claim.getMainSnak().getDataValue(); // nullable + mainPanel.add(new StatementPanel(claim.getMainSnak().getProperty(), value == null ? I18n.tr("Unknown datatype!") : value.toString())); + }); + hideProgress(); + } + } + } catch (IOException e) { + new Notification(I18n.tr("Failed to download statements for Wikidata item {0}!", qId)) + .setIcon(WikipediaPlugin.W_IMAGE.get()) + .show(); + } + hideProgress(); + }).start(); + + } +} diff --git a/src/main/java/org/wikipedia/gui/WikidataInfoLabelPanel.java b/src/main/java/org/wikipedia/gui/WikidataInfoLabelPanel.java index 72835541..a73ff37a 100644 --- a/src/main/java/org/wikipedia/gui/WikidataInfoLabelPanel.java +++ b/src/main/java/org/wikipedia/gui/WikidataInfoLabelPanel.java @@ -4,15 +4,16 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import javax.swing.JPanel; -import javax.swing.JProgressBar; +import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; import org.openstreetmap.josm.gui.Notification; import org.openstreetmap.josm.tools.I18n; +import org.openstreetmap.josm.tools.Logging; import org.openstreetmap.josm.tools.Pair; import org.wikipedia.WikipediaPlugin; import org.wikipedia.api.ApiQueryClient; @@ -22,42 +23,18 @@ /** * Panel displaying the labels for a Wikidata item */ -class WikidataInfoLabelPanel extends JPanel { - - private static final JProgressBar downloadProgress = new JProgressBar(); +class WikidataInfoLabelPanel extends ProgressJPanel { private final LabelTableModel tableModel = new LabelTableModel(this); - - static { - downloadProgress.setStringPainted(true); - } + private final JTable table = new JTable(tableModel); WikidataInfoLabelPanel() { - setLayout(new BorderLayout()); - add(new JTable(tableModel), BorderLayout.CENTER); - } - - void clear() { - tableModel.clear(); + add(new JScrollPane(table), BorderLayout.CENTER); } void downloadLabelsFor(final String qId) { tableModel.downloadLabelsFor(qId); } - private synchronized void showDownloadProgress(final String qId) { - if (!isAncestorOf(downloadProgress)) { - add(downloadProgress, BorderLayout.NORTH); - } - downloadProgress.setIndeterminate(true); - downloadProgress.setString(I18n.tr("Download labels for {0}…", qId)); - revalidate(); - } - - private synchronized void hideDownloadProgress() { - remove(downloadProgress); - revalidate(); - } - private static class LabelTableModel extends AbstractTableModel { private final WikidataInfoLabelPanel parent; private String qIdBeingDownloaded; @@ -67,36 +44,40 @@ private static class LabelTableModel extends AbstractTableModel { this.parent = parent; } - void clear() { - this.valueMap.clear(); - } - void downloadLabelsFor(final String qId) { - synchronized (valueMap) { - qIdBeingDownloaded = qId; - parent.showDownloadProgress(qId); - } + qIdBeingDownloaded = qId; new Thread(() -> { try { + parent.showProgress(I18n.tr("Download labels for {0}…", qId)); + valueMap.clear(); + parent.table.revalidate(); + parent.revalidate(); + parent.repaint(); final Map newValues = ApiQueryClient.query(WikidataActionApiQuery.wbgetentitiesLabels(qId)); + final Map languages = new HashMap<>(); + try { + languages.putAll(ApiQueryClient.query(WikidataActionApiQuery.queryLanguages())); + } catch (IOException e) { + Logging.warn("Could not download language names! Only the language codes are displayed.", e); + } synchronized (valueMap) { if (qIdBeingDownloaded != null && qIdBeingDownloaded.equals(qId)) { valueMap.clear(); valueMap.addAll( - newValues.entrySet().stream() - .map(it -> Pair.create(it.getValue(), it.getKey())) + newValues.values().stream() + .map(it -> Pair.create(it, languages.containsKey(it.getLangCode()) ? languages.get(it.getLangCode()) : it.getLangCode())) .sorted(Comparator.comparing(it -> it.a.getLangCode())) .collect(Collectors.toList()) ); + parent.table.revalidate(); } } } catch (IOException e) { new Notification(I18n.tr("Failed to download labels for {0}!", qId)).setIcon(WikipediaPlugin.W_IMAGE.get()).show(); } - parent.hideDownloadProgress(); + parent.hideProgress(); }).start(); - } @Override @@ -106,17 +87,32 @@ public int getRowCount() { @Override public int getColumnCount() { - return 2; + return 3; } @Override public Object getValueAt(int rowIndex, int columnIndex) { - return columnIndex == 0 ? valueMap.get(rowIndex).a : valueMap.get(rowIndex).b; + switch (columnIndex) { + case 0: return valueMap.get(rowIndex).a.getLangCode(); + case 1: return valueMap.get(rowIndex).b; + case 2: + default: return valueMap.get(rowIndex).a.getValue(); + } } @Override public String getColumnName(int column) { - return column == 0 ? "language" : "label"; + switch (column) { + case 0: return I18n.tr("language code"); + case 1: return I18n.tr("language"); + case 2: + default: return I18n.tr("label"); + } + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return columnIndex == 3; } } } diff --git a/src/main/java/org/wikipedia/gui/WikidataInfoToggleDialog.java b/src/main/java/org/wikipedia/gui/WikidataInfoToggleDialog.java index ea56556c..c7f1d47f 100644 --- a/src/main/java/org/wikipedia/gui/WikidataInfoToggleDialog.java +++ b/src/main/java/org/wikipedia/gui/WikidataInfoToggleDialog.java @@ -5,10 +5,7 @@ import java.awt.Color; import java.awt.FlowLayout; import java.awt.Font; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; import java.awt.GridLayout; -import java.awt.Insets; import java.awt.event.ActionEvent; import java.util.Collections; import java.util.Map; @@ -20,7 +17,6 @@ import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; -import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import org.openstreetmap.josm.data.osm.DataSelectionListener; import org.openstreetmap.josm.data.osm.DataSet; @@ -30,7 +26,6 @@ import org.openstreetmap.josm.gui.MainApplication; import org.openstreetmap.josm.gui.Notification; import org.openstreetmap.josm.gui.dialogs.ToggleDialog; -import org.openstreetmap.josm.tools.GBC; import org.openstreetmap.josm.tools.I18n; import org.openstreetmap.josm.tools.OpenBrowser; import org.wikipedia.WikipediaPlugin; @@ -38,6 +33,9 @@ import org.wikipedia.data.WikipediaEntry; import org.wikipedia.tools.OsmPrimitiveUtil; +/** + * Toggle dialog that displays infos about the currently selected Wikidata item. + */ public class WikidataInfoToggleDialog extends ToggleDialog { private static final Logger L = Logger.getLogger(WikidataInfoToggleDialog.class.getName()); private static final String EMPTY_STRING = ""; @@ -56,7 +54,7 @@ public class WikidataInfoToggleDialog extends ToggleDialog { private final JTabbedPane tabs = new JTabbedPane(); private final WikidataInfoLabelPanel labelTab = new WikidataInfoLabelPanel(); - private final JPanel statementTab = new JPanel(); + private final WikidataInfoClaimPanel statementTab = new WikidataInfoClaimPanel(); private final JPanel linkTab = new JPanel(); private final JButton webLinkButton = new JButton(); @@ -98,25 +96,6 @@ public WikidataInfoToggleDialog(final WikipediaToggleDialog wikiDialog) { infoPanel.add(basicInfoPanel, BorderLayout.NORTH); infoPanel.add(tabs, BorderLayout.CENTER); - // Set up statement tab - statementTab.setLayout(new GridBagLayout()); - final GridBagConstraints constraints = new GridBagConstraints(); - constraints.anchor = GridBagConstraints.NORTH; - constraints.gridx = 0; - constraints.gridy = 0; - constraints.insets = new Insets(1, 1, 1, 1); - constraints.fill = GridBagConstraints.BOTH; - // At the moment only dummy content - constraints.weightx = 1; - statementTab.add(new StatementPanel("instance of", "example", "dummy content"), constraints); - constraints.gridy++; - statementTab.add(new StatementPanel("start date", "42"), constraints); - constraints.gridy++; - statementTab.add(new StatementPanel("architect", "John Doe"), constraints); - constraints.gridy++; - constraints.weighty = 1; - statementTab.add(GBC.glue(0, 0), constraints); - linkTab.add(webLinkButton); tabs.add(I18n.tr("Statements"), statementTab); @@ -126,7 +105,6 @@ public WikidataInfoToggleDialog(final WikipediaToggleDialog wikiDialog) { // Set up listeners this.wikiDialog.list.addListSelectionListener(event -> updateDisplayedItem()); MainApplication.getLayerManager().addAndFireActiveLayerChangeListener(event -> { - System.out.println("Fire active layer change"); final DataSet previous = event.getPreviousDataSet(); final DataSet current = event.getSource().getActiveDataSet(); if (previous != null) { @@ -173,7 +151,9 @@ private void updateDisplayedItem() { } } else if (wdTagsInDataset.size() >= 2) { // More than one OSM object with valid wikidata=* tag is selected - final String itemList = wdTagsInDataset.entrySet().stream().map(it -> it.getKey() + " (" + it.getValue() + "×)").collect(Collectors.joining(", ")); + final String itemList = wdTagsInDataset.entrySet().stream() + .map(it -> it.getKey() + " (" + it.getValue() + "×)") + .collect(Collectors.joining(", ")); displayMessage(itemList, I18n.tr("More than one OSM object is selected: {0}", itemList)); } else { // size == 1 // An OSM object or multiple OSM objects with exactly one valid wikidata=* tag (multiple tags with same value count as one) @@ -182,7 +162,7 @@ private void updateDisplayedItem() { } } - private void displayItem(final String qId, final String label, final String description) { + private synchronized void displayItem(final String qId, final String label, final String description) { if (qId != null && !qId.equals(getDisplayedItem())) { mainPanel.removeAll(); setTitle(qId); @@ -190,28 +170,31 @@ private void displayItem(final String qId, final String label, final String desc descriptionLabel.setText(description); setDisplayedItem(qId); - labelTab.clear(); labelTab.downloadLabelsFor(qId); + statementTab.downloadStatementsFor(qId); + webLinkButton.setAction(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { final String uri = "https://www.wikidata.org/wiki/" + qId; final String error = OpenBrowser.displayUrl(uri); if (error != null) { - new Notification(I18n.tr("Can't open website {0} in browser! Error message: {1}", uri, error)).setIcon(WikipediaPlugin.W_IMAGE.get()).show(); + new Notification(I18n.tr("Can't open website {0} in browser! Error message: {1}", uri, error)) + .setIcon(WikipediaPlugin.W_IMAGE.get()) + .show(); } } }); webLinkButton.setText(I18n.tr("Open item {0} in browser", qId)); - mainPanel.add(new JScrollPane(infoPanel)); + mainPanel.add(infoPanel); mainPanel.revalidate(); mainPanel.repaint(); } } - private void displayMessage(final String title, final String message) { + private synchronized void displayMessage(final String title, final String message) { mainPanel.removeAll(); setTitle(title); setDisplayedItem(null);