qwickie.hyperlink.WicketHyperlink.java Source code

Java tutorial

Introduction

Here is the source code for qwickie.hyperlink.WicketHyperlink.java

Source

/*
 * 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";
    }

}