Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sorting and disabling functionality for ExplanationServices #1059

Merged
merged 5 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
package org.protege.editor.owl.ui.explanation;

import org.protege.editor.core.prefs.Preferences;
import org.protege.editor.core.prefs.PreferencesManager;
import org.protege.editor.owl.model.inference.ReasonerPreferences;
import org.semanticweb.owlapi.model.OWLAxiom;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;

public class ExplanationDialog extends JPanel {

public static final String PREFERENCES_SET_KEY = "EXPLANATION_PREFS_SET";

public static final String DEFAULT_EXPLANATION_ID = "PREFERRED_PLUGIN_ID";

private JPanel explanationContainer;

private ExplanationResult explanation;
Expand Down Expand Up @@ -46,22 +37,27 @@ public ExplanationDialog(ExplanationManager explanationManager, OWLAxiom axiom)
private JComboBox<ExplanationService> createComboBox(Collection<ExplanationService> explanationServices) {
ExplanationService[] teacherArray = explanationServices.toArray(new ExplanationService[explanationServices.size()]);
final JComboBox<ExplanationService> selector = new JComboBox<>(teacherArray);
final ExplanationPreferences prefs = ExplanationPreferences.create().load();
if (teacherArray.length > 0) {
ExplanationService selected = teacherArray[0];
String id = getDefaultPluginId();
if (id != null) {
for (ExplanationService t : explanationServices) {
if (id.equals(t.getPluginId())) {
selected = t;
}
}
}
if (prefs.useLastExplanationService) {
String id = prefs.defaultExplanationService;
if (id != null) {
for (ExplanationService t : explanationServices) {
if (id.equals(t.getPluginId())) {
selected = t;
}
}
}
}
selector.setSelectedItem(selected);
explanation = selected.explain(axiom);
}
selector.addActionListener(e -> {
ExplanationService t = (ExplanationService) selector.getSelectedItem();
setDefaultPluginId(t.getPluginId());
prefs.load();
prefs.defaultExplanationService = t.getPluginId();
prefs.save();
explanationContainer.removeAll();
if (explanation != null) {
explanation.dispose();
Expand All @@ -73,19 +69,6 @@ private JComboBox<ExplanationService> createComboBox(Collection<ExplanationServi
return selector;
}


public String getDefaultPluginId() {
PreferencesManager prefMan = PreferencesManager.getInstance();
Preferences prefs = prefMan.getPreferencesForSet(PREFERENCES_SET_KEY, ReasonerPreferences.class);
return prefs.getString(DEFAULT_EXPLANATION_ID, null);
}

public void setDefaultPluginId(String id) {
PreferencesManager prefMan = PreferencesManager.getInstance();
Preferences prefs = prefMan.getPreferencesForSet(PREFERENCES_SET_KEY, ReasonerPreferences.class);
prefs.putString(DEFAULT_EXPLANATION_ID, id);
}

public void dispose() {
if (explanation != null) {
explanation.dispose();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.Map;
import java.util.TreeMap;

import javax.swing.JDialog;
import javax.swing.JOptionPane;
Expand All @@ -26,8 +28,10 @@ public class ExplanationManager implements Disposable {

private final OWLEditorKit editorKit;

private final Collection<ExplanationService> explanationServices = new HashSet<>();

private final Collection<ExplanationService> explanationServices = new ArrayList<>();

private final Collection<ExplanationService> enabledServices = new ArrayList<>();

private final Collection<ExplanationDialog> openedExplanations = new HashSet<>();

public ExplanationManager(OWLEditorKit editorKit) {
Expand All @@ -37,16 +41,50 @@ public ExplanationManager(OWLEditorKit editorKit) {

public void reload() {
ExplanationPluginLoader loader = new ExplanationPluginLoader(editorKit);
explanationServices.clear();
// use TreeMap for alphabetical ordering
Map<String, ExplanationService> sortedExplanationServices = new TreeMap<>();
for (ExplanationPlugin plugin : loader.getPlugins()) {
ExplanationService teacher = null;
try {
teacher = plugin.newInstance();
teacher.initialise();
sortedExplanationServices.put(teacher.getPluginId(), teacher);
} catch (Exception e) {
logger.error("An error occurred whilst initialising an explanation service {}.", plugin.getName(), e);
}
}

// add ExplanationServices in the order defined in the preferences
final ExplanationPreferences prefs = ExplanationPreferences.create().load();
explanationServices.clear();
for (String id : prefs.explanationServicesList) {
ExplanationService teacher = sortedExplanationServices.get(id);
if (teacher != null) {
explanationServices.add(teacher);
sortedExplanationServices.remove(id);
}
catch (Exception e) {
logger.error("An error occurred whilst initialising an explanation service {}.", plugin.getName(), e);
}

if (!sortedExplanationServices.isEmpty()) {
// add new ExplanationServices (which do not occur in the preferences yet) in
// alphabetical order at the end
for (ExplanationService teacher : sortedExplanationServices.values()) {
explanationServices.add(teacher);
}
}

// update preferences according to current list (adding new and removing old
// ExplanationServices)
prefs.explanationServicesList = new ArrayList<>();
for (ExplanationService teacher : explanationServices) {
prefs.explanationServicesList.add(teacher.getPluginId());
}
prefs.save();

enabledServices.clear();
for (ExplanationService teacher : explanationServices) {
if (!prefs.disabledExplanationServices.contains(teacher.getPluginId())) {
enabledServices.add(teacher);
}
}
}
Expand All @@ -64,8 +102,8 @@ public Collection<ExplanationService> getExplainers() {
}

public Collection<ExplanationService> getTeachers(OWLAxiom axiom) {
Set<ExplanationService> smartTeachers = new HashSet<>();
for (ExplanationService teacher : explanationServices) {
Collection<ExplanationService> smartTeachers = new ArrayList<>();
for (ExplanationService teacher : enabledServices) {
if (teacher.hasExplanation(axiom)) {
smartTeachers.add(teacher);
}
Expand All @@ -74,7 +112,7 @@ public Collection<ExplanationService> getTeachers(OWLAxiom axiom) {
}

public boolean hasExplanation(OWLAxiom axiom) {
for (ExplanationService explanationService : explanationServices) {
for (ExplanationService explanationService : enabledServices) {
if (explanationService.hasExplanation(axiom)) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.protege.editor.owl.ui.explanation;

import java.util.Collections;
import java.util.List;

import org.protege.editor.core.prefs.Preferences;
import org.protege.editor.core.prefs.PreferencesManager;

public class ExplanationPreferences {

private static final String PREFERENCES_SET_KEY_ = "EXPLANATION_PREFS_SET",
DEFAULT_EXPLANATION_ID_ = "PREFERRED_PLUGIN_ID",
USE_LAST_EXPLANATION_SERVICE_KEY_ = "USE_LAST_EXPLANATION_SERVICE",
EXPLANATION_SERVICES_LIST_KEY_ = "EXPLANATION_SERVICES_LIST",
DISABLED_EXPLANATION_SERVICES_KEY_ = "DISABLED_EXPLANATION_SERVICES";

private final static String DEFAULT_DEFAULT_EXPLANATION_ID_ = null;
private final static boolean DEFAULT_USE_LAST_EXPLANATION_SERVICE_ = true;
private final static List<String> DEFAULT_EXPLANATION_SERVICES_LIST_ = Collections.emptyList();
private final static List<String> DEFAULT_DISABLED_EXPLANATION_SERVICES_ = Collections.emptyList();

public String defaultExplanationService;
public boolean useLastExplanationService;
public List<String> explanationServicesList;
public List<String> disabledExplanationServices;

private ExplanationPreferences() {
// use create()
}

public static ExplanationPreferences create() {
return new ExplanationPreferences().reset();
}

private static Preferences getPrefs() {
PreferencesManager prefMan = PreferencesManager.getInstance();
return prefMan.getPreferencesForSet(PREFERENCES_SET_KEY_, ExplanationPreferences.class);
}

public ExplanationPreferences load() {
Preferences prefs = getPrefs();
defaultExplanationService = prefs.getString(DEFAULT_EXPLANATION_ID_, DEFAULT_DEFAULT_EXPLANATION_ID_);
useLastExplanationService = prefs.getBoolean(USE_LAST_EXPLANATION_SERVICE_KEY_,
DEFAULT_USE_LAST_EXPLANATION_SERVICE_);
explanationServicesList = prefs.getStringList(EXPLANATION_SERVICES_LIST_KEY_,
DEFAULT_EXPLANATION_SERVICES_LIST_);
disabledExplanationServices = prefs.getStringList(DISABLED_EXPLANATION_SERVICES_KEY_,
DEFAULT_DISABLED_EXPLANATION_SERVICES_);
return this;
}

public ExplanationPreferences save() {
Preferences prefs = getPrefs();
prefs.putString(DEFAULT_EXPLANATION_ID_, defaultExplanationService);
prefs.putBoolean(USE_LAST_EXPLANATION_SERVICE_KEY_, useLastExplanationService);
prefs.putStringList(EXPLANATION_SERVICES_LIST_KEY_, explanationServicesList);
prefs.putStringList(DISABLED_EXPLANATION_SERVICES_KEY_, disabledExplanationServices);
return this;
}

public ExplanationPreferences reset() {
defaultExplanationService = DEFAULT_DEFAULT_EXPLANATION_ID_;
useLastExplanationService = DEFAULT_USE_LAST_EXPLANATION_SERVICE_;
explanationServicesList = DEFAULT_EXPLANATION_SERVICES_LIST_;
disabledExplanationServices = DEFAULT_DISABLED_EXPLANATION_SERVICES_;
return this;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.*;

import org.protege.editor.core.ui.preferences.PreferencesLayoutPanel;
import org.protege.editor.owl.ui.preferences.OWLPreferencesPanel;
Expand All @@ -15,30 +15,110 @@ public class ExplanationPreferencesGeneralPanel extends OWLPreferencesPanel {

private static final long serialVersionUID = -3354987384223578780L;

private JCheckBox checkRecentlyUsed;
private SortedPluginsTableModel tableModel;

@Override
public void initialise() throws Exception {
setLayout(new BorderLayout());
PreferencesLayoutPanel panel = new PreferencesLayoutPanel();
add(panel, BorderLayout.NORTH);
addInstalledExplanationServicesComponent(panel);
addDefaultExplanationServiceComponent(panel);
loadFrom(ExplanationPreferences.create().load());
}

@Override
public void initialise() throws Exception {
setLayout(new BorderLayout());
PreferencesLayoutPanel panel = new PreferencesLayoutPanel();
add(panel, BorderLayout.NORTH);

panel.addGroup("Installed explanation services");
DefaultListModel<String> pluginModel = new DefaultListModel<>();
ExplanationManager manager = new ExplanationManager(getOWLEditorKit());
Collection<ExplanationService> services = manager.getExplainers();
for (ExplanationService service : services)
pluginModel.addElement(service.getName());
JList<String> pluginList = new JList<>(pluginModel);
pluginList.setToolTipText("Plugins that provide explanation facilities");
JScrollPane pluginInfoScrollPane = new JScrollPane(pluginList);
pluginInfoScrollPane.setPreferredSize(new Dimension(300, 100));
panel.addGroupComponent(pluginInfoScrollPane);
}

@Override
public void dispose() throws Exception {
}

@Override
public void applyChanges() {
}
public void dispose() throws Exception {
getOWLEditorKit().getModelManager().getExplanationManager().reload();
}

@Override
public void applyChanges() {
ExplanationPreferences prefs = ExplanationPreferences.create();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create() will erase defaultExplanationService, which is not stored in this preferences. One should probably use preferences that have been loaded during initialize()

saveTo(prefs);
prefs.save();
}

private void loadFrom(ExplanationPreferences prefs) {
checkRecentlyUsed.setSelected(prefs.useLastExplanationService);
tableModel.setPluginIds(prefs.explanationServicesList);
tableModel.setDisabledIds(prefs.disabledExplanationServices);
}

private void saveTo(ExplanationPreferences prefs) {
prefs.useLastExplanationService = checkRecentlyUsed.isSelected();
prefs.explanationServicesList = tableModel.getPluginIds();
prefs.disabledExplanationServices = tableModel.getDisabledIds();
}

private void addDefaultExplanationServiceComponent(PreferencesLayoutPanel panel) {
checkRecentlyUsed = new JCheckBox("Try using the most recently used explanation service first");
checkRecentlyUsed.setToolTipText("Use the most recently used explanation service, if it can provide an explanation for the chosen axiom; otherwise, use the first available service from the list above");
panel.addGroupComponent(checkRecentlyUsed);
}

private void addInstalledExplanationServicesComponent(PreferencesLayoutPanel panel) {
panel.addGroup("Installed explanation services");
Collection<ExplanationService> services = getOWLEditorKit().getOWLModelManager().getExplanationManager()
.getExplainers();
Map<String, String> nameMap = new HashMap<>();
for (ExplanationService service : services) {
nameMap.put(service.getPluginId(), service.getName());
}
tableModel = new SortedPluginsTableModel(nameMap);
JTable pluginTable = new JTable(tableModel);
pluginTable.setToolTipText(
"Plugins that provide explanation facilities. Protégé will use the first enabled service on the list that can provide an explanation for the chosen axiom.");
pluginTable.setRowSelectionAllowed(true);
pluginTable.setColumnSelectionAllowed(false);
pluginTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
pluginTable.getColumnModel().getColumn(0).setMaxWidth(20);
pluginTable.getColumnModel().getColumn(1).setMaxWidth(50);
pluginTable.getColumnModel().getColumn(2).setMinWidth(300);
pluginTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
JScrollPane pluginTableScrollPane = new JScrollPane(pluginTable);
pluginTableScrollPane.setPreferredSize(new Dimension(400, 100));
panel.addGroupComponent(pluginTableScrollPane);
addUpDownButtons(panel, pluginTable);
}

private void addUpDownButtons(PreferencesLayoutPanel panel, JTable pluginTable) {
JButton buttonUp = new JButton("↑ Move up");
buttonUp.setToolTipText("Move the selected explanation service towards the top of the list");
buttonUp.addActionListener(e -> {
int rowIndex = pluginTable.getSelectedRow();
if (rowIndex > 0) {
tableModel.swap(rowIndex - 1, rowIndex);
}
pluginTable.setRowSelectionInterval(rowIndex - 1, rowIndex - 1);
});

JButton buttonDown = new JButton("↓ Move down︎");
buttonDown.setToolTipText("Move the selected explanation service towards the bottom of the list");
buttonDown.addActionListener(e -> {
int rowIndex = pluginTable.getSelectedRow();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the panel is created, no row in the table is selected. So either select, e.g., the first row (if there is) or make the buttons not active.

if (rowIndex < pluginTable.getRowCount() - 1) {
tableModel.swap(rowIndex, rowIndex + 1);
}
pluginTable.setRowSelectionInterval(rowIndex + 1, rowIndex + 1);
});

JPanel buttonsUpDown = new JPanel();
buttonsUpDown.add(buttonUp);
buttonsUpDown.add(buttonDown);
panel.addGroupComponent(buttonsUpDown);

pluginTable.getSelectionModel().addListSelectionListener(e -> {
int rowIndex = pluginTable.getSelectedRow();
if (rowIndex == -1) {
buttonUp.setEnabled(false);
buttonDown.setEnabled(false);
} else {
buttonUp.setEnabled(rowIndex > 0);
buttonDown.setEnabled(rowIndex < pluginTable.getRowCount() - 1);
}
});
}

}
Loading