/*
* 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.checkwiki;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.TextAttribute;
import java.beans.EventHandler;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
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.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JToolBar;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeListener;
import org.wikipediacleaner.api.APIFactory;
import org.wikipediacleaner.api.check.CheckError;
import org.wikipediacleaner.api.check.CheckErrorPage;
import org.wikipediacleaner.api.check.CheckWiki;
import org.wikipediacleaner.api.check.CheckWikiListener;
import org.wikipediacleaner.api.check.algorithm.CheckErrorAlgorithm;
import org.wikipediacleaner.api.check.algorithm.CheckErrorAlgorithmComparator;
import org.wikipediacleaner.api.check.algorithm.CheckErrorAlgorithms;
import org.wikipediacleaner.api.constants.CWConfigurationError;
import org.wikipediacleaner.api.constants.EnumWikipedia;
import org.wikipediacleaner.api.constants.WPCConfigurationString;
import org.wikipediacleaner.api.data.DataManager;
import org.wikipediacleaner.api.data.Page;
import org.wikipediacleaner.gui.swing.OnePageWindow;
import org.wikipediacleaner.gui.swing.action.ActionFullAnalysis;
import org.wikipediacleaner.gui.swing.basic.BasicWorker;
import org.wikipediacleaner.gui.swing.basic.DefaultBasicWorkerListener;
import org.wikipediacleaner.gui.swing.basic.Utilities;
import org.wikipediacleaner.gui.swing.component.CheckErrorPageListCellRenderer;
import org.wikipediacleaner.gui.swing.component.HTMLPane;
import org.wikipediacleaner.gui.swing.component.JCloseableTabbedPane;
import org.wikipediacleaner.gui.swing.worker.CheckWikiProjectWorker;
import org.wikipediacleaner.gui.swing.worker.RetrieveContentWorker;
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;
/**
* Check Wiki Project window.
*/
public class CheckWikiWindow extends OnePageWindow implements CheckWikiListener {
List<CheckErrorAlgorithm> allAlgorithms;
private List<CheckErrorAlgorithm> selectedAlgorithms;
private List<JMenuItem> menuItemAlgorithms;
private JPopupMenu popupSelectErrors;
private JMenu menuUseSelection;
private JMenu menuDeleteSelection;
private JButton buttonSelectErrors;
private JButton buttonLoadErrors;
private SpinnerNumberModel modelMaxErrors;
List<CheckError> errors;
Properties checkWikiConfig;
JComboBox listAllErrors;
DefaultComboBoxModel<Object> modelAllErrors;
private HTMLPane textDescription;
private HTMLPane textParameters;
private int lastErrorDisplayed = -1;
private JButton buttonReloadError;
private JButton buttonErrorDetail;
private JButton buttonErrorList;
private JButton buttonWhiteList;
private JList<CheckErrorPage> listPages;
private DefaultListModel<CheckErrorPage> modelPages;
boolean yesAll = false;
boolean noAll = false;
JTabbedPane contentPane;
public final static String ACTION_SELECT_ERRORS = "SELECT_ERRORS:";
/**
* Create and display a CheckWikiProjectWindow.
*
* @param wikipedia Wikipedia.
*/
public static void createCheckWikiProjectWindow(
final EnumWikipedia wikipedia) {
createWindow(
"CheckWikiWindow",
wikipedia,
WindowConstants.DISPOSE_ON_CLOSE,
CheckWikiWindow.class,
null);
}
/**
* @return Window title.
*/
@Override
public String getTitle() {
return GT._("Check Wikipedia");
}
/**
* @return Menu bar.
*/
@Override
protected JMenuBar createMenuBar() {
JMenuBar menuBar = new JMenuBar();
menuBar.add(createToolsMenu());
menuBar.add(Box.createHorizontalGlue());
return menuBar;
}
/**
* @return Window components.
*/
@Override
protected Component createComponents() {
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;
// Check Wikipedia Project
constraints.fill = GridBagConstraints.BOTH;
constraints.gridwidth = 2;
constraints.gridx = 0;
constraints.weightx = 1;
constraints.weighty = 0;
panel.add(createProjectComponents(), constraints);
constraints.gridy++;
// Page list
constraints.fill = GridBagConstraints.BOTH;
constraints.gridwidth = 1;
constraints.gridx = 0;
constraints.weightx = 0;
constraints.weighty = 1;
panel.add(createPageListComponents(), constraints);
// Contents
constraints.fill = GridBagConstraints.BOTH;
constraints.gridwidth = 1;
constraints.gridx++;
constraints.weightx = 1;
constraints.weighty = 1;
contentPane = new JCloseableTabbedPane();
contentPane.setPreferredSize(new Dimension(900, 600));
contentPane.addChangeListener(EventHandler.create(
ChangeListener.class, this, "displayErrorDescription"));
panel.add(contentPane, constraints);
constraints.gridy++;
updateComponentState();
return panel;
}
/**
* @return Message for the Load button.
*/
private String getLoadMessage() {
if ((allAlgorithms == null) || (allAlgorithms.isEmpty())) {
return GT._("No errors available");
}
if ((selectedAlgorithms == null) || (selectedAlgorithms.isEmpty())) {
return GT._("No errors selected");
}
// Check algorithms selected
boolean allErrorsSelected = true;
boolean allTopPrioritySelected = true;
boolean noTopPrioritySelected = true;
boolean allMiddlePrioritySelected = true;
boolean noMiddlePrioritySelected = true;
boolean allLowestPrioritySelected = true;
boolean noLowestPrioritySelected = true;
boolean allBotOnlyPrioritySelected = true;
boolean noBotOnlyPrioritySelected = true;
for (CheckErrorAlgorithm algorithm : allAlgorithms) {
boolean useAlgorithm = false;
if (algorithm.isAvailable() &&
CWConfigurationError.isPriorityFullyActive(algorithm.getPriority())) {
if (algorithm.hasList()) {
useAlgorithm = true;
}
}
if (useAlgorithm) {
if (!selectedAlgorithms.contains(algorithm)) {
allErrorsSelected = false;
switch (algorithm.getPriority()) {
case CWConfigurationError.PRIORITY_TOP:
allTopPrioritySelected = false;
break;
case CWConfigurationError.PRIORITY_MIDDLE:
allMiddlePrioritySelected = false;
break;
case CWConfigurationError.PRIORITY_LOWEST:
allLowestPrioritySelected = false;
break;
case CWConfigurationError.PRIORITY_BOT_ONLY:
allBotOnlyPrioritySelected = false;
break;
}
} else {
switch (algorithm.getPriority()) {
case CWConfigurationError.PRIORITY_TOP:
noTopPrioritySelected = false;
break;
case CWConfigurationError.PRIORITY_MIDDLE:
noMiddlePrioritySelected = false;
break;
case CWConfigurationError.PRIORITY_LOWEST:
noLowestPrioritySelected = false;
break;
case CWConfigurationError.PRIORITY_BOT_ONLY:
noBotOnlyPrioritySelected = false;
break;
}
}
}
}
// Get message depending on algorithms selected
if (allErrorsSelected) {
return GT._("Load all errors");
} else if (allTopPrioritySelected &&
noMiddlePrioritySelected &&
noLowestPrioritySelected &&
noBotOnlyPrioritySelected) {
return GT._("Load all high priority errors");
} else if (allTopPrioritySelected &&
allMiddlePrioritySelected &&
noLowestPrioritySelected &&
noBotOnlyPrioritySelected) {
return GT._("Load all high and middle priority errors");
} else if (noTopPrioritySelected &&
allMiddlePrioritySelected &&
noLowestPrioritySelected &&
noBotOnlyPrioritySelected) {
return GT._("Load all middle priority errors");
} else if (allTopPrioritySelected &&
allMiddlePrioritySelected &&
allLowestPrioritySelected &&
noBotOnlyPrioritySelected) {
return GT._("Load all high, middle and lowest priority errors");
} else if (allTopPrioritySelected &&
noMiddlePrioritySelected &&
allLowestPrioritySelected &&
noBotOnlyPrioritySelected) {
return GT._("Load all high and lowest priority errors");
} else if (noTopPrioritySelected &&
allMiddlePrioritySelected &&
allLowestPrioritySelected &&
noBotOnlyPrioritySelected) {
return GT._("Load all middle and lowest priority errors");
} else if (noTopPrioritySelected &&
noMiddlePrioritySelected &&
allLowestPrioritySelected &&
noBotOnlyPrioritySelected) {
return GT._("Load all lowest priority errors");
} else if (noTopPrioritySelected &&
noMiddlePrioritySelected &&
noLowestPrioritySelected &&
allBotOnlyPrioritySelected) {
return GT._("Load all errors for bots");
}
// Message with an explicit list of errors
StringBuilder msg = new StringBuilder();
for (int i = 0; i < selectedAlgorithms.size(); i++) {
int j = i;
while ((j + 1 < selectedAlgorithms.size()) &&
(selectedAlgorithms.get(j).getErrorNumber() + 1 == selectedAlgorithms.get(j + 1).getErrorNumber())) {
j++;
}
if (msg.length() > 0) {
msg.append(", ");
}
if (j > i + 1) {
msg.append(selectedAlgorithms.get(i).getErrorNumber());
msg.append("-");
msg.append(selectedAlgorithms.get(j).getErrorNumber());
i = j;
} else {
msg.append(selectedAlgorithms.get(i).getErrorNumber());
}
}
return GT._("Load errors {0}", msg.toString());
}
/**
* Create popup menu for selecting errors.
*/
private void createPopupSelectErrors() {
popupSelectErrors = new JPopupMenu(GT._("Select errors"));
menuItemAlgorithms = new ArrayList<JMenuItem>();
JMenuItem menuItem = null;
menuItem = new JMenuItem(GT._("Select all errors"));
menuItem.setActionCommand(ACTION_SELECT_ERRORS + "*");
menuItem.addActionListener(this);
popupSelectErrors.add(menuItem);
menuItem = new JMenuItem(GT._("Select high priority errors"));
menuItem.setActionCommand(ACTION_SELECT_ERRORS + "P1");
menuItem.addActionListener(this);
popupSelectErrors.add(menuItem);
menuItem = new JMenuItem(GT._("Select middle priority (and above) errors"));
menuItem.setActionCommand(ACTION_SELECT_ERRORS + "P1,P2");
menuItem.addActionListener(this);
popupSelectErrors.add(menuItem);
menuItem = new JMenuItem(GT._("Select middle priority errors"));
menuItem.setActionCommand(ACTION_SELECT_ERRORS + "P2");
menuItem.addActionListener(this);
popupSelectErrors.add(menuItem);
menuItem = new JMenuItem(GT._("Select lowest priority (and above) errors"));
menuItem.setActionCommand(ACTION_SELECT_ERRORS + "P1,P2,P3");
menuItem.addActionListener(this);
popupSelectErrors.add(menuItem);
menuItem = new JMenuItem(GT._("Select lowest priority errors"));
menuItem.setActionCommand(ACTION_SELECT_ERRORS + "P3");
menuItem.addActionListener(this);
popupSelectErrors.add(menuItem);
popupSelectErrors.addSeparator();
final Map<TextAttribute, Boolean> inactiveAttributes = new HashMap<TextAttribute, Boolean>();
inactiveAttributes.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
final int PART_SIZE = 20;
int lastPart = -1;
JMenu subMenu = null;
for (CheckErrorAlgorithm algorithm : allAlgorithms) {
if (algorithm != null) {
int errorNumber = algorithm.getErrorNumber();
boolean useAlgorithm = false;
if (errorNumber > 0) {
if (algorithm.hasList()) {
useAlgorithm = true;
}
}
if (useAlgorithm) {
int part = (errorNumber - 1) / PART_SIZE;
if ((subMenu == null) || (part > lastPart)) {
int from = (part * PART_SIZE) + 1;
int to = (part + 1) * PART_SIZE;
subMenu = new JMenu(GT._(
"Errors from {0} to {1}",
new Object[] { Integer.valueOf(from), Integer.valueOf(to) }));
popupSelectErrors.add(subMenu);
lastPart = part;
}
String label =
algorithm.getErrorNumberString() + " - " +
algorithm.getShortDescriptionReplaced();
menuItem = new JCheckBoxMenuItem(label, selectedAlgorithms.contains(algorithm));
if (!CWConfigurationError.isPriorityActive(algorithm.getPriority())) {
menuItem.setEnabled(false);
menuItem.setFont(menuItem.getFont().deriveFont(inactiveAttributes));
} else if (!algorithm.isAvailable()) {
menuItem.setEnabled(false);
} else if (CWConfigurationError.PRIORITY_BOT_ONLY == algorithm.getPriority()) {
menuItem.setEnabled(false);
menuItem.setFont(menuItem.getFont().deriveFont(Font.ITALIC));
menuItem.setSelected(false);
}
menuItem.setActionCommand(ACTION_SELECT_ERRORS + "+" + algorithm.getErrorNumberString());
menuItem.addActionListener(this);
subMenu.add(menuItem);
while (menuItemAlgorithms.size() <= errorNumber) {
menuItemAlgorithms.add(null);
}
menuItemAlgorithms.set(errorNumber, menuItem);
}
}
}
// Select only
popupSelectErrors.addSeparator();
lastPart = -1;
subMenu = null;
for (CheckErrorAlgorithm algorithm : allAlgorithms) {
if (algorithm != null) {
int errorNumber = algorithm.getErrorNumber();
boolean useAlgorithm = false;
if (errorNumber > 0) {
if ((errorNumber <= CheckErrorAlgorithm.MAX_ERROR_NUMBER_WITH_LIST) ||
algorithm.hasSpecialList()) {
useAlgorithm = true;
}
}
if (useAlgorithm) {
int part = (errorNumber - 1) / PART_SIZE;
if ((subMenu == null) || (part > lastPart)) {
int from = (part * PART_SIZE) + 1;
int to = (part + 1) * PART_SIZE;
subMenu = new JMenu(
GT._("Select only") + " - " +
GT._(
"Errors from {0} to {1}",
new Object[] { Integer.valueOf(from), Integer.valueOf(to) }));
popupSelectErrors.add(subMenu);
lastPart = part;
}
String label =
algorithm.getErrorNumberString() + " - " +
algorithm.getShortDescriptionReplaced();
menuItem = new JMenuItem(label);
if (!CWConfigurationError.isPriorityActive(algorithm.getPriority())) {
menuItem.setEnabled(false);
menuItem.setFont(menuItem.getFont().deriveFont(inactiveAttributes));
} else if (!algorithm.isAvailable()) {
menuItem.setEnabled(false);
} else if (CWConfigurationError.PRIORITY_BOT_ONLY == algorithm.getPriority()) {
menuItem.setEnabled(false);
menuItem.setFont(menuItem.getFont().deriveFont(Font.ITALIC));
}
menuItem.setActionCommand(ACTION_SELECT_ERRORS + algorithm.getErrorNumberString());
menuItem.addActionListener(this);
subMenu.add(menuItem);
}
}
}
// Saved selections
popupSelectErrors.addSeparator();
menuItem = new JMenuItem(GT._("Save current selection"));
menuItem.setActionCommand(ACTION_SELECT_ERRORS + "S");
menuItem.addActionListener(this);
popupSelectErrors.add(menuItem);
menuUseSelection = new JMenu(GT._("Use selection"));
popupSelectErrors.add(menuUseSelection);
menuDeleteSelection = new JMenu(GT._("Delete selection"));
popupSelectErrors.add(menuDeleteSelection);
updateSavedSelections();
}
/**
* Update menus for the saved selections.
*/
private void updateSavedSelections() {
menuUseSelection.removeAll();
menuDeleteSelection.removeAll();
Configuration config = Configuration.getConfiguration();
Properties properties = config.getProperties(null, Configuration.ARRAY_CHECK_SELECTION);
Set<Object> keySet = properties.keySet();
List<String> keyList = new ArrayList<String>();
for (Object key : keySet) {
keyList.add(key.toString());
}
Collections.sort(keyList);
JMenuItem menuItem = null;
for (String name : keyList) {
String selection = properties.getProperty(name);
menuItem = new JMenuItem(name + ": " + selection);
menuItem.setActionCommand(ACTION_SELECT_ERRORS + selection);
menuItem.addActionListener(this);
menuUseSelection.add(menuItem);
menuItem = new JMenuItem(name + ": " + selection);
menuItem.setActionCommand(ACTION_SELECT_ERRORS + "D" + name);
menuItem.addActionListener(this);
menuDeleteSelection.add(menuItem);
}
}
/**
* Update popup menu for selecting errors.
*/
private void updatePopupSelectErrors() {
for (CheckErrorAlgorithm algorithm : allAlgorithms) {
if (algorithm != null) {
int errorNumber = algorithm.getErrorNumber();
if (errorNumber < menuItemAlgorithms.size()) {
JMenuItem menuItem = menuItemAlgorithms.get(errorNumber);
if (menuItem != null) {
menuItem.setSelected(selectedAlgorithms.contains(algorithm));
}
}
}
}
}
/**
* @return Project components
*/
private Component createProjectComponents() {
JPanel panel = new JPanel(new GridBagLayout());
Configuration configuration = Configuration.getConfiguration();
// 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(1, 1, 1, 1);
constraints.ipadx = 0;
constraints.ipady = 0;
constraints.weightx = 0;
constraints.weighty = 0;
// Initialize algorithms list
allAlgorithms = CheckErrorAlgorithms.getAlgorithms(getWikipedia());
if (allAlgorithms == null) {
allAlgorithms = Collections.emptyList();
}
selectedAlgorithms = new ArrayList<CheckErrorAlgorithm>();
for (CheckErrorAlgorithm algorithm : allAlgorithms) {
if (algorithm.isAvailable() &&
CWConfigurationError.isPriorityFullyActive(algorithm.getPriority())) {
selectedAlgorithms.add(algorithm);
}
}
createPopupSelectErrors();
// Loading
JToolBar toolbarLoad = new JToolBar(SwingConstants.HORIZONTAL);
toolbarLoad.setFloatable(false);
modelMaxErrors = new SpinnerNumberModel(
configuration.getInt(
null,
ConfigurationValueInteger.CHECK_NB_ERRORS),
10, 1000, 5);
JSpinner spinMaxErrors = new JSpinner(modelMaxErrors);
spinMaxErrors.setPreferredSize(new Dimension(80, 25));
spinMaxErrors.setMaximumSize(new Dimension(80, 25));
JLabel labelMaxErrors = Utilities.createJLabel(
GT._("Maximum number of errors for Check Wiki :"));
labelMaxErrors.setLabelFor(spinMaxErrors);
labelMaxErrors.setHorizontalAlignment(SwingConstants.TRAILING);
toolbarLoad.add(labelMaxErrors);
toolbarLoad.add(spinMaxErrors);
toolbarLoad.addSeparator();
buttonSelectErrors = Utilities.createJButton(
"gnome-preferences-desktop.png", EnumImageSize.NORMAL,
GT._("Select errors"), true, null);
buttonSelectErrors.addActionListener(EventHandler.create(
ActionListener.class, this, "actionChooseErrors"));
toolbarLoad.add(buttonSelectErrors);
buttonLoadErrors = Utilities.createJButton(
"gnome-view-refresh.png", EnumImageSize.NORMAL,
getLoadMessage(), true, null);
buttonLoadErrors.setActionCommand(ACTION_RELOAD);
buttonLoadErrors.addActionListener(this);
buttonLoadErrors.setPreferredSize(new Dimension(800, 20));
buttonLoadErrors.setHorizontalAlignment(SwingConstants.LEADING);
buttonLoadErrors.setComponentPopupMenu(popupSelectErrors);
buttonLoadErrors.setToolTipText(GT._("Right click to select errors"));
toolbarLoad.add(buttonLoadErrors);
constraints.fill = GridBagConstraints.BOTH;
constraints.gridwidth = 3;
constraints.gridx = 0;
constraints.weightx = 1;
constraints.weighty = 0;
panel.add(toolbarLoad, constraints);
constraints.gridy++;
// List of errors managed by the project
JLabel labelErrors = Utilities.createJLabel(GT._("List of errors detected :"));
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridwidth = 1;
constraints.gridx = 0;
constraints.weightx = 0;
constraints.weighty = 0;
panel.add(labelErrors, constraints);
modelAllErrors = new DefaultComboBoxModel<Object>();
listAllErrors = new JComboBox<Object>(modelAllErrors);
listAllErrors.addActionListener(new ActionListener() {
@Override
public void actionPerformed(@SuppressWarnings("unused") ActionEvent e) {
actionSelectErrorType();
}
});
constraints.gridx++;
constraints.weightx = 1;
panel.add(listAllErrors, constraints);
JToolBar toolbar = new JToolBar(SwingConstants.HORIZONTAL);
toolbar.setFloatable(false);
buttonReloadError = Utilities.createJButton(
"gnome-view-refresh.png", EnumImageSize.NORMAL,
GT._("Reload error"), false, null);
buttonReloadError.addActionListener(EventHandler.create(
ActionListener.class, this, "actionReloadError"));
toolbar.add(buttonReloadError);
buttonErrorDetail = Utilities.createJButton(
"tango-help-browser.png", EnumImageSize.NORMAL,
GT._("Detail"), false, null);
buttonErrorDetail.addActionListener(EventHandler.create(
ActionListener.class, this, "actionErrorDetail"));
buttonErrorDetail.setEnabled(false);
toolbar.add(buttonErrorDetail);
buttonErrorList = Utilities.createJButton(
"gnome-web-browser.png", EnumImageSize.NORMAL,
GT._("List on {0}", CheckWiki.getServerName(getWikipedia())), false, null);
buttonErrorList.addActionListener(
EventHandler.create(ActionListener.class, this, "actionErrorList"));
buttonErrorList.setEnabled(false);
toolbar.add(buttonErrorList);
buttonWhiteList = Utilities.createJButton(
"gnome-accessories-text-editor.png", EnumImageSize.NORMAL,
GT._("View or edit whitelist"), false, null);
buttonWhiteList.addActionListener(EventHandler.create(
ActionListener.class, this, "actionErrorWhiteList"));
buttonWhiteList.setEnabled(false);
toolbar.add(buttonWhiteList);
constraints.gridx++;
constraints.weightx = 0;
panel.add(toolbar, constraints);
constraints.gridx = 0;
constraints.gridy++;
// Error description
textDescription = HTMLPane.createHTMLPane(null);
textDescription.setPreferredSize(new Dimension(500, 100));
textDescription.setMinimumSize(new Dimension(200, 100));
JScrollPane scrollDescription = new JScrollPane(textDescription);
scrollDescription.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
// Parameters description
textParameters = HTMLPane.createHTMLPane(null);
textParameters.setPreferredSize(new Dimension(500, 100));
textParameters.setMinimumSize(new Dimension(200, 100));
JScrollPane scrollParameters = new JScrollPane(textParameters);
scrollParameters.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
// Split pane
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
splitPane.setLeftComponent(scrollDescription);
splitPane.setRightComponent(scrollParameters);
splitPane.setPreferredSize(new Dimension(700, 100));
splitPane.setMinimumSize(new Dimension(300, 100));
splitPane.setResizeWeight(1.0);
constraints.fill = GridBagConstraints.BOTH;
constraints.gridwidth = 3;
constraints.gridx = 0;
constraints.weightx = 1;
constraints.weighty = 1;
panel.add(splitPane, constraints);
constraints.gridy++;
return panel;
}
/**
* @return Page list components
*/
private Component createPageListComponents() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(), GT._("Pages")));
modelPages = new DefaultListModel<CheckErrorPage>();
listPages = new JList<CheckErrorPage>(modelPages);
// 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;
// Load pages
JToolBar toolbarButtons = new JToolBar(SwingConstants.HORIZONTAL);
toolbarButtons.setFloatable(false);
JButton buttonLoad = Utilities.createJButton(GT._("&Load pages"), null);
buttonLoad.addActionListener(EventHandler.create(
ActionListener.class, this, "actionLoadPages"));
toolbarButtons.add(buttonLoad);
ActionFullAnalysis.addButton(
getParentComponent(), toolbarButtons, getWikipedia(), listPages, null, true, true);
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 0;
constraints.weightx = 0;
constraints.weighty = 0;
panel.add(toolbarButtons, constraints);
constraints.gridy++;
// Page List
listPages.setCellRenderer(new CheckErrorPageListCellRenderer(true));
listPages.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
listPages.addMouseListener(new MouseAdapter() {
/* (non-Javadoc)
* @see java.awt.event.MouseAdapter#mouseClicked(java.awt.event.MouseEvent)
*/
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
if (e.getClickCount() != 2) {
return;
}
actionLoadPages();
}
});
JScrollPane scrollPages = new JScrollPane(listPages);
scrollPages.setMinimumSize(new Dimension(200, 200));
scrollPages.setPreferredSize(new Dimension(200, 300));
scrollPages.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 0;
constraints.weightx = 0;
constraints.weighty = 1;
panel.add(scrollPages, constraints);
constraints.gridy++;
return panel;
}
/**
* @param pane Pane.
* @param page Page.
* @param pageErrors Errors detected in the page.
* @return Contents components.
*/
public CheckWikiContentPanel createContentsComponents(
JTabbedPane pane, Page page,
List<CheckError> pageErrors) {
CheckWikiContentPanel panel = new CheckWikiContentPanel(
this, pane, page, pageErrors);
panel.initialize();
return panel;
}
/**
* Callback called at the end of the Reload Worker.
*/
@Override
protected void afterFinishedReloadWorker() {
super.afterFinishedReloadWorker();
CheckWiki checkWiki = APIFactory.getCheckWiki();
checkWiki.addListener(this);
analyzeCheckWiki();
}
/**
* Analyze the Check Wiki page contents.
*/
private void analyzeCheckWiki() {
//String contents = projectPage.getContents();
//errors = CheckError.initCheckErrors(getWikipedia(), contents);
if (modelAllErrors != null) {
int selectedError = 0;
if (listAllErrors.getSelectedItem() instanceof CheckError) {
selectedError = ((CheckError) listAllErrors.getSelectedItem()).getErrorNumber();
}
modelAllErrors.removeAllElements();
Configuration config = Configuration.getConfiguration();
boolean showAllErrors = config.getBoolean(
null,
ConfigurationValueBoolean.CHECK_SHOW_0_ERRORS);
int selectedIndex = -1;
if (errors != null) {
for (CheckError error : errors) {
if ((error.getPageCount() > 0) || (showAllErrors)) {
if (error.getErrorNumber() == selectedError) {
selectedIndex = modelAllErrors.getSize();
}
modelAllErrors.addElement(error);
}
}
if (!getPagesWithSeveralErrors().isEmpty()) {
modelAllErrors.insertElementAt(GT._("Pages with several errors"), 0);
if (selectedIndex > 0) {
selectedIndex++;
}
}
}
selectedIndex = Math.max(selectedIndex, 0);
if (listAllErrors.getItemCount() > selectedIndex) {
listAllErrors.setSelectedIndex(selectedIndex);
}
}
}
/**
* @return List of pages with several errors.
*/
private List<String> getPagesWithSeveralErrors() {
Set<String> pagesWithMultipleErrors = new HashSet<String>();
Set<String> pagesWithError = new HashSet<String>();
for (CheckError error : errors) {
for (int pageNumber = 0; pageNumber < error.getPageCount(); pageNumber++) {
Page page = error.getPage(pageNumber);
String title = page.getTitle();
if (pagesWithError.contains(title)) {
pagesWithMultipleErrors.add(title);
} else {
pagesWithError.add(title);
}
}
}
List<String> result = new ArrayList<String>(pagesWithMultipleErrors);
Collections.sort(result);
return result;
}
/**
* @param pageTitle Page title.
* @return List of errors for the page.
*/
List<CheckError> getErrorsForPage(String pageTitle) {
List<CheckError> result = new ArrayList<CheckError>();
if (pageTitle != null) {
for (CheckError error : errors) {
for (int pageNumber = 0; pageNumber < error.getPageCount(); pageNumber++) {
Page page = error.getPage(pageNumber);
String title = page.getTitle();
if (Page.areSameTitle(pageTitle, title)) {
result.add(error);
}
}
}
}
return result;
}
/**
* Action called when an error type is selected.
*/
void actionSelectErrorType() {
Object selection = listAllErrors.getSelectedItem();
modelPages.clear();
if (selection instanceof CheckError) {
CheckError error = (CheckError) selection;
// Button status
buttonReloadError.setEnabled(true);
buttonErrorDetail.setEnabled(true);
buttonErrorList.setEnabled(true);
buttonWhiteList.setEnabled(true);
displayErrorDescription();
// Pages
int nbPages = error.getPageCount();
for (int numPage = 0; numPage < nbPages; numPage++) {
Page page = error.getPage(numPage);
CheckErrorPage errorPage = new CheckErrorPage(page, error.getAlgorithm());
if ((errorPage.isInWhiteList()) && (page.getPageId() != null)) {
markPageAsFixed(error.getAlgorithm().getErrorNumberString(), page);
} else {
modelPages.addElement(errorPage);
}
}
setPageLoaded(false);
actionSelectPages();
updateComponentState();
} else {
buttonReloadError.setEnabled(false);
buttonErrorDetail.setEnabled(false);
buttonErrorList.setEnabled(false);
buttonWhiteList.setEnabled(false);
displayErrorDescription();
if (selection instanceof String) {
List<String> listErrorPages = getPagesWithSeveralErrors();
for (String page : listErrorPages) {
CheckErrorPage errorPage = new CheckErrorPage(DataManager.getPage(getWikipedia(), page, null, null, null), null);
modelPages.addElement(errorPage);
}
}
setPageLoaded(false);
actionSelectPages();
updateComponentState();
}
}
/**
* Display description of an error.
*/
public void displayErrorDescription() {
CheckErrorAlgorithm algorithm = null;
// Look in the current page
if ((contentPane != null) &&
(contentPane.getSelectedComponent() != null) &&
(contentPane.getSelectedComponent() instanceof CheckWikiContentPanel)) {
CheckWikiContentPanel panel = (CheckWikiContentPanel) contentPane.getSelectedComponent();
CheckErrorPage error = panel.getSelectedError();
if (error != null) {
algorithm = error.getAlgorithm();
}
}
// Look in the global list of errors
if (algorithm == null) {
Object selection = listAllErrors.getSelectedItem();
if (selection instanceof CheckError) {
CheckError error = (CheckError) selection;
algorithm = error.getAlgorithm();
}
}
// Display description
displayErrorDescription(algorithm);
}
/**
* Display description of an error.
*
* @param algorithm Algorithm.
*/
private void displayErrorDescription(CheckErrorAlgorithm algorithm) {
// Check error number
int errorNumber = -1;
if (algorithm != null) {
errorNumber = algorithm.getErrorNumber();
}
if (errorNumber == lastErrorDisplayed) {
return;
}
lastErrorDisplayed = errorNumber;
String description = null;
if (algorithm != null) {
description = algorithm.getLongDescription();
if ((description == null) || (description.trim().length() == 0)) {
description = algorithm.getShortDescription();
}
}
// Display description
if ((algorithm != null) && (description != null)) {
// Error type description
textDescription.setText(description);
// Parameters description
Configuration config = Configuration.getConfiguration();
boolean secured = config.getBoolean(null, ConfigurationValueBoolean.SECURE_URL);
EnumWikipedia wiki = getWikipedia();
String translationPage = wiki.getConfiguration().getString(
WPCConfigurationString.CW_TRANSLATION_PAGE);
String url = wiki.getSettings().getURL(translationPage, true, secured);
StringBuilder parametersDescription = new StringBuilder();
parametersDescription.append(GT._(
"The error n°{0} can be configured with the following parameters in the <a href=\"{1}\">translation file</a> :",
new Object[] { Integer.toString(errorNumber), url }));
parametersDescription.append("\n<ul>");
Map<String, String> parameters = algorithm.getParameters();
SortedSet<String> keySet = new TreeSet<>(parameters.keySet());
for (String key: keySet) {
parametersDescription.append("<li><b>");
parametersDescription.append(key);
parametersDescription.append("</b>: ");
parametersDescription.append(parameters.get(key));
parametersDescription.append("</li>\n");
}
parametersDescription.append("</ul>");
textParameters.setText(parametersDescription.toString());
} else {
textDescription.clearText();
textParameters.clearText();
}
}
/* (non-Javadoc)
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
@Override
public void actionPerformed(ActionEvent e) {
if (e == null) {
return;
}
super.actionPerformed(e);
if ((e.getActionCommand() != null) &&
(e.getActionCommand().startsWith(ACTION_SELECT_ERRORS))) {
actionSelectErrors(e.getActionCommand().substring(ACTION_SELECT_ERRORS.length()));
}
}
/**
* Action called when the Select Errors button is pressed.
*/
public void actionChooseErrors() {
popupSelectErrors.show(
buttonSelectErrors,
0,
buttonSelectErrors.getHeight());
}
/**
* Action called when selected errors changes.
*
* @param command Command.
*/
private void actionSelectErrors(String command) {
if (command == null) {
return;
}
// Select all
if (command.equals("*")) {
selectedAlgorithms.clear();
for (CheckErrorAlgorithm algorithm : allAlgorithms) {
if (algorithm.isAvailable() &&
algorithm.hasList() &&
CWConfigurationError.isPriorityFullyActive(algorithm.getPriority())) {
selectedAlgorithms.add(algorithm);
}
}
// Save current selection
} else if (command.equals("S")) {
// Retrieve configuration name
String name = askForValue(GT._("What is the name of the selection?"), null, null);
if ((name == null) || (name.isEmpty())) {
return;
}
// Creates a string representing the current selection
StringBuilder selection = new StringBuilder();
Collections.sort(selectedAlgorithms, new CheckErrorAlgorithmComparator());
for (CheckErrorAlgorithm algorithm : selectedAlgorithms) {
if (selection.length() > 0) {
selection.append(",");
}
selection.append(algorithm.getErrorNumber());
}
String strSelection = selection.toString();
// Save configuration
Configuration config = Configuration.getConfiguration();
config.setSubString(null, Configuration.ARRAY_CHECK_SELECTION, name, strSelection);
updateSavedSelections();
// Delete a saved selection
} else if (command.startsWith("D")) {
String name = command.substring(1);
Configuration config = Configuration.getConfiguration();
config.setSubString(null, Configuration.ARRAY_CHECK_SELECTION, name, null);
updateSavedSelections();
} else {
boolean selectionCleared = false;
String[] units = command.split(",");
for (int i = 0; i < units.length; i++) {
String unit = units[i].trim();
// Select priority
if (unit.startsWith("P")) {
if (!selectionCleared) {
selectedAlgorithms.clear();
selectionCleared = true;
}
try {
int priority = Integer.parseInt(unit.substring(1));
for (CheckErrorAlgorithm algorithm : allAlgorithms) {
if (algorithm.isAvailable() &&
algorithm.hasList() &&
CWConfigurationError.isPriorityActive(algorithm.getPriority()) &&
(priority == algorithm.getPriority())) {
selectedAlgorithms.add(algorithm);
}
}
} catch (NumberFormatException e) {
//
}
// Invert error selection
} else if (unit.startsWith("+")) {
try {
int errorNumber = Integer.parseInt(unit.substring(1));
for (CheckErrorAlgorithm algorithm : allAlgorithms) {
if (algorithm.isAvailable() &&
CWConfigurationError.isPriorityActive(algorithm.getPriority()) &&
(errorNumber == algorithm.getErrorNumber())) {
if (selectedAlgorithms.contains(algorithm)) {
selectedAlgorithms.remove(algorithm);
} else {
selectedAlgorithms.add(algorithm);
}
}
}
} catch (NumberFormatException e) {
//
}
// Add an error
} else {
if (!selectionCleared) {
selectedAlgorithms.clear();
selectionCleared = true;
}
try {
int errorNumber = Integer.parseInt(unit);
for (CheckErrorAlgorithm algorithm : allAlgorithms) {
if (algorithm.isAvailable() &&
algorithm.hasList() &&
CWConfigurationError.isPriorityActive(algorithm.getPriority()) &&
(errorNumber == algorithm.getErrorNumber())) {
if (!selectedAlgorithms.contains(algorithm)) {
selectedAlgorithms.add(algorithm);
}
}
}
} catch (NumberFormatException e) {
//
}
}
}
}
updatePopupSelectErrors();
buttonLoadErrors.setText(getLoadMessage());
}
/**
* Action called to display error detail.
*/
public void actionErrorDetail() {
Object selected = listAllErrors.getSelectedItem();
if ((selected instanceof CheckError) &&
(Utilities.isDesktopSupported())) {
EnumWikipedia wiki = getWikipedia();
CheckError error = (CheckError) selected;
if (error.getAlgorithm().getLink() != null) {
Utilities.browseURL(wiki, error.getAlgorithm().getLink(), true);
} else {
DecimalFormat format = new DecimalFormat("000");
String description =
"error_" +
format.format(error.getErrorNumber()) +
"_link_" +
wiki.getSettings().getCodeCheckWiki();
String translationPage = wiki.getConfiguration().getString(
WPCConfigurationString.CW_TRANSLATION_PAGE);
Utilities.displayInformationMessage(getParentComponent(), GT._(
"There''s no page defined for this error type.\n" +
"If you want to define a page you need to add :\n" +
" {0} = <page name> END\n" +
"to the translation page ({1}) on \"{2}\"",
new Object[] { description, translationPage, wiki.toString()
}));
}
}
}
/**
* Action called to display error list on server.
*/
public void actionErrorList() {
Object selected = listAllErrors.getSelectedItem();
if ((selected instanceof CheckError) &&
(Utilities.isDesktopSupported())) {
CheckError error = (CheckError) selected;
CheckWiki checkWiki = APIFactory.getCheckWiki();
String url = checkWiki.getUrlDescription(getWikipedia(), error.getAlgorithm());
Utilities.browseURL(url);
}
}
/**
* Action called to display error white list.
*/
public void actionErrorWhiteList() {
Object selected = listAllErrors.getSelectedItem();
if ((selected instanceof CheckError) &&
(Utilities.isDesktopSupported())) {
EnumWikipedia wiki = getWikipedia();
CheckError error = (CheckError) selected;
if (error.getAlgorithm().getWhiteListPageName() != null) {
Utilities.browseURL(wiki, error.getAlgorithm().getWhiteListPageName(), true);
} else {
DecimalFormat format = new DecimalFormat("000");
String parameter =
"error_" +
format.format(error.getErrorNumber()) +
"_whitelistpage_" +
wiki.getSettings().getCodeCheckWiki();
String translationPage = wiki.getConfiguration().getString(
WPCConfigurationString.CW_TRANSLATION_PAGE);
Utilities.displayInformationMessage(getParentComponent(), GT._(
"There''s no whitelist defined for this error type.\n" +
"If you want to define a whitelist, you need to add:\n" +
" {0} = <page name> END\n" +
"to the translation page ({1}) on \"{2}\"",
new Object[] { parameter, translationPage, wiki.toString()
}));
}
}
}
/**
* Action called for selecting pages.
*/
public void actionSelectPages() {
Configuration config = Configuration.getConfiguration();
int max = config.getInt(null, ConfigurationValueInteger.MAXIMUM_PAGES);
if (max > modelPages.getSize()) {
max = modelPages.getSize();
}
if (max <= 0) {
listPages.clearSelection();
return;
}
listPages.getSelectionModel().setSelectionInterval(0, max -1);
}
/**
* Action called when requesting to load selected pages.
*/
public void actionLoadPages() {
final List<CheckErrorPage> selection = listPages.getSelectedValuesList();
final List<Page> pages = new ArrayList<Page>();
if (selection != null) {
for (CheckErrorPage errorPage : selection) {
pages.add(errorPage.getPage());
}
}
if (pages.size() > 0) {
RetrieveContentWorker contentWorker = new RetrieveContentWorker(getWikipedia(), this, pages);
contentWorker.setListener(new DefaultBasicWorkerListener() {
/* (non-Javadoc)
* @see org.wikipediacleaner.gui.swing.basic.DefaultBasicWorkerListener#beforeFinished(org.wikipediacleaner.gui.swing.basic.BasicWorker)
*/
@Override
public void beforeFinished(BasicWorker worker) {
super.beforeFinished(worker);
final List<CheckWikiContentPanel> contentPanels = new ArrayList<CheckWikiContentPanel>();
for (Page page : pages) {
while (page != null) {
Object errorSelected = modelAllErrors.getSelectedItem();
final CheckWikiContentPanel contentPanel = createContentsComponents(
contentPane, page,
(errorSelected instanceof CheckError) ?
Collections.singletonList((CheckError) errorSelected) :
getErrorsForPage(page.getTitle()));
contentPane.add(contentPanel);
contentPane.setSelectedComponent(contentPanel);
contentPanels.add(contentPanel);
if (page.isRedirect()) {
List<Page> redirects = page.getRedirects();
if ((redirects != null) && (redirects.size() > 0)) {
page = redirects.get(0);
} else {
page = null;
}
} else {
page = null;
}
}
}
yesAll = false;
noAll = false;
List<String> messages = new ArrayList<>();
for (CheckWikiContentPanel contentPanel : contentPanels) {
contentPanel.actionPageSelected(messages);
}
if (!messages.isEmpty()) {
StringBuilder message = new StringBuilder();
for (String line : messages) {
if (message.length() > 0) {
message.append('\n');
}
message.append(line);
}
displayWarning(message.toString());
}
}
//
});
contentWorker.start();
} else {
updateComponentState();
}
}
/**
* Action called when Reload button is pressed.
*/
@Override
protected void actionReload() {
clean();
contentPane.removeAll();
if (errors == null) {
errors = new ArrayList<CheckError>();
}
CheckWikiProjectWorker reloadWorker = new CheckWikiProjectWorker(
getWikipedia(), this, errors, selectedAlgorithms,
true, modelMaxErrors.getNumber().intValue());
setupReloadWorker(reloadWorker);
reloadWorker.start();
}
/**
* Action called when Reload Error button is pressed.
*/
public void actionReloadError() {
Object selected = listAllErrors.getSelectedItem();
if (selected instanceof CheckError) {
CheckError error = (CheckError) selected;
List<CheckErrorAlgorithm> algorithms = Collections.singletonList(error.getAlgorithm());
CheckWikiProjectWorker reloadWorker = new CheckWikiProjectWorker(
getWikipedia(), this, errors, algorithms,
true, modelMaxErrors.getNumber().intValue());
setupReloadWorker(reloadWorker);
reloadWorker.start();
}
}
/**
* @param page
* @param errorNumber
* @see org.wikipediacleaner.api.check.CheckWikiListener#pageFixed(org.wikipediacleaner.api.data.Page, int)
*/
@Override
public void pageFixed(Page page, int errorNumber) {
if ((errors == null) || (errors.isEmpty())) {
return;
}
Iterator<CheckError> itError = errors.iterator();
while (itError.hasNext()) {
CheckError error = itError.next();
if (error.getErrorNumber() == errorNumber) {
error.remove(page);
}
}
requestUpdate();
}
private boolean updateNeeded = false;
/**
* Request for an update of the display.
*/
private void requestUpdate() {
updateNeeded = true;
if (SwingUtilities.isEventDispatchThread()) {
doUpdate();
} else {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
doUpdate();
}
});
}
}
/**
* Update the display. Needs to be run on the event dispatcher thread.
*/
void doUpdate() {
if (!updateNeeded) {
return;
}
updateNeeded = false;
// Remove errors with no pages
Configuration config = Configuration.getConfiguration();
boolean showAllErrors = config.getBoolean(
null,
ConfigurationValueBoolean.CHECK_SHOW_0_ERRORS);
if (!showAllErrors) {
Iterator<CheckError> itError = errors.iterator();
while (itError.hasNext()) {
CheckError error = itError.next();
if (error.getPageCount() == 0) {
itError.remove();
modelAllErrors.removeElement(error);
}
}
}
// Remove list of pages with several errors if needed
if ((modelAllErrors.getSize() > 0) &&
!(modelAllErrors.getElementAt(0) instanceof CheckError)) {
List<String> severalErrors = getPagesWithSeveralErrors();
if ((severalErrors != null) && severalErrors.isEmpty()) {
modelAllErrors.removeElementAt(0);
}
}
// Update display
actionSelectErrorType();
}
}