Add capability to search source code on maven.org

This commit is contained in:
emmanue1 2019-05-18 08:46:40 +02:00
parent 6d3a04a8b5
commit d3d556b39b
14 changed files with 700 additions and 18 deletions

View File

@ -50,4 +50,14 @@ public interface API {
Map<String, String> getPreferences();
Collection<Future<Indexes>> getCollectionOfFutureIndexes();
interface LoadSourceListener {
void sourceLoaded(String source);
}
String getSource(Container.Entry entry);
void loadSource(Container.Entry entry, LoadSourceListener listener);
File loadSourceFile(Container.Entry entry);
}

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) 2008-2019 Emmanuel Dupuy.
* This project is distributed under the GPLv3 license.
* This is a Copyleft license that gives the user the right to use,
* copy and modify the code freely for non-commercial purposes.
*/
package org.jd.gui.spi;
import org.jd.gui.api.API;
import org.jd.gui.api.model.Container;
import java.io.File;
public interface SourceLoader {
String getSource(API api, Container.Entry entry);
String loadSource(API api, Container.Entry entry);
File loadSourceFile(API api, Container.Entry entry);
}

View File

@ -21,6 +21,7 @@ import org.jd.gui.service.mainpanel.PanelFactoryService;
import org.jd.gui.service.pastehandler.PasteHandlerService;
import org.jd.gui.service.platform.PlatformService;
import org.jd.gui.service.preferencespanel.PreferencesPanelService;
import org.jd.gui.service.sourceloader.SourceLoaderService;
import org.jd.gui.service.sourcesaver.SourceSaverService;
import org.jd.gui.service.treenode.TreeNodeFactoryService;
import org.jd.gui.service.type.TypeFactoryService;
@ -64,6 +65,7 @@ public class MainController implements API {
protected SaveAllSourcesController saveAllSourcesController;
protected SelectLocationController selectLocationController;
protected AboutController aboutController;
protected SourceLoaderService sourceLoaderService;
protected History history = new History();
protected JComponent currentPage = null;
@ -147,6 +149,7 @@ public class MainController implements API {
preferencesController = new PreferencesController(configuration, mainFrame, PreferencesPanelService.getInstance().getProviders());
selectLocationController = new SelectLocationController(MainController.this, mainFrame);
aboutController = new AboutController(mainFrame);
sourceLoaderService = new SourceLoaderService();
// Add listeners
mainFrame.addComponentListener(new MainFrameListener(configuration));
// Set drop files transfer handler
@ -677,4 +680,25 @@ public class MainController implements API {
return list;
}
@Override
public String getSource(Container.Entry entry) {
return sourceLoaderService.getSource(this, entry);
}
@Override
public void loadSource(Container.Entry entry, LoadSourceListener listener) {
executor.execute(() -> {
String source = sourceLoaderService.loadSource(this, entry);
if ((source != null) && !source.isEmpty()) {
listener.sourceLoaded(source);
}
});
}
@Override
public File loadSourceFile(Container.Entry entry) {
return sourceLoaderService.getSourceFile(this, entry);
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2008-2019 Emmanuel Dupuy.
* This project is distributed under the GPLv3 license.
* This is a Copyleft license that gives the user the right to use,
* copy and modify the code freely for non-commercial purposes.
*/
package org.jd.gui.service.sourceloader;
import org.jd.gui.api.API;
import org.jd.gui.api.model.Container;
import org.jd.gui.service.extension.ExtensionService;
import org.jd.gui.spi.SourceLoader;
import java.io.File;
import java.util.Collection;
public class SourceLoaderService {
protected static final SourceLoaderService SOURCE_LOADER_SERVICE = new SourceLoaderService();
public static SourceLoaderService getInstance() { return SOURCE_LOADER_SERVICE; }
protected Collection<SourceLoader> providers = ExtensionService.getInstance().load(SourceLoader.class);
public String getSource(API api, Container.Entry entry) {
for (SourceLoader provider : providers) {
String source = provider.getSource(api, entry);
if ((source != null) && !source.isEmpty()) {
return source;
}
}
return null;
}
public String loadSource(API api, Container.Entry entry) {
for (SourceLoader provider : providers) {
String source = provider.loadSource(api, entry);
if ((source != null) && !source.isEmpty()) {
return source;
}
}
return null;
}
public File getSourceFile(API api, Container.Entry entry) {
for (SourceLoader provider : providers) {
File file = provider.loadSourceFile(api, entry);
if (file != null) {
return file;
}
}
return null;
}
}

View File

@ -0,0 +1,147 @@
/*
* Copyright (c) 2008-2019 Emmanuel Dupuy.
* This project is distributed under the GPLv3 license.
* This is a Copyleft license that gives the user the right to use,
* copy and modify the code freely for non-commercial purposes.
*/
package org.jd.gui.service.preferencespanel;
import org.jd.gui.spi.PreferencesPanel;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Map;
import java.util.regex.Pattern;
public class MavenOrgSourceLoaderPreferencesProvider extends JPanel implements PreferencesPanel, DocumentListener, ActionListener {
public static final String ACTIVATED = "MavenOrgSourceLoaderPreferencesProvider.activated";
public static final String FILTERS = "MavenOrgSourceLoaderPreferencesProvider.filters";
public static final String DEFAULT_FILTERS_VALUE =
"+org +com.google +com.ibm +com.jcraft +com.springsource +com.sun -com +java +javax +sun +sunw " +
"+spring +springframework +springmodules +tomcat +maven";
protected static final Pattern CONTROL_PATTERN = Pattern.compile("([+-][a-zA-Z_0-9$_.]+(\\s+[+-][a-zA-Z_0-9$_.]+)*)?\\s*");
protected JCheckBox enableCheckBox;
protected JTextArea filtersTextArea;
protected JButton resetButton;
protected Color errorBackgroundColor = Color.RED;
protected Color defaultBackgroundColor;
protected PreferencesPanel.PreferencesPanelChangeListener listener;
public MavenOrgSourceLoaderPreferencesProvider() {
super(new BorderLayout());
enableCheckBox = new JCheckBox("Search source code on maven.org for:");
enableCheckBox.addActionListener(this);
filtersTextArea = new JTextArea();
filtersTextArea.setFont(getFont());
filtersTextArea.setLineWrap(true);
filtersTextArea.getDocument().addDocumentListener(this);
defaultBackgroundColor = filtersTextArea.getBackground();
JComponent spacer = new JComponent() {};
JScrollPane scrollPane = new JScrollPane(filtersTextArea);
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("windows")) {
spacer.setPreferredSize(new Dimension(22, -1));
scrollPane.setPreferredSize(new Dimension(-1, 50));
} else if (osName.contains("mac os")) {
spacer.setPreferredSize(new Dimension(28, -1));
scrollPane.setPreferredSize(new Dimension(-1, 56));
} else {
spacer.setPreferredSize(new Dimension(22, -1));
scrollPane.setPreferredSize(new Dimension(-1, 56));
}
resetButton = new JButton("Reset");
resetButton.addActionListener(this);
JPanel southPanel = new JPanel(new BorderLayout());
southPanel.add(resetButton, BorderLayout.EAST);
add(enableCheckBox, BorderLayout.NORTH);
add(spacer, BorderLayout.WEST);
add(scrollPane, BorderLayout.CENTER);
add(southPanel, BorderLayout.SOUTH);
}
// --- PreferencesPanel --- //
@Override public String getPreferencesGroupTitle() { return "Source loader"; }
@Override public String getPreferencesPanelTitle() { return "maven.org"; }
@Override public JComponent getPanel() { return this; }
@Override
public void init(Color errorBackgroundColor) {
this.errorBackgroundColor = errorBackgroundColor;
}
@Override public boolean isActivated() { return true; }
@Override
public void loadPreferences(Map<String, String> preferences) {
boolean enabled = !"false".equals(preferences.get(ACTIVATED));
enableCheckBox.setSelected(enabled);
filtersTextArea.setEnabled(enabled);
resetButton.setEnabled(enabled);
String filters = preferences.get(FILTERS);
if ((filters == null) || filters.isEmpty()) {
filtersTextArea.setText(DEFAULT_FILTERS_VALUE);
}
}
@Override
public void savePreferences(Map<String, String> preferences) {
preferences.put(ACTIVATED, Boolean.toString(enableCheckBox.isSelected()));
preferences.put(FILTERS, filtersTextArea.getText().trim());
}
@Override public boolean arePreferencesValid() {
return CONTROL_PATTERN.matcher(filtersTextArea.getText()).matches();
}
@Override public void addPreferencesChangeListener(PreferencesPanelChangeListener listener) {
this.listener = listener;
}
// --- DocumentListener --- //
@Override public void insertUpdate(DocumentEvent e) { onTextChange(); }
@Override public void removeUpdate(DocumentEvent e) { onTextChange(); }
@Override public void changedUpdate(DocumentEvent e) { onTextChange(); }
protected void onTextChange() {
filtersTextArea.setBackground(arePreferencesValid() ? defaultBackgroundColor : errorBackgroundColor);
if (listener != null) {
listener.preferencesPanelChanged(this);
}
}
// --- ActionListener --- //
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == enableCheckBox) {
boolean enabled = enableCheckBox.isSelected();
filtersTextArea.setEnabled(enabled);
resetButton.setEnabled(enabled);
} else {
// Reset button
filtersTextArea.setText(DEFAULT_FILTERS_VALUE);
filtersTextArea.requestFocus();
}
}
}

View File

@ -0,0 +1,255 @@
/*
* Copyright (c) 2008-2019 Emmanuel Dupuy.
* This project is distributed under the GPLv3 license.
* This is a Copyleft license that gives the user the right to use,
* copy and modify the code freely for non-commercial purposes.
*/
package org.jd.gui.service.sourceloader;
import org.jd.gui.api.API;
import org.jd.gui.api.model.Container;
import org.jd.gui.service.preferencespanel.MavenOrgSourceLoaderPreferencesProvider;
import org.jd.gui.spi.PreferencesPanel;
import org.jd.gui.spi.SourceLoader;
import org.jd.gui.util.exception.ExceptionUtil;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.URL;
import java.nio.file.Path;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.util.*;
import java.util.List;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class MavenOrgSourceLoaderProvider implements SourceLoader {
protected static final String MAVENORG_SEARCH_URL_PREFIX = "https://search.maven.org/solrsearch/select?q=1:%22";
protected static final String MAVENORG_SEARCH_URL_SUFFIX = "%22&rows=20&wt=xml";
protected static final String MAVENORG_LOAD_URL_PREFIX = "https://search.maven.org/classic/remotecontent?filepath=";
protected static final String MAVENORG_LOAD_URL_SUFFIX = "-sources.jar";
protected HashSet<Container.Entry> failed = new HashSet<>();
protected HashMap<Container.Entry, File> cache = new HashMap<>();
@Override
public String getSource(API api, Container.Entry entry) {
if (isActivated(api)) {
String filters = api.getPreferences().get(MavenOrgSourceLoaderPreferencesProvider.FILTERS);
if ((filters == null) || filters.isEmpty()) {
filters = MavenOrgSourceLoaderPreferencesProvider.DEFAULT_FILTERS_VALUE;
}
if (accepted(filters, entry.getPath())) {
return search(entry, cache.get(entry.getContainer().getRoot().getParent()));
}
}
return null;
}
@Override
public String loadSource(API api, Container.Entry entry) {
boolean activated = !"false".equals(api.getPreferences().get(MavenOrgSourceLoaderPreferencesProvider.ACTIVATED));
if (isActivated(api)) {
String filters = api.getPreferences().get(MavenOrgSourceLoaderPreferencesProvider.FILTERS);
if ((filters == null) || filters.isEmpty()) {
filters = MavenOrgSourceLoaderPreferencesProvider.DEFAULT_FILTERS_VALUE;
}
if (accepted(filters, entry.getPath())) {
return search(entry, load(entry.getContainer().getRoot().getParent()));
}
}
return null;
}
@Override
public File loadSourceFile(API api, Container.Entry entry) {
return isActivated(api) ? load(entry) : null;
}
private static boolean isActivated(API api) {
return !"false".equals(api.getPreferences().get(MavenOrgSourceLoaderPreferencesProvider.ACTIVATED));
}
protected String search(Container.Entry entry, File file) {
if (file != null) {
String fileName = file.toString().toLowerCase();
if (fileName.endsWith(".zip") || fileName.endsWith(".jar")) {
byte[] buffer = new byte[1024 * 2];
try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(file)))) {
ZipEntry ze = zis.getNextEntry();
String name = entry.getPath();
name = name.substring(0, name.length()-6) + ".java"; // 6 = ".class".length()
while (ze != null) {
if (ze.getName().equals(name)) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int read = zis.read(buffer);
while (read > 0) {
out.write(buffer, 0, read);
read = zis.read(buffer);
}
return new String(out.toByteArray(), "UTF-8");
}
ze = zis.getNextEntry();
}
zis.closeEntry();
} catch (IOException e) {
assert ExceptionUtil.printStackTrace(e);
}
}
}
return null;
}
protected File load(Container.Entry entry) {
if (cache.containsKey(entry)) {
return cache.get(entry);
}
if (!entry.isDirectory() && !failed.contains(entry)) {
try {
// SHA-1
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
byte[] buffer = new byte[1024 * 2];
try (DigestInputStream is = new DigestInputStream(entry.getInputStream(), messageDigest)) {
while (is.read(buffer) > -1);
}
byte[] array = messageDigest.digest();
StringBuilder sb = new StringBuilder();
for (byte b : array) {
sb.append(hexa((b & 255) >> 4));
sb.append(hexa(b & 15));
}
String sha1 = sb.toString();
// Search artifact on maven.org
URL searchUrl = new URL(MAVENORG_SEARCH_URL_PREFIX + sha1 + MAVENORG_SEARCH_URL_SUFFIX);
boolean sourceAvailable = false;
String id = null;
try (InputStream is = searchUrl.openStream()) {
XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(is);
String name = "";
while (reader.hasNext()) {
switch (reader.next()) {
case XMLStreamConstants.START_ELEMENT:
if ("str".equals(reader.getLocalName())) {
if ("id".equals(reader.getAttributeValue(null, "name"))) {
name = "id";
} else {
name = "str";
}
} else {
name = "";
}
break;
case XMLStreamConstants.CHARACTERS:
switch (name) {
case "id":
id = reader.getText().trim();
break;
case "str":
sourceAvailable |= "-sources.jar".equals(reader.getText().trim());
break;
}
break;
}
}
reader.close();
}
if (sourceAvailable == false) {
failed.add(entry);
} else {
// Load source
int index1 = id.indexOf(':');
int index2 = id.lastIndexOf(':');
String groupId = id.substring(0, index1);
String artifactId = id.substring(index1+1, index2);
String version = id.substring(index2+1);
String filePath = groupId.replace('.', '/') + '/' + artifactId + '/' + version + '/' + artifactId + '-' + version;
URL loadUrl = new URL(MAVENORG_LOAD_URL_PREFIX + filePath + MAVENORG_LOAD_URL_SUFFIX);
File tmpFile = File.createTempFile("jd-gui.tmp.", '.' + artifactId + '-' + version + "-sources.jar");
tmpFile.delete();
tmpFile.deleteOnExit();
try (InputStream is = new BufferedInputStream(loadUrl.openStream()); OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile))) {
int readed = is.read(buffer);
while (readed > 0) {
os.write(buffer, 0, readed);
readed = is.read(buffer);
}
}
cache.put(entry, tmpFile);
return tmpFile;
}
} catch (Exception e) {
assert ExceptionUtil.printStackTrace(e);
failed.add(entry);
}
}
return null;
}
private static char hexa(int i) { return (char)( (i <= 9) ? ('0' + i) : (('a' - 10) + i) ); }
protected boolean accepted(String filters, String path) {
// 'filters' example : '+org +com.google +com.ibm +com.jcraft +com.springsource +com.sun -com +java +javax +sun +sunw'
StringTokenizer tokenizer = new StringTokenizer(filters);
while (tokenizer.hasMoreTokens()) {
String filter = tokenizer.nextToken();
if (filter.length() > 1) {
String prefix = filter.substring(1).replace('.', '/');
if (prefix.charAt(prefix.length() - 1) != '/') {
prefix += '/';
}
if (path.startsWith(prefix)) {
return (filter.charAt(0) == '+');
}
}
}
return false;
}
}

View File

@ -14,7 +14,10 @@ import org.jd.gui.util.exception.ExceptionUtil;
import java.io.File;
import java.net.URI;
import java.nio.file.*;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
public class ZipFileSourceSaverProvider extends DirectorySourceSaverProvider {
@ -32,25 +35,31 @@ public class ZipFileSourceSaverProvider extends DirectorySourceSaverProvider {
Files.createDirectories(parentPath);
}
File tmpFile = File.createTempFile("jd-gui.", ".tmp.zip");
tmpFile.delete();
File tmpSourceFile = api.loadSourceFile(entry);
URI tmpFileUri = tmpFile.toURI();
URI tmpArchiveUri = new URI("jar:" + tmpFileUri.getScheme(), tmpFileUri.getHost(), tmpFileUri.getPath() + "!/", null);
if (tmpSourceFile != null) {
Files.copy(tmpSourceFile.toPath(), path);
} else {
File tmpFile = File.createTempFile("jd-gui.", ".tmp.zip");
HashMap<String,String> env = new HashMap<>();
env.put("create", "true");
tmpFile.delete();
tmpFile.deleteOnExit();
FileSystem tmpArchiveFs = FileSystems.newFileSystem(tmpArchiveUri, env);
Path tmpArchiveRootPath = tmpArchiveFs.getPath("/");
URI tmpFileUri = tmpFile.toURI();
URI tmpArchiveUri = new URI("jar:" + tmpFileUri.getScheme(), tmpFileUri.getHost(), tmpFileUri.getPath() + "!/", null);
saveContent(api, controller, listener, tmpArchiveRootPath, tmpArchiveRootPath, entry);
HashMap<String, String> env = new HashMap<>();
env.put("create", "true");
tmpArchiveFs.close();
FileSystem tmpArchiveFs = FileSystems.newFileSystem(tmpArchiveUri, env);
Path tmpArchiveRootPath = tmpArchiveFs.getPath("/");
Path tmpPath = Paths.get(tmpFile.getAbsolutePath());
saveContent(api, controller, listener, tmpArchiveRootPath, tmpArchiveRootPath, entry);
Files.move(tmpPath, path);
tmpArchiveFs.close();
Files.move(tmpFile.toPath(), path);
}
} catch (Exception e) {
assert ExceptionUtil.printStackTrace(e);
}

View File

@ -12,7 +12,7 @@ import org.jd.gui.api.feature.ContainerEntryGettable;
import org.jd.gui.api.feature.UriGettable;
import org.jd.gui.api.model.Container;
import org.jd.gui.util.exception.ExceptionUtil;
import org.jd.gui.view.component.ClassFilePage;
import org.jd.gui.view.component.DynamicPage;
import org.jd.gui.view.data.TreeNodeBean;
import javax.swing.*;
@ -29,7 +29,7 @@ public class ClassFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFa
static {
// Early class loading
try {
Class.forName(ClassFilePage.class.getName());
Class.forName(DynamicPage.class.getName());
} catch (Exception e) {
assert ExceptionUtil.printStackTrace(e);
}
@ -49,7 +49,7 @@ public class ClassFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFa
@Override
@SuppressWarnings("unchecked")
public <T extends JComponent & UriGettable> T makePage(API a, Container.Entry e) {
return (T)new ClassFilePage(a, e);
return (T)new DynamicPage(a, e);
}
@Override

View File

@ -143,6 +143,10 @@ public class AbstractTextPage extends JPanel implements LineNumberNavigable, Con
public String getText() { return textArea.getText(); }
public JScrollPane getScrollPane() {
return scrollPane;
}
public void setText(String text) {
textArea.setText(text);
textArea.setCaretPosition(0);

View File

@ -7,7 +7,10 @@
package org.jd.gui.view.component;
import org.fife.ui.rsyntaxtextarea.*;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaEditorKit;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaUI;
import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
import org.fife.ui.rsyntaxtextarea.folding.Fold;
import org.fife.ui.rsyntaxtextarea.folding.FoldManager;
import org.fife.ui.rtextarea.Gutter;
@ -58,6 +61,14 @@ public abstract class CustomLineNumbersPage extends HyperlinkPage {
}
}
public void initLineNumbers(int maxLineNumber) {
setMaxLineNumber(maxLineNumber);
for (int i=1; i<=maxLineNumber; i++) {
lineNumberMap[i] = i;
}
}
public void setLineNumber(int textAreaLineNumber, int originalLineNumber) {
if (originalLineNumber > 0) {
setMaxLineNumber(textAreaLineNumber);

View File

@ -0,0 +1,134 @@
/*
* Copyright (c) 2008-2019 Emmanuel Dupuy.
* This project is distributed under the GPLv3 license.
* This is a Copyleft license that gives the user the right to use,
* copy and modify the code freely for non-commercial purposes.
*/
package org.jd.gui.view.component;
import org.jd.gui.api.API;
import org.jd.gui.api.feature.*;
import org.jd.gui.api.model.Container;
import org.jd.gui.api.model.Indexes;
import javax.swing.*;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.Future;
public class DynamicPage
extends JPanel
implements ContentCopyable, ContentSavable, ContentSearchable, ContentSelectable, FocusedTypeGettable,
IndexesChangeListener, LineNumberNavigable, PreferencesChangeListener, UriGettable, UriOpenable,
API.LoadSourceListener
{
protected API api;
protected Container.Entry entry;
protected TypePage page;
protected URI lastOpenedUri;
protected Collection<Future<Indexes>> collectionOfFutureIndexes;
public DynamicPage(API api, Container.Entry entry) {
super(new BorderLayout());
this.api = api;
this.entry = entry;
String source = api.getSource(entry);
if (source == null) {
// Display the decompiled source code
add(page = new ClassFilePage(api, entry));
// Try to load source in background
api.loadSource(entry, this);
} else {
// Display original source code
add(page = new JavaFilePage(api, new DelegatedEntry(entry, source)));
}
}
// --- ContentCopyable --- //
@Override public void copy() { page.copy(); }
// --- ContentSavable --- //
@Override public String getFileName() { return page.getFileName(); }
@Override public void save(API api, OutputStream outputStream) { page.save(api, outputStream); }
// --- ContentSearchable --- //
@Override public boolean highlightText(String text, boolean caseSensitive) { return page.highlightText(text, caseSensitive); }
@Override public void findNext(String text, boolean caseSensitive) { page.findNext(text, caseSensitive); }
@Override public void findPrevious(String text, boolean caseSensitive) { page.findPrevious(text, caseSensitive); }
// --- ContentSelectable --- //
@Override public void selectAll() { page.selectAll(); }
// --- FocusedTypeGettable --- //
@Override public String getFocusedTypeName() { return page.getFocusedTypeName(); }
// --- ContainerEntryGettable --- //
@Override public Container.Entry getEntry() { return entry; }
// --- IndexesChangeListener --- //
@Override public void indexesChanged(Collection<Future<Indexes>> collectionOfFutureIndexes) {
this.collectionOfFutureIndexes = collectionOfFutureIndexes;
page.indexesChanged(collectionOfFutureIndexes);
}
// --- LineNumberNavigable --- //
@Override public int getMaximumLineNumber() { return page.getMaximumLineNumber(); }
@Override public void goToLineNumber(int lineNumber) { page.goToLineNumber(lineNumber); }
@Override public boolean checkLineNumber(int lineNumber) { return page.checkLineNumber(lineNumber); }
// --- PreferencesChangeListener --- //
@Override public void preferencesChanged(Map<String, String> preferences) { page.preferencesChanged(preferences); }
// --- UriGettable --- //
@Override public URI getUri() { return entry.getUri(); }
// --- UriOpenable --- //
@Override public boolean openUri(URI uri) { return page.openUri(lastOpenedUri = uri); }
// --- LoadSourceListener --- //
@Override public void sourceLoaded(String source) {
SwingUtilities.invokeLater(() -> {
// Replace the decompiled source code by the original
Point viewPosition = page.getScrollPane().getViewport().getViewPosition();
removeAll();
add(page = new JavaFilePage(api, new DelegatedEntry(entry, source)));
page.getScrollPane().getViewport().setViewPosition(viewPosition);
if (lastOpenedUri != null) {
page.openUri(lastOpenedUri);
}
if (collectionOfFutureIndexes != null) {
page.indexesChanged(collectionOfFutureIndexes);
}
});
}
protected static class DelegatedEntry implements Container.Entry {
protected Container.Entry entry;
protected String source;
DelegatedEntry(Container.Entry entry, String source) {
this.entry = entry;
this.source = source;
}
@Override public Container getContainer() { return entry.getContainer(); }
@Override public Container.Entry getParent() { return entry.getParent(); }
@Override public URI getUri() { return entry.getUri(); }
@Override public String getPath() { return entry.getPath(); }
@Override public boolean isDirectory() { return entry.isDirectory(); }
@Override public long length() { return entry.length(); }
@Override public InputStream getInputStream() { return new ByteArrayInputStream(source.getBytes()); }
@Override public Collection<Container.Entry> getChildren() { return entry.getChildren(); }
}
}

View File

@ -31,7 +31,7 @@ public class JavaFilePage extends TypePage {
public JavaFilePage(API api, Container.Entry entry) {
super(api, entry);
// Load content file
String text = TextReader.getText(entry.getInputStream()).replace("\r\n", "\n").replace("\r", "\n");
String text = TextReader.getText(entry.getInputStream()).replace("\r\n", "\n").replace('\r', '\n');
// Parse
DeclarationListener declarationListener = new DeclarationListener(entry);
ReferenceListener referenceListener = new ReferenceListener(entry);
@ -40,9 +40,14 @@ public class JavaFilePage extends TypePage {
referenceListener.init(declarationListener);
ANTLRJavaParser.parse(new ANTLRInputStream(text), referenceListener);
// Display
initLineNumbers(getMaxLineNumber(text));
setText(text);
}
private static int getMaxLineNumber(String text) {
return text.length() - text.replace("\n", "").length();
}
public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_JAVA; }
// --- ContentSavable --- //

View File

@ -2,3 +2,4 @@ org.jd.gui.service.preferencespanel.DirectoryIndexerPreferencesProvider
org.jd.gui.service.preferencespanel.ClassFileSaverPreferencesProvider
org.jd.gui.service.preferencespanel.ClassFileDecompilerPreferencesProvider
org.jd.gui.service.preferencespanel.ViewerPreferencesProvider
org.jd.gui.service.preferencespanel.MavenOrgSourceLoaderPreferencesProvider

View File

@ -0,0 +1 @@
org.jd.gui.service.sourceloader.MavenOrgSourceLoaderProvider