mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2026-08-22 18:32:31 -04:00
GP-7145 - Added an action to compare two data types
This commit is contained in:
parent
358fcc6f4b
commit
5e9056b387
10 changed files with 320 additions and 52 deletions
|
|
@ -1080,6 +1080,8 @@
|
|||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
|
||||
<H3><A name="ReplaceDataType"></A>Replacing a Data Type</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
|
@ -1092,6 +1094,9 @@
|
|||
</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
|
||||
<H3><A name="MergeDataType"></A>Merging Data Types</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
|
|
|||
|
|
@ -582,6 +582,28 @@
|
|||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
<H3><A name="Compare"></A>Compare...</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The <I><B>Compare...</B></I> action is used to compare the selected data type with
|
||||
another type chosen from
|
||||
<A HREF="help/topics/DataTypeEditors/DataTypeSelectionDialog.htm">dialog</A>.
|
||||
Once a second type is chosen, the Data Type Comparison provider will be shown.
|
||||
</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>
|
||||
<IMG src="help/shared/tip.png" alt="">
|
||||
<A name="Show_Data_Type"></A>You can right-click in either data type
|
||||
preview and choose <B>Show Data Type</B> to have the Data Type Manager tree
|
||||
show and select that type.
|
||||
</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
<H3><A name="Replace"></A>Replace...</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
|
@ -20,6 +20,7 @@ import java.awt.*;
|
|||
import javax.swing.*;
|
||||
|
||||
import docking.widgets.label.GDHtmlLabel;
|
||||
import docking.widgets.textpane.GHtmlTextPane;
|
||||
import generic.theme.GThemeDefaults.Colors;
|
||||
import ghidra.app.util.ToolTipUtils;
|
||||
import ghidra.app.util.html.HTMLDataTypeRepresentation;
|
||||
|
|
@ -31,12 +32,12 @@ import ghidra.util.HTMLUtilities;
|
|||
*/
|
||||
class DataTypeComparePanel extends JPanel {
|
||||
|
||||
private JLabel dtLabel1;
|
||||
private JLabel dtLabel2;
|
||||
private GHtmlTextPane leftDtPane;
|
||||
private GHtmlTextPane rightDtPane;
|
||||
private JPanel leftPanel;
|
||||
private JPanel rightPanel;
|
||||
private JLabel leftPanelLabel;
|
||||
private JLabel rightPanelLabel;
|
||||
private JLabel leftNameLabel;
|
||||
private JLabel rightNameLabel;
|
||||
private String clientName;
|
||||
private String sourceName;
|
||||
|
||||
|
|
@ -48,39 +49,38 @@ class DataTypeComparePanel extends JPanel {
|
|||
}
|
||||
|
||||
private void init() {
|
||||
setPreferredSize(new Dimension(500, 200));
|
||||
setPreferredSize(new Dimension(600, 400));
|
||||
|
||||
leftPanel = new JPanel(new BorderLayout());
|
||||
rightPanel = new JPanel(new BorderLayout());
|
||||
|
||||
leftPanelLabel = new GDHtmlLabel();
|
||||
rightPanelLabel = new GDHtmlLabel();
|
||||
leftPanelLabel.setBorder(BorderFactory.createEmptyBorder(2, 8, 2, 0));
|
||||
rightPanelLabel.setBorder(BorderFactory.createEmptyBorder(2, 8, 2, 0));
|
||||
leftNameLabel = new GDHtmlLabel();
|
||||
rightNameLabel = new GDHtmlLabel();
|
||||
leftNameLabel.setBorder(BorderFactory.createEmptyBorder(2, 8, 2, 0));
|
||||
rightNameLabel.setBorder(BorderFactory.createEmptyBorder(2, 8, 2, 0));
|
||||
|
||||
setLabelText(leftPanelLabel, HTMLUtilities.escapeHTML(clientName) + ":");
|
||||
setLabelText(rightPanelLabel, HTMLUtilities.escapeHTML(sourceName) + ":");
|
||||
setLabelText(leftNameLabel, HTMLUtilities.escapeHTML(clientName) + ":");
|
||||
setLabelText(rightNameLabel, HTMLUtilities.escapeHTML(sourceName) + ":");
|
||||
|
||||
add(leftPanel);
|
||||
add(rightPanel);
|
||||
dtLabel1 = new GDHtmlLabel();
|
||||
dtLabel1.setOpaque(true);
|
||||
dtLabel1.setBackground(Colors.BACKGROUND);
|
||||
dtLabel1.setBorder(BorderFactory.createEmptyBorder(2, 8, 0, 0));
|
||||
dtLabel1.setVerticalAlignment(SwingConstants.TOP);
|
||||
dtLabel2 = new GDHtmlLabel();
|
||||
dtLabel2.setOpaque(true);
|
||||
dtLabel2.setBackground(Colors.BACKGROUND);
|
||||
dtLabel2.setBorder(BorderFactory.createEmptyBorder(2, 8, 0, 0));
|
||||
dtLabel2.setVerticalAlignment(SwingConstants.TOP);
|
||||
leftDtPane = new GHtmlTextPane();
|
||||
leftDtPane.setOpaque(true);
|
||||
leftDtPane.setBackground(Colors.BACKGROUND);
|
||||
leftDtPane.setBorder(BorderFactory.createEmptyBorder(2, 8, 0, 0));
|
||||
rightDtPane = new GHtmlTextPane();
|
||||
rightDtPane.setOpaque(true);
|
||||
rightDtPane.setBackground(Colors.BACKGROUND);
|
||||
rightDtPane.setBorder(BorderFactory.createEmptyBorder(2, 8, 0, 0));
|
||||
|
||||
JScrollPane leftScrollPane = new JScrollPane(dtLabel1);
|
||||
JScrollPane rightScrollPane = new JScrollPane(dtLabel2);
|
||||
JScrollPane leftScrollPane = new JScrollPane(leftDtPane);
|
||||
JScrollPane rightScrollPane = new JScrollPane(rightDtPane);
|
||||
leftScrollPane.getVerticalScrollBar().setUnitIncrement(9);
|
||||
rightScrollPane.getVerticalScrollBar().setUnitIncrement(9);
|
||||
leftPanel.add(leftScrollPane);
|
||||
rightPanel.add(rightScrollPane);
|
||||
leftPanel.add(leftPanelLabel, BorderLayout.NORTH);
|
||||
rightPanel.add(rightPanelLabel, BorderLayout.NORTH);
|
||||
leftPanel.add(leftNameLabel, BorderLayout.NORTH);
|
||||
rightPanel.add(rightNameLabel, BorderLayout.NORTH);
|
||||
syncScrollers(leftScrollPane, rightScrollPane);
|
||||
|
||||
}
|
||||
|
|
@ -107,8 +107,8 @@ class DataTypeComparePanel extends JPanel {
|
|||
String path1 = dataType1 != null ? dataType1.getPathName() : "";
|
||||
String path2 = dataType2 != null ? dataType2.getPathName() : "";
|
||||
|
||||
setLabelText(leftPanelLabel, clientName + ": " + path1);
|
||||
setLabelText(rightPanelLabel, sourceName + ": " + path2);
|
||||
setLabelText(leftNameLabel, clientName + ":<BR>" + path1);
|
||||
setLabelText(rightNameLabel, sourceName + ":<BR>" + path2);
|
||||
|
||||
HTMLDataTypeRepresentation representation1 = ToolTipUtils.getHTMLRepresentation(dataType1);
|
||||
HTMLDataTypeRepresentation representation2 = ToolTipUtils.getHTMLRepresentation(dataType2);
|
||||
|
|
@ -119,12 +119,16 @@ class DataTypeComparePanel extends JPanel {
|
|||
String dt1Text = (dataType1 != null) ? diffs[0].getFullHTMLString() : "";
|
||||
String dt2Text = (dataType2 != null) ? diffs[1].getFullHTMLString()
|
||||
: (dataType1 != null) ? "<Removed>" : "";
|
||||
dtLabel1.setText(dt1Text);
|
||||
dtLabel2.setText(dt2Text);
|
||||
leftDtPane.setText(dt1Text);
|
||||
rightDtPane.setText(dt2Text);
|
||||
}
|
||||
|
||||
private void setLabelText(JLabel label, String text) {
|
||||
label.setText(HTMLUtilities.wrapAsHTML(HTMLUtilities.bold(text)));
|
||||
|
||||
}
|
||||
|
||||
public boolean isLeft(Component component) {
|
||||
return SwingUtilities.isDescendingFrom(component, leftPanel);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
|
||||
import docking.*;
|
||||
import docking.action.builder.ActionBuilder;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
/**
|
||||
* A provider that shows a comparison between two data types.
|
||||
*/
|
||||
public class DataTypeCompareProvider extends ComponentProvider {
|
||||
|
||||
private DataTypeComparePanel compareComponent;
|
||||
private DataType rightDt;
|
||||
private DataType leftDt;
|
||||
|
||||
public DataTypeCompareProvider(Tool tool, String owner, DataType leftDt, DataType rightDt) {
|
||||
super(tool, "Data Type Compare", owner);
|
||||
this.leftDt = leftDt;
|
||||
this.rightDt = rightDt;
|
||||
|
||||
setTransient();
|
||||
setSubTitle(leftDt.getName() + " / " + rightDt.getName());
|
||||
setTabText(leftDt.getName());
|
||||
setWindowMenuGroup(getName());
|
||||
setHelpLocation(new HelpLocation(owner, "Compare"));
|
||||
|
||||
build();
|
||||
|
||||
createActions();
|
||||
|
||||
addToTool();
|
||||
}
|
||||
|
||||
private void createActions() {
|
||||
|
||||
new ActionBuilder("Show Data Type", getOwner())
|
||||
.popupMenuPath("Show Data Type")
|
||||
.onAction(this::showType)
|
||||
.buildAndInstallLocal(this);
|
||||
}
|
||||
|
||||
private void showType(ActionContext context) {
|
||||
|
||||
MouseEvent event = context.getMouseEvent();
|
||||
Component mouseComponent = event.getComponent();
|
||||
boolean isLeft = compareComponent.isLeft(mouseComponent);
|
||||
DataType dt = isLeft ? leftDt : rightDt;
|
||||
|
||||
DataTypeManagerService service =
|
||||
getTool().getService(DataTypeManagerService.class);
|
||||
service.setDataTypeSelected(dt);
|
||||
}
|
||||
|
||||
private void build() {
|
||||
DataTypeManager leftDtm = leftDt.getDataTypeManager();
|
||||
DataTypeManager rightDtm = rightDt.getDataTypeManager();
|
||||
|
||||
String leftName = leftDtm.getName();
|
||||
String rightName = rightDtm.getName();
|
||||
compareComponent = new DataTypeComparePanel(leftName, rightName);
|
||||
compareComponent.setDataTypes(leftDt, rightDt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getComponent() {
|
||||
return compareComponent;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -208,21 +208,6 @@ public class DataTypeSynchronizer {
|
|||
return sourceArchive.getName();
|
||||
}
|
||||
|
||||
// public void openTransactions() {
|
||||
//// if (sourceDTM != null) {
|
||||
//// sourceTransactionID = sourceDTM.startTransaction("Data Type Synchronization");
|
||||
//// }
|
||||
// localTransactionID = dataTypeManager.startTransaction("Data Type Synchronization");
|
||||
// }
|
||||
//
|
||||
// public void closeTransactions() {
|
||||
// dataTypeManager.endTransaction(localTransactionID, true);
|
||||
//// if (sourceDTM != null) {
|
||||
//// sourceDTM.endTransaction(sourceTransactionID, true);
|
||||
//// }
|
||||
//
|
||||
// }
|
||||
|
||||
/**
|
||||
* If the indicated data type is associated with a source archive, this will remove the
|
||||
* association.
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ public class DataTypesProvider extends ComponentProviderAdapter {
|
|||
addLocalAction(new CutAction(plugin));
|
||||
addLocalAction(new CopyAction(plugin));
|
||||
addLocalAction(new PasteAction(plugin));
|
||||
addLocalAction(new CompareDataTypesAction(plugin));
|
||||
addLocalAction(new ReplaceDataTypeAction(plugin));
|
||||
addLocalAction(new MergeDataTypeAction(plugin));
|
||||
addLocalAction(new DeleteAction(plugin));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,130 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr.actions;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.label.GLabel;
|
||||
import docking.widgets.tree.GTree;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeTreeNode;
|
||||
import ghidra.app.util.datatype.DataTypeSelectionDialog;
|
||||
import ghidra.app.util.datatype.DataTypeSelectionEditor;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.data.DataTypeParser.AllowedDataTypes;
|
||||
import ghidra.util.layout.VerticalLayout;
|
||||
|
||||
/**
|
||||
* An action available from a selected data type that allows the user to choose a second type
|
||||
* to be shown in a comparison window.
|
||||
*/
|
||||
public class CompareDataTypesAction extends DockingAction {
|
||||
|
||||
private DataTypeManagerPlugin plugin;
|
||||
|
||||
public CompareDataTypesAction(DataTypeManagerPlugin plugin) {
|
||||
super("Compare", plugin.getName());
|
||||
|
||||
this.plugin = plugin;
|
||||
setPopupMenuData(new MenuData(new String[] { "Compare..." }, "EditAdvanced"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAddToPopup(ActionContext context) {
|
||||
DataTypeTreeNode node = getSelectedDataTypeTreeNode(context);
|
||||
return node instanceof DataTypeNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
DataTypeTreeNode node = getSelectedDataTypeTreeNode(context);
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(node instanceof DataTypeNode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private DataTypeTreeNode getSelectedDataTypeTreeNode(ActionContext context) {
|
||||
if (!(context instanceof DataTypesActionContext)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
GTree gTree = (GTree) context.getContextObject();
|
||||
TreePath[] selectionPaths = gTree.getSelectionPaths();
|
||||
if (selectionPaths == null || selectionPaths.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (selectionPaths.length > 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DataTypeTreeNode node = (DataTypeTreeNode) selectionPaths[0].getLastPathComponent();
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
|
||||
PluginTool tool = plugin.getTool();
|
||||
int noSizeRestriction = -1;
|
||||
DataTypeSelectionDialog selectionDialog = new DataTypeSelectionDialog(tool,
|
||||
plugin.getProgram().getDataTypeManager(), noSizeRestriction, AllowedDataTypes.ALL) {
|
||||
|
||||
@Override
|
||||
protected JComponent createEditorPanel(DataTypeSelectionEditor dtEditor) {
|
||||
|
||||
setTitle("Choose Type to Compare");
|
||||
|
||||
JPanel updatedPanel = new JPanel();
|
||||
updatedPanel.setBorder(BorderFactory.createEmptyBorder(5, 10, 10, 0));
|
||||
updatedPanel.setLayout(new VerticalLayout(5));
|
||||
|
||||
GLabel label = new GLabel("Choose comparison data type: ");
|
||||
label.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
|
||||
updatedPanel.add(label);
|
||||
|
||||
updatedPanel.add(dtEditor.getEditorComponent());
|
||||
|
||||
return updatedPanel;
|
||||
}
|
||||
|
||||
};
|
||||
selectionDialog.setHelpLocation(getHelpLocation());
|
||||
tool.showDialog(selectionDialog);
|
||||
DataType otherDt = selectionDialog.getUserChosenDataType();
|
||||
if (otherDt == null) {
|
||||
return; // cancelled
|
||||
}
|
||||
|
||||
DataTypeTreeNode node = getSelectedDataTypeTreeNode(context);
|
||||
DataType selectedDt = ((DataTypeNode) node).getDataType();
|
||||
DataTypeCompareProvider provider =
|
||||
new DataTypeCompareProvider(tool, plugin.getName(), selectedDt, otherDt);
|
||||
provider.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,8 @@ package docking;
|
|||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.action.*;
|
||||
import docking.actions.AutoGeneratedDockingAction;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
|
@ -64,13 +66,15 @@ class ShowComponentAction extends DockingAction
|
|||
icon = EMPTY_ICON;
|
||||
}
|
||||
|
||||
// Defer setting the menu name until after the constructor so we can specify it using
|
||||
// MenuData.setMenuItemNamePlain(), which won't parse the string for '&'s.
|
||||
String[] menuPath = subMenuName != null
|
||||
? new String[] { MENU_WINDOW, subMenuName, "temporary_placeholder" }
|
||||
: new String[] { MENU_WINDOW, "temporary_placeholder" };
|
||||
MenuData menuData = new MenuData(menuPath, icon, "Permanent");
|
||||
// defer setting the menu name until after the ctor so we can specify it using
|
||||
// MenuData.setMenuItemNamePlain(), which won't parse the string for '&'s.
|
||||
menuData.setMenuItemNamePlain(subMenuName != null ? placeholder.getFullTitle() : title);
|
||||
|
||||
String menuItemName = getMenuItemName(placeholder, subMenuName);
|
||||
menuData.setMenuItemNamePlain(menuItemName);
|
||||
setMenuBarData(menuData);
|
||||
|
||||
// keybinding data used to show the binding in the menu
|
||||
|
|
@ -89,6 +93,26 @@ class ShowComponentAction extends DockingAction
|
|||
}
|
||||
}
|
||||
|
||||
private String getMenuItemName(ComponentPlaceholder placeholder, String subMenuName) {
|
||||
|
||||
if (subMenuName == null) {
|
||||
return title;
|
||||
}
|
||||
|
||||
// We have pull-right menu for all instances of the component provider. Use the full title
|
||||
// unless that title also starts with the submenu name. In that case, we don't want to
|
||||
// repeat the text, as it looks wasteful.
|
||||
String fullTitle = placeholder.getFullTitle();
|
||||
if (fullTitle.startsWith(subMenuName)) {
|
||||
String subTitle = placeholder.getSubTitle();
|
||||
if (!StringUtils.isEmpty(subTitle)) {
|
||||
return subTitle;
|
||||
}
|
||||
}
|
||||
|
||||
return fullTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the given provider's key binding matches this class's key binding
|
||||
* @param provider the provider
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
|
@ -20,6 +20,7 @@ import java.io.StringWriter;
|
|||
|
||||
import javax.swing.JTextPane;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.text.html.HTMLDocument;
|
||||
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import ghidra.util.Msg;
|
||||
|
|
@ -31,6 +32,10 @@ public class GHtmlTextPane extends JTextPane {
|
|||
|
||||
public GHtmlTextPane() {
|
||||
setContentType("text/html");
|
||||
|
||||
// Disabling rendering of tags that the editor kit does not understand, such as comments
|
||||
HTMLDocument doc = (HTMLDocument) getDocument();
|
||||
doc.setPreservesUnknownTags(false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ public class GHelpSet extends HelpSet {
|
|||
try {
|
||||
url = new URI(id).toURL();
|
||||
}
|
||||
catch (MalformedURLException | URISyntaxException e) {
|
||||
catch (IllegalArgumentException | MalformedURLException | URISyntaxException e) {
|
||||
LOG.trace("ID is not a URL; tried to make URL from string: " + id);
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue