Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 qwickie.hyperlink; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.ui.actions.OpenNewClassWizardAction; import org.eclipse.jdt.ui.wizards.NewClassWizardPage; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.FindReplaceDocumentAdapter; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.texteditor.ITextEditor; import qwickie.QWickieActivator; import qwickie.util.DocumentHelper; import qwickie.util.FileSearcher; import qwickie.util.TypeHelper; /** * @author count.negative * */ public class WicketHyperlink implements IHyperlink { public static final String JAVA = "java"; public static final String HTML = "html"; public static final String PROPERTIES = "properties"; public static final String XML = "xml"; public static final String XML_PROPERTIES = "properties.xml"; private String wicketId; private final IRegion region; private final String extension; private boolean found; private boolean openJavaFileOnly; public WicketHyperlink(final IRegion region, final String wicketId, final String extension) { Assert.isNotNull(wicketId); Assert.isNotNull(region); Assert.isNotNull(extension); this.region = region; this.wicketId = wicketId; this.extension = extension; } public IRegion getHyperlinkRegion() { return this.region; } public void open() { if (this.wicketId != null) { final IWorkbench workbench = PlatformUI.getWorkbench(); final IWorkbenchPage activePage = workbench.getActiveWorkbenchWindow().getActivePage(); final IEditorInput editorInput = activePage.getActiveEditor().getEditorInput(); final IResource openedResource = (IResource) editorInput.getAdapter(IResource.class); final List<String> toOpenFilenames = getFilenamesToOpen(openedResource, extension); boolean foundInPropertiesFile = false; for (final String toOpenFilename : toOpenFilenames) { if (!samePackage( FileSearcher.removeSourceFolder(openedResource.getProject(), openedResource.getFullPath().toPortableString()), FileSearcher.removeSourceFolder(openedResource.getProject(), toOpenFilename))) { continue; } try { // try to get the file final IFile file = getFile(toOpenFilename); if (file != null && file.exists()) { // open in editor final IEditorPart editor = IDE.openEditor(activePage, file, false); Assert.isNotNull(editor); final ITextEditor textEditor = (ITextEditor) editor.getAdapter(ITextEditor.class); final IDocument document = ((textEditor).getDocumentProvider()) .getDocument(editor.getEditorInput()); Assert.isNotNull(document); final FindReplaceDocumentAdapter frda = new FindReplaceDocumentAdapter(document); try { if (JAVA.equals(extension)) { IRegion region = frda.find(0, '"' + wicketId + '"', true, true, false, false); if (region != null) { while (region != null) { final IRegion li = document.getLineInformationOfOffset(region.getOffset()); String line = document.get(li.getOffset(), li.getLength()).trim(); if (line.startsWith("*") || line.startsWith("/*") || line.startsWith("//")) { region = frda.find(region.getOffset() + 1, '"' + wicketId + '"', true, true, false, false); } else { DocumentHelper.markOccurrence(textEditor, DocumentHelper.getStringConstantName(line)); textEditor.selectAndReveal(region.getOffset() + 1, wicketId.length()); found = true; break; } } } else { // wicket id not found in file, so search up in tree final List<Object> supertypes = TypeHelper.getSupertypes(file); if (supertypes.size() > 0) { if (supertypes.get(0) instanceof IFile) { final IEditorPart oe = IDE.openEditor(activePage, (IFile) supertypes.get(0), false); open(); if (!found) { activePage.closeEditor(oe, false); } } } } } else if (HTML.equals(extension)) { String wid_const = DocumentHelper.getNamespacePrefix(document); final IRegion region = frda.find(0, wid_const + ":id=\"" + wicketId, true, true, true, false); if (region != null) { textEditor.selectAndReveal(region.getOffset() + wid_const.length() + 5, wicketId.length()); break; } } else if (PROPERTIES.equals(extension)) { // for the wicket tags that use wicket:message if (wicketId.startsWith("value:")) { wicketId = wicketId.substring(6); } final IRegion regionBegin = frda.find(0, wicketId, true, true, false, false); if (regionBegin != null) { IRegion sr = frda.find(regionBegin.getOffset(), "\">", true, true, false, false); if (sr == null) { // properties, select till eol sr = frda.find(regionBegin.getOffset(), "=", true, true, false, false); if (sr == null) { activePage.closeEditor(editor, false); continue; } final IRegion lineRegion = document .getLineInformationOfOffset(sr.getOffset()); final int selectionLength = lineRegion.getOffset() + lineRegion.getLength() - sr.getOffset(); textEditor.selectAndReveal(sr.getOffset() + 1, selectionLength - 1); foundInPropertiesFile = true; break; } else { // xml, select till </ final IRegion selEnd = frda.find(regionBegin.getOffset(), "</", true, true, false, false); textEditor.selectAndReveal(sr.getOffset() + 2, selEnd.getOffset() - sr.getOffset() - 2); foundInPropertiesFile = true; break; } } else { activePage.closeEditor(editor, false); continue; } } } catch (final BadLocationException e) { textEditor.resetHighlightRange(); return; } } else { if (!found) { if (JAVA.equals(extension) && !openedResource.getName().contains("_")) { createJavaFile(openedResource); } else if (HTML.equals(extension)) { createHtmlFile(workbench); } } } } catch (final PartInitException pie) { return; } } if (PROPERTIES.equals(extension) && !foundInPropertiesFile) { if (createPropertiesFile(openedResource.getFullPath().removeFileExtension() .addFileExtension(PROPERTIES).toPortableString(), wicketId + "=") != null) { open(); } } } } private boolean samePackage(final String portableString, final String toOpenFilename) { String[] segmentsA = portableString.split("/"); String[] segmentsB = toOpenFilename.split("/"); if (segmentsA.length != segmentsB.length) { return false; } for (int i = segmentsA.length - 2; i >= 0; i--) { if (segmentsA[i].equals(segmentsB[i])) { continue; } else { return false; } } return true; } public List<String> getFilenamesToOpen(final IResource openedResource, final String extension) { Assert.isNotNull(openedResource); String ressourceExtension = openedResource.getFileExtension(); final Set<String> filenames = new LinkedHashSet<String>(); if (openJavaFileOnly) { filenames.add(getJavaFile(openedResource).getFullPath().toPortableString()); return new ArrayList<String>(filenames); } if (HTML.equals(ressourceExtension)) { filenames.add(getJavaFile(openedResource).getFullPath().toPortableString()); filenames.addAll(getPropertiesFilename(openedResource)); } else if (JAVA.equals(ressourceExtension)) { if (!PROPERTIES.equals(extension)) { filenames.addAll(getHtmlFiles(openedResource)); } filenames.addAll(getPropertiesFilename(openedResource)); } else if (PROPERTIES.equals(ressourceExtension)) { filenames.addAll(getHtmlFiles(openedResource)); filenames.add(getJavaFile(openedResource).getFullPath().toPortableString()); } return new ArrayList<String>(filenames); } public boolean openJavaFile() { return JAVA.equals(extension); } public void openJavaFileOnly(final boolean openJavaFileOnly) { this.openJavaFileOnly = openJavaFileOnly; } public static List<String> getHtmlFiles(final IResource openedResource) { Assert.isNotNull(openedResource); final IProject project = openedResource.getProject(); List<String> htmlFilenames = new ArrayList<String>(); final String filename = openedResource.getFullPath().removeFileExtension().addFileExtension(HTML) .toPortableString(); final IFile file = getFile(filename); // is there a html file in the same folder? if (file != null && file.exists()) { htmlFilenames.add(filename); } else { // if not, search for one with the same name final FileSearcher fs = new FileSearcher(project, new Path(filename).lastSegment()); try { final IJavaProject javaProject = (IJavaProject) project.getNature(JavaCore.NATURE_ID); final IPackageFragmentRoot[] packageFragmentRoots = javaProject.getPackageFragmentRoots(); project.accept(fs); for (final IFile foundFile : fs.getFoundFiles()) { for (final IPackageFragmentRoot packageFragmentRoot : packageFragmentRoots) { if (packageFragmentRoot.getKind() == 1) { // if it's in a source folder if (packageFragmentRoot.getPath().segment(1) .equals(foundFile.getFullPath().segment(1))) { // starting with /src htmlFilenames.add(foundFile.getFullPath().toPortableString()); } } } } } catch (final CoreException e1) { } } FileSearcher fs = new FileSearcher(project, new Path(filename).removeFileExtension().lastSegment() + "$*"); try { project.accept(fs); for (final IFile foundFile : fs.getFoundFiles()) { htmlFilenames.add(foundFile.getFullPath().toPortableString()); } } catch (CoreException e) { } Collections.reverse(htmlFilenames); return htmlFilenames; } public static IFile getJavaFile(final IResource openedResource) { Assert.isNotNull(openedResource); String filePath = openedResource.getFullPath().removeFileExtension().addFileExtension(JAVA) .toPortableString(); String searchName = new Path(filePath).lastSegment(); if (searchName.contains("_")) { searchName = searchName.split("_")[0].concat(".java"); } // it is an inner class if (searchName.contains("$")) { searchName = searchName.split("\\$")[0].concat(".java"); } filePath = openedResource.getFullPath().removeLastSegments(1).append(searchName).toPortableString(); final IFile file = getFile(filePath); // is there a file with the same name in the same folder? if (file != null && file.exists()) { return file; } else { // if not, search for one with the same name, but without variations // String searchName = new Path(filename).lastSegment(); // if (searchName.contains("_")) { // searchName = searchName.split("_")[0].concat(".java"); // } // it is an inner class // if (searchName.contains("$")) { // searchName = searchName.split("\\$")[0].concat(".java"); // } final FileSearcher fs = new FileSearcher(openedResource.getProject(), searchName); try { final IProject project = openedResource.getProject(); project.accept(fs); if (fs.getFoundFiles().size() > 1) { // more then one file found means, there are other packages with the same filenames List<IPath> sourceRoots = FileSearcher.getSourceFolders(project); IPath orp = openedResource.getFullPath().removeLastSegments(1); for (IPath sourceRoot : sourceRoots) { if (sourceRoot.isPrefixOf(orp)) { for (IFile ff : fs.getFoundFiles()) { final IPath ffr = ff.getFullPath().removeFirstSegments(sourceRoot.segmentCount()) .removeLastSegments(1); orp = openedResource.getFullPath().removeFirstSegments(sourceRoot.segmentCount()) .removeLastSegments(1); if (orp.toPortableString().equals(ffr.toPortableString())) { return ff; } } } } } else if (fs.getFoundFile() != null) { return fs.getFoundFile(); } } catch (final CoreException e1) { } } return file; } /** Properties can be properties files but also xml files */ public static List<String> getPropertiesFilename(final IResource openedResource) { Assert.isNotNull(openedResource); final List<String> propertyFiles = getWicketFile(openedResource, PROPERTIES); propertyFiles.add(openedResource.getParent().getFullPath() + "/wicket-package.properties"); final List<String> xmlPropertyFiles = getWicketFile(openedResource, XML_PROPERTIES); propertyFiles.addAll(xmlPropertyFiles); final List<String> xmlFiles = getWicketFile(openedResource, XML); propertyFiles.addAll(xmlFiles); if (xmlFiles.size() == 1 || xmlPropertyFiles.size() == 1) { Collections.reverse(propertyFiles); } return propertyFiles; } private static List<String> getWicketFile(final IResource openedResource, final String ext) { Assert.isNotNull(openedResource); Assert.isNotNull(ext); final String filename = openedResource.getFullPath().removeFileExtension().addFileExtension(ext) .toPortableString(); final List<String> filenames = new ArrayList<String>(); final IFile file = getFile(filename); // is there a file in the same folder, with the same name? then take this one first if (file != null && file.exists()) { filenames.add(filename); } else { // if not, search for one with the same name final FileSearcher fs = new FileSearcher(openedResource.getProject(), openedResource.getFullPath().removeFileExtension().lastSegment() + "*." + ext); try { final IProject project = openedResource.getProject(); project.accept(fs); final List<IFile> ffs = fs.getFoundFiles(); if (ffs != null) { for (final IFile ff : ffs) { filenames.add(ff.getFullPath().toPortableString()); } } } catch (final CoreException e1) { } } return filenames; } private void createHtmlFile(final IWorkbench workbench) { /* * Do nothing, the html creating wizard in eclipse is not very mature final NewHTMLWizard wiz = new NewHTMLWizard(); wiz.init(workbench, new * StructuredSelection()); final WizardDialog dialog = new WizardDialog(workbench.getActiveWorkbenchWindow().getShell(), wiz); dialog.create(); * dialog.open(); */ } private IFile createPropertiesFile(final String toOpenFilename, final String key) { final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(toOpenFilename)); try { if (!file.exists()) { final InputStream ins = new ByteArrayInputStream(key.getBytes()); file.create(ins, true, null); } else { final InputStream ins = new ByteArrayInputStream(("\n" + key).getBytes()); file.appendContents(ins, IFile.FORCE | IFile.KEEP_HISTORY, null); } } catch (final CoreException e) { } return file; } private void createJavaFile(final IResource resource) { Assert.isNotNull(resource); final OpenNewClassWizardAction action = new OpenNewClassWizardAction(); final NewClassWizardPage ncwp = new NewClassWizardPage(); ncwp.setTypeName(resource.getName().replaceAll("\\.html", ""), true); final IJavaProject javaProject = JavaCore.create(resource.getProject()); IPackageFragmentRoot root = null; try { final IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots(); for (int i = 0; i < roots.length; i++) { if (roots[i].getKind() == IPackageFragmentRoot.K_SOURCE) { root = roots[i]; break; } } ncwp.setPackageFragmentRoot(root, true); } catch (final JavaModelException e) { } final String os = root.getParent().getPath().toPortableString(); final String fp = root.getResource().getFullPath().toPortableString().replaceFirst(os, "").substring(1); final String ps = resource.getProjectRelativePath().toPortableString().replaceFirst(fp, ""); String pn = ps.replaceFirst(resource.getName(), "").substring(1).replaceAll("/", "."); pn = pn.substring(0, pn.length() - 1); ncwp.setPackageFragment(root.getPackageFragment(pn), true); ncwp.setSuperClass("org.apache.wicket.markup.html.WebPage", openJavaFile()); action.setConfiguredWizardPage(ncwp); action.setOpenEditorOnFinish(true); action.run(); } /** Helper to get a IFile in this workspace */ public static IFile getFile(final String filename) { IFile file = null; if (filename != null) { final IPath filePath = new Path(filename); if ((filePath.segmentCount() > 1) && (ResourcesPlugin.getWorkspace().getRoot().getFile(filePath).exists())) { return ResourcesPlugin.getWorkspace().getRoot().getFile(filePath); } final IFile[] files = ResourcesPlugin.getWorkspace().getRoot() .findFilesForLocationURI(URIUtil.toURI(filePath.makeAbsolute())); for (int i = 0; (i < files.length) && (file == null); ++i) { if (files[i].exists()) { file = files[i]; break; } } } return file; } public String getTypeLabel() { return null; } public String getHyperlinkText() { return "Open " + extension + " file and jump to " + QWickieActivator.WICKET_ID + " \"" + wicketId + "\""; } public String getURLString() { return this.wicketId; } @Override public String toString() { return getClass().getSimpleName() + " for " + QWickieActivator.WICKET_ID + " \"" + wicketId + "\" to " + extension + " file"; } }