/*
* WPCleaner: A tool to help on Wikipedia maintenance tasks.
* Copyright (C) 2013 Nicolas Vervelle
*
* See README.txt file for licensing information.
*/
package org.wikipediacleaner.gui.swing;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.beans.EventHandler;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import org.wikipediacleaner.api.constants.EnumWikipedia;
import org.wikipediacleaner.api.data.CompositeComparator;
import org.wikipediacleaner.api.data.Namespace;
import org.wikipediacleaner.api.data.Page;
import org.wikipediacleaner.api.data.PageComparator;
import org.wikipediacleaner.gui.swing.action.ActionDisambiguationAnalysis;
import org.wikipediacleaner.gui.swing.action.ActionExternalViewer;
import org.wikipediacleaner.gui.swing.action.ActionFullAnalysis;
import org.wikipediacleaner.gui.swing.action.ActionWatchPage;
import org.wikipediacleaner.gui.swing.action.SetComparatorAction;
import org.wikipediacleaner.gui.swing.basic.BasicWindow;
import org.wikipediacleaner.gui.swing.basic.DefaultBasicWindowListener;
import org.wikipediacleaner.gui.swing.basic.Utilities;
import org.wikipediacleaner.gui.swing.component.DisambiguationPageListPopupListener;
import org.wikipediacleaner.gui.swing.component.PageListAnalyzeListener;
import org.wikipediacleaner.gui.swing.component.PageListCellRenderer;
import org.wikipediacleaner.gui.swing.component.PageListModel;
import org.wikipediacleaner.gui.swing.worker.DisambiguationAnalysisWorker;
import org.wikipediacleaner.i18n.GT;
import org.wikipediacleaner.images.EnumImageSize;
import org.wikipediacleaner.utils.Configuration;
import org.wikipediacleaner.utils.ConfigurationValueBoolean;
import org.wikipediacleaner.utils.ConfigurationValueInteger;
/**
* Disambiguation window.
*/
public class DisambiguationWindow extends OnePageWindow {
//public final static Integer WINDOW_VERSION = Integer.valueOf(2);
private Properties backlinksProperties;
JList<Page> listLinks;
PageListModel modelLinks;
private PageListCellRenderer listCellRenderer;
private DisambiguationPageListPopupListener popupListenerLinks;
JLabel linkCount;
private JButton buttonAutomaticFixing;
private JButton buttonFullAnalysisLink;
private JButton buttonMarkNeedHelp;
private JButton buttonMarkNormal;
private JButton buttonSelectNextLinks;
private JButton buttonView;
private JButton buttonViewHistory;
private JButton buttonViewLink;
private JButton buttonWatch;
private JMenu menuFilter;
List<Page> knownPages;
/**
* Create and display a DisambiguationWindow.
*
* @param page Page name.
* @param wikipedia Wikipedia.
*/
public static void createDisambiguationWindow(
final String page,
final EnumWikipedia wikipedia) {
createWindow(
"DisambiguationWindow",
wikipedia,
WindowConstants.DISPOSE_ON_CLOSE,
DisambiguationWindow.class,
new DefaultBasicWindowListener() {
@Override
public void initializeWindow(BasicWindow window) {
if (window instanceof DisambiguationWindow) {
DisambiguationWindow disambig = (DisambiguationWindow) window;
disambig.setPageName(page);
disambig.modelLinks = new PageListModel();
disambig.modelLinks.setComparator(PageComparator.getTemplateFirstComparator());
disambig.modelLinks.setShowDisambiguation(true);
disambig.modelLinks.setShowOther(true);
Configuration config = Configuration.getConfiguration();
List<String> filtered = config.getStringList(wikipedia, Configuration.ARRAY_FILTER_NS);
disambig.modelLinks.setFilterNamespace(filtered);
disambig.knownPages = new ArrayList<Page>();
}
}
@Override
public void displayWindow(BasicWindow window) {
if (window instanceof DisambiguationWindow) {
DisambiguationWindow disambig = (DisambiguationWindow) window;
disambig.actionReload();
}
}
});
}
/* (non-Javadoc)
* @see org.wikipediacleaner.gui.swing.basic.BasicWindow#getTitle()
*/
@Override
public String getTitle() {
return GT._("Disambiguation - {0}", getPageName());
}
/**
* @return Menu bar.
*/
@Override
protected JMenuBar createMenuBar() {
JMenuBar menuBar = new JMenuBar();
menuBar.add(createToolsMenu());
menuBar.add(createSortMenu());
menuBar.add(Box.createHorizontalGlue());
return menuBar;
}
/**
* @return Window components.
*/
@Override
protected Component createComponents() {
createElements();
JPanel panel = new JPanel(new GridBagLayout());
// Initialize constraints
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridheight = 1;
constraints.gridwidth = 1;
constraints.gridx = 0;
constraints.gridy = 0;
constraints.insets = new Insets(2, 2, 2, 2);
constraints.ipadx = 0;
constraints.ipady = 0;
constraints.weightx = 0;
constraints.weighty = 0;
// Page name
//constraints.gridwidth = 2;
panel.add(createPageComponents(), constraints);
constraints.gridy++;
// Contents
constraints.fill = GridBagConstraints.BOTH;
constraints.gridwidth = 1;
constraints.gridx = 0;
constraints.weightx = 1;
constraints.weighty = 1;
JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
split.setLeftComponent(createLinksComponents());
split.setRightComponent(createContentsComponents());
split.setPreferredSize(new Dimension(1200, 700));
split.setMinimumSize(new Dimension(200, 200));
split.setResizeWeight(0.0);
split.setDividerLocation(200 + split.getInsets().left);
panel.add(split, constraints);
constraints.gridy++;
updateComponentState();
return panel;
}
/**
* Update component state.
*/
@Override
protected void updateComponentState() {
super.updateComponentState();
setEnabledStatus(buttonFullAnalysisLink, isPageLoaded());
setEnabledStatus(buttonView, isPageLoaded());
setEnabledStatus(buttonViewHistory, isPageLoaded());
setEnabledStatus(buttonViewLink, isPageLoaded());
setEnabledStatus(buttonWatch, isPageLoaded());
}
/**
* Creates internal elements.
*/
private void createElements() {
createTextContents(this);
}
/**
* @return Page components.
*/
private Component createPageComponents() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER));
addTextPageName(panel);
JToolBar toolbar = new JToolBar(SwingConstants.HORIZONTAL);
toolbar.setFloatable(false);
toolbar.setBorderPainted(false);
addButtonReload(toolbar, true);
buttonView = ActionExternalViewer.addButton(
toolbar, getWikipedia(), getPageName(), false, true, false);
buttonViewHistory = ActionExternalViewer.addButton(
toolbar, getWikipedia(), getPageName(), ActionExternalViewer.ACTION_HISTORY, true, true);
addButtonSend(toolbar, true);
buttonWatch = ActionWatchPage.addButton(
getParentComponent(), toolbar, getWikipedia(), getPageName(), true, true);
addButtonFullAnalysis(toolbar, true);
panel.add(toolbar);
return panel;
}
/**
* @return Contents components.
*/
private Component createContentsComponents() {
JPanel panel = new JPanel(new GridBagLayout());
// Initialize constraints
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridheight = 1;
constraints.gridwidth = 1;
constraints.gridx = 0;
constraints.gridy = 0;
constraints.insets = new Insets(0, 0, 0, 0);
constraints.ipadx = 0;
constraints.ipady = 0;
constraints.weightx = 1;
constraints.weighty = 0;
// Contents
constraints.fill = GridBagConstraints.BOTH;
constraints.weighty = 1;
addTextContents(panel, constraints);
constraints.gridy++;
return panel;
}
/**
* @return Links components.
*/
private Component createLinksComponents() {
JPanel panel = new JPanel(new GridBagLayout());
Configuration configuration = Configuration.getConfiguration();
listLinks = new JList<Page>(modelLinks);
// Initialize constraints
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridheight = 1;
constraints.gridwidth = 1;
constraints.gridx = 0;
constraints.gridy = 0;
constraints.insets = new Insets(0, 0, 0, 0);
constraints.ipadx = 0;
constraints.ipady = 0;
constraints.weightx = 1;
constraints.weighty = 0;
// Select next links button
buttonSelectNextLinks = Utilities.createJButton(GT._("Select &next links"), null);
buttonSelectNextLinks.addActionListener(EventHandler.create(
ActionListener.class, this, "actionSelectNextLinks"));
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.weightx = 1;
panel.add(buttonSelectNextLinks, constraints);
constraints.gridy++;
// Automatic fixing
buttonAutomaticFixing = Utilities.createJButton(GT._("Automatic fixing"), null);
buttonAutomaticFixing.addActionListener(EventHandler.create(
ActionListener.class, this, "actionRunAutomaticFixing"));
panel.add(buttonAutomaticFixing, constraints);
constraints.gridy++;
// Button toolbar
JToolBar toolbar = new JToolBar(SwingConstants.HORIZONTAL);
toolbar.setFloatable(false);
toolbar.setBorderPainted(false);
buttonFullAnalysisLink = ActionFullAnalysis.addButton(
getParentComponent(), toolbar, getWikipedia(), listLinks, knownPages, true, true);
ActionDisambiguationAnalysis.addButton(
getParentComponent(), toolbar, getWikipedia(), listLinks, true, true);
buttonMarkNormal = Utilities.createJButton(
"wpc-mark-normal.png", EnumImageSize.NORMAL,
GT._("Mark backlink as normal"), false, null);
buttonMarkNormal.addActionListener(EventHandler.create(
ActionListener.class, this, "actionMarkBacklinkNormal"));
toolbar.add(buttonMarkNormal);
buttonMarkNeedHelp = Utilities.createJButton(
"wpc-mark-need-help.png", EnumImageSize.NORMAL,
GT._("Mark backlink as needing help"), false, null);
buttonMarkNeedHelp.addActionListener(EventHandler.create(
ActionListener.class, this, "actionMarkBacklinkHelpNeeded"));
toolbar.add(buttonMarkNeedHelp);
buttonViewLink = ActionExternalViewer.addButton(
toolbar, getWikipedia(), listLinks, false, true, true);
toolbar.addSeparator();
linkCount = new JLabel(GT._("Link count"));
toolbar.add(linkCount);
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.weightx = 1;
constraints.weighty = 0;
panel.add(toolbar, constraints);
constraints.gridy++;
// Links
listCellRenderer = new PageListCellRenderer();
listCellRenderer.showRedirect(true);
listCellRenderer.showRedirectBacklinks(true);
if (getPage() != null) {
listCellRenderer.setPageProperties(configuration.getSubProperties(
getWikipedia(), Configuration.PROPERTIES_BACKLINKS, getPage().getTitle()));
}
listLinks.setCellRenderer(listCellRenderer);
popupListenerLinks = new DisambiguationPageListPopupListener(
getWikipedia(), getTextContents(), listLinks, this);
listLinks.addMouseListener(popupListenerLinks);
listLinks.addMouseListener(new PageListAnalyzeListener(getWikipedia(), this));
JScrollPane scrollLinks = new JScrollPane(listLinks);
scrollLinks.setMinimumSize(new Dimension(100, 100));
scrollLinks.setPreferredSize(new Dimension(200, 500));
scrollLinks.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
constraints.fill = GridBagConstraints.BOTH;
constraints.weighty = 1;
panel.add(scrollLinks, constraints);
constraints.gridy++;
return panel;
}
/**
* @return Tools menu.
*/
@Override
protected JMenu createToolsMenu() {
JMenu menu = super.createToolsMenu();
menu.add(createFilterMenu());
return menu;
}
/**
* @return Filter namespace menu.
*/
private JMenu createFilterMenu() {
if (menuFilter == null) {
menuFilter = Utilities.createJMenu(GT._("Filter namespaces"));
} else {
menuFilter.removeAll();
}
EnumWikipedia wiki = getWikipedia();
if (wiki == null) {
return menuFilter;
}
Configuration config = Configuration.getConfiguration();
List<String> filtered = config.getStringList(wiki, Configuration.ARRAY_FILTER_NS);
for (Namespace ns : wiki.getWikiConfiguration().getNamespaces()) {
Integer id = ns.getId();
if ((id != null) && (id.intValue() >= 0)) {
boolean active = !filtered.contains(Integer.toString(ns.getId()));
JMenuItem item = new JCheckBoxMenuItem(
ns.toString(), active);
item.setActionCommand(id.toString());
item.addActionListener(EventHandler.create(
ActionListener.class, this,
active ? "actionFilterNamespaceTrue" : "actionFilterNamespaceFalse",
"actionCommand"));
menuFilter.add(item);
}
}
return menuFilter;
}
/**
* Action called to activate the filter on a namespace.
*
* @param namespaceId Namespace identifier.
*/
public void actionFilterNamespaceTrue(String namespaceId) {
actionFilterNamespace(namespaceId, true);
}
/**
* Action called to deactivate the filter on a namespace.
*
* @param namespaceId Namespace identifier.
*/
public void actionFilterNamespaceFalse(String namespaceId) {
actionFilterNamespace(namespaceId, false);
}
/**
* Action called to activate/deactivate the filter on a namespace.
*
* @param namespaceId Namespace identifier.
* @param filter True to activate the filter on the namespace.
*/
private void actionFilterNamespace(String namespaceId, boolean filter) {
EnumWikipedia wiki = getWikipedia();
Configuration config = Configuration.getConfiguration();
List<String> filtered = config.getStringList(wiki, Configuration.ARRAY_FILTER_NS);
if (filter) {
filtered.add(namespaceId);
} else {
filtered.remove(namespaceId);
}
config.setStringList(wiki, Configuration.ARRAY_FILTER_NS, filtered);
modelLinks.setFilterNamespace(filtered);
}
/**
* @return Sort menu.
*/
private JMenu createSortMenu() {
JMenu menu = Utilities.createJMenu(GT._("Sort"));
List<CompositeComparator<Page>> comparators = PageComparator.getComparators();
for (CompositeComparator<Page> comparator : comparators) {
JMenuItem menuItem = Utilities.createJMenuItem(comparator.getName(), true);
menuItem.addActionListener(new SetComparatorAction(modelLinks, comparator));
menu.add(menuItem);
}
return menu;
}
/**
* Clean page.
*/
@Override
protected void clean() {
super.clean();
modelLinks.clear();
updateComponentState();
}
/**
* Action called when Reload button is pressed.
*/
@Override
protected void actionReload() {
clean();
DisambiguationAnalysisWorker reloadWorker = new DisambiguationAnalysisWorker(
getWikipedia(), this, getPage());
setupReloadWorker(reloadWorker);
reloadWorker.start();
}
/**
* Callback called at the end of the Reload Worker.
*/
@Override
protected void afterFinishedReloadWorker() {
super.afterFinishedReloadWorker();
Configuration config = Configuration.getConfiguration();
Page page = getPage();
backlinksProperties = config.getSubProperties(
getWikipedia(), Configuration.PROPERTIES_BACKLINKS, page.getTitle());
listCellRenderer.setPageProperties(backlinksProperties);
popupListenerLinks.setPage(page);
popupListenerLinks.setBackLinksProperties(backlinksProperties);
List<Page> links = page.getAllLinksToPage();
if (config.getBoolean(null, ConfigurationValueBoolean.IGNORE_DAB_USER_NS)) {
links = new ArrayList<Page>(links);
for (int i = links.size(); i > 0; i--) {
if (links.get(i - 1).isInUserNamespace()) {
links.remove(i - 1);
}
}
}
modelLinks.setElements(links);
Integer countMain = page.getBacklinksCountInMainNamespace();
Integer countTotal = page.getBacklinksCount();
linkCount.setText(
((countMain != null) ? countMain.toString() : "?") +
" / " +
((countTotal != null) ? countTotal.toString() : "?"));
// Construct list of known pages
knownPages.clear();
if (getPage() != null) {
knownPages = new ArrayList<Page>(1);
knownPages.add(getPage());
for (Page backLink : getPage().getAllLinksToPage()) {
if ((backLink != null) &&
(backLink.isRedirect()) &&
(Page.areSameTitle(getPage().getTitle(), backLink.getRedirectDestination()))) {
knownPages.add(backLink);
}
}
}
// Select next links
actionSelectNextLinks();
}
/**
* Callback called before the start of the Reload Worker.
*/
@Override
protected void beforeStartReloadWorker() {
super.beforeStartReloadWorker();
modelLinks.setShowDisambiguation(true);
modelLinks.setShowOther(true);
}
/**
* Action called when Run Automatic Fixing button is pressed.
*/
public void actionRunAutomaticFixing() {
List<Page> values = listLinks.getSelectedValuesList();
if ((values == null) || (values.size() == 0)) {
Utilities.displayWarning(
getParentComponent(),
GT._("You must select pages on which running automatic fixing."));
return;
}
Controller.runAutomaticFixing(values, getPage(), getWikipedia());
}
/**
* Action called when Mark back link button is pressed.
*/
public void actionMarkBacklinkNormal() {
actionMarkBacklink(Configuration.VALUE_PAGE_NORMAL);
}
/**
* Action called when Mark back link button is pressed.
*/
public void actionMarkBacklinkHelpNeeded() {
actionMarkBacklink(Configuration.VALUE_PAGE_HELP_NEEDED);
}
/**
* Action called when Mark back link button is pressed.
*/
private void actionMarkBacklink(String mark) {
for (Page selection : listLinks.getSelectedValuesList()) {
if (selection != null) {
backlinksProperties.put(selection.getTitle(), mark);
}
}
Configuration configuration = Configuration.getConfiguration();
configuration.setSubProperties(
getWikipedia(),
Configuration.PROPERTIES_BACKLINKS, getPageName(),
backlinksProperties);
listLinks.repaint();
}
/**
* Action called when Select next links button is pressed.
*/
public void actionSelectNextLinks() {
// Test
if (listLinks.getModel().getSize() == 0) {
return;
}
// Check if something can be selected after current selection
int lastSelected = listLinks.getMaxSelectionIndex();
int currentLine = lastSelected + 1;
boolean lineAvailable = false;
while ((!lineAvailable) &&
(currentLine < listLinks.getModel().getSize())) {
Object value = listLinks.getModel().getElementAt(currentLine);
String property = backlinksProperties.getProperty(value.toString());
if ((!Configuration.VALUE_PAGE_NORMAL.equals(property)) &&
(!Configuration.VALUE_PAGE_HELP_NEEDED.equals(property))) {
lineAvailable = true;
}
currentLine++;
}
if (!lineAvailable) {
lastSelected = -1;
}
// Find first item to be selected
currentLine = lastSelected + 1;
int firstSelection = -1;
Integer firstNamespace = null;
while ((firstSelection < 0) &&
(currentLine < listLinks.getModel().getSize())) {
Object value = listLinks.getModel().getElementAt(currentLine);
String property = backlinksProperties.getProperty(value.toString());
if ((!Configuration.VALUE_PAGE_NORMAL.equals(property)) &&
(!Configuration.VALUE_PAGE_HELP_NEEDED.equals(property))) {
firstSelection = currentLine;
if (value instanceof Page) {
Page firstPage = (Page) value;
firstNamespace = firstPage.getNamespace();
}
}
currentLine++;
}
if (firstSelection < 0) {
listLinks.clearSelection();
listLinks.ensureIndexIsVisible(0);
return;
}
// Initialize array for items to be selected
Configuration config = Configuration.getConfiguration();
int maxCount = config.getInt(
null,
ConfigurationValueInteger.MAXIMUM_PAGES);
maxCount = Math.min(maxCount, listLinks.getModel().getSize() - firstSelection);
if (maxCount <= 0) {
listLinks.clearSelection();
listLinks.ensureIndexIsVisible(0);
return;
}
int indices[] = new int[maxCount];
// Find items to be selected
currentLine = firstSelection;
int currentIndice = 0;
while ((currentIndice < maxCount) &&
(currentLine < listLinks.getModel().getSize())) {
Object value = listLinks.getModel().getElementAt(currentLine);
String property = backlinksProperties.getProperty(value.toString());
if ((firstNamespace == null) ||
((value instanceof Page) &&
(firstNamespace.equals(((Page) value).getNamespace())))) {
if ((!Configuration.VALUE_PAGE_NORMAL.equals(property)) &&
(!Configuration.VALUE_PAGE_HELP_NEEDED.equals(property))) {
indices[currentIndice] = currentLine;
currentIndice++;
}
currentLine++;
} else {
currentLine = Integer.MAX_VALUE;
}
}
// Select items found
if (currentIndice < indices.length) {
int newIndices[] = new int[currentIndice];
for (int i = 0; i < currentIndice; i++) {
newIndices[i] = indices[i];
}
indices = newIndices;
}
listLinks.setSelectedIndices(indices);
if (indices.length > 0) {
listLinks.ensureIndexIsVisible(indices[0]);
listLinks.ensureIndexIsVisible(indices[indices.length - 1]);
}
}
}