Eclipse Plugin:如何获取当前所选项目的路径

发布于 2024-11-27 17:30:57 字数 1357 浏览 1 评论 0原文

我正在编写一个 Eclipse 插件,它将在 Java 项目的上下文菜单中显示一个菜单项。我已经编写了plugin.xml如下:

<plugin>
   <extension
         point="org.eclipse.ui.menus">
      <menuContribution
            locationURI="popup:org.eclipse.jdt.ui.PackageExplorer">
         <dynamic
               class="uk.co.dajohnston.plugin.classpathswitcher.menu.MenuContribution"
               id="uk.co.dajohnston.plugin.classpathSwitcher.switchMenuContribution">
            <visibleWhen>
               <with
                     variable="activeMenuSelection">
                  <iterate>
                     <adapt
                           type="org.eclipse.jdt.core.IJavaProject">
                     </adapt>
                  </iterate>
                  <count
                        value="1">
                  </count>
               </with>
            </visibleWhen>
         </dynamic>
      </menuContribution>
   </extension>

</plugin>

所以我现在尝试编写扩展CompoundContributionItemMenuContribution类,以便我可以创建一个动态菜单及其内容菜单将基于 Java 项目根目录中存在的一组文件。但我一直试图从 getContributionItems 方法中获取根目录的路径。

根据plugin.xml 文件,我可以保证只有选择单个Java 项目时才会调用该方法,因此我需要做的就是获取当前选择,然后获取其绝对路径。有什么想法吗?或者有更好的方法来做到这一点吗?

I am writing an Eclipse plugin that will display a menu item in the context menu for a Java Project. I have written the plugin.xml as follows:

<plugin>
   <extension
         point="org.eclipse.ui.menus">
      <menuContribution
            locationURI="popup:org.eclipse.jdt.ui.PackageExplorer">
         <dynamic
               class="uk.co.dajohnston.plugin.classpathswitcher.menu.MenuContribution"
               id="uk.co.dajohnston.plugin.classpathSwitcher.switchMenuContribution">
            <visibleWhen>
               <with
                     variable="activeMenuSelection">
                  <iterate>
                     <adapt
                           type="org.eclipse.jdt.core.IJavaProject">
                     </adapt>
                  </iterate>
                  <count
                        value="1">
                  </count>
               </with>
            </visibleWhen>
         </dynamic>
      </menuContribution>
   </extension>

</plugin>

So I am now trying to write the MenuContribution class which extends CompoundContributionItem so that I can create a dynamic menu and the contents of this menu are going to be based on a set of files that exist in the Java Project's root directory. But I am stuck trying to get the path to the root directory from within the getContributionItems method.

Based on the plugin.xml file I can be guarenteed that the method will only be called if a single Java Project is selected, so all I need to do is get the current selection and then get its absolute path. Any ideas? Or is there a better way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

转瞬即逝 2024-12-04 17:30:57

这应该会让你更接近(如果不能为你完全解决它;))

    IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
    if (window != null)
    {
        IStructuredSelection selection = (IStructuredSelection) window.getSelectionService().getSelection();
        Object firstElement = selection.getFirstElement();
        if (firstElement instanceof IAdaptable)
        {
            IProject project = (IProject)((IAdaptable)firstElement).getAdapter(IProject.class);
            IPath path = project.getFullPath();
            System.out.println(path);
        }
    }

This should get you closer (if not solve it completely for you ;))

    IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
    if (window != null)
    {
        IStructuredSelection selection = (IStructuredSelection) window.getSelectionService().getSelection();
        Object firstElement = selection.getFirstElement();
        if (firstElement instanceof IAdaptable)
        {
            IProject project = (IProject)((IAdaptable)firstElement).getAdapter(IProject.class);
            IPath path = project.getFullPath();
            System.out.println(path);
        }
    }
王权女流氓 2024-12-04 17:30:57

自从我写了前面的答案以来,我又编写了几个实用程序插件,现在有了 Eclipse Navigator Popups 的通用启动器。文件如下:

基本清单文件

MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: NavigatorPopup
Bundle-SymbolicName: com.nsd.NavigatorPopup;singleton:=true
Bundle-Version: 1.0.0.1
Bundle-Vendor: NSD
Require-Bundle: org.eclipse.ui,
 org.eclipse.core.resources,
 org.eclipse.core.runtime
Bundle-RequiredExecutionEnvironment: JavaSE-1.6

基本属性文件

build.properties

source.. = src/
output.. = bin/
bin.includes = plugin.xml,\
               META-INF/,\
               .

插件文件

特别注意 ;扩展点中的链接到 扩展点中,这允许我们将多个菜单贡献链接到单个处理程序。

另外值得注意的是,存在多个 locationURI,因为它们可以从一个角度更改为另一个角度。

plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
    <extension point="org.eclipse.ui.commands">
        <category name="NSD Category" id="com.nsd.NavigatorPopup.commands.category"/>
        <command name="Navigator Popup" categoryId="com.nsd.NavigatorPopup.commands.category" id="com.nsd.NavigatorPopup.commands.navigatorPopupCommand"/>
    </extension>
    <extension point="org.eclipse.ui.handlers">
        <handler commandId="com.nsd.NavigatorPopup.commands.navigatorPopupCommand" class="com.nsd.navigatorpopup.NavigatorPopupHandler"/>
    </extension>
    <extension point="org.eclipse.ui.menus">
        <menuContribution locationURI="popup:org.eclipse.jdt.ui.PackageExplorer?after=additions">
            <menu label="Popup Utilities">
                <command commandId="com.nsd.NavigatorPopup.commands.navigatorPopupCommand" id="com.nsd.NavigatorPopup.menus.navigatorPopupCommand"/>
            </menu>
        </menuContribution>
        <menuContribution locationURI="popup:org.eclipse.ui.navigator.ProjectExplorer#PopupMenu?after=additions">
            <menu label="Popup Utilities">
                <command commandId="com.nsd.NavigatorPopup.commands.navigatorPopupCommand" id="com.nsd.NavigatorPopup.menus.navigatorPopupCommand"/>
            </menu>
        </menuContribution>
    </extension>
</plugin>

要了解有关当前选择的插件的更多信息,请单击文件并使用 ALT-SHIFT-F1 进行插件选择间谍

插件选择间谍

使用 ALT-SHIFT-F2 进行插件菜单间谍。 请注意,在右键单击并选择感兴趣的弹出菜单项之前,请按 ALT-SHIFT-F2 组合。
Plug-in Menu Spy

最后是插件的代码。

NavigatorPopupHandler.java

package com.nsd.navigatorpopup;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;

// ====================================================================================================================
// This handler will obtain the core information about a file from a navigator popup menu
// ====================================================================================================================
public class NavigatorPopupHandler extends AbstractHandler {
    private IWorkbenchWindow window;
    private IWorkbenchPage activePage;

    private IProject theProject;
    private IResource theResource;
    private IFile theFile;

    private String workspaceName;
    private String projectName;
    private String fileName;

    public NavigatorPopupHandler() {
        // Empty constructor
    }

    public Object execute(ExecutionEvent event) throws ExecutionException {
        // Get the project and file name from the initiating event if at all possible
        if(!extractProjectAndFileFromInitiatingEvent(event)) {
            return null;
        }

        // CODE THAT USES THE FILE GOES HERE
        MessageDialog.openInformation(this.window.getShell(), "NavigatorPopup", String.format("File Details.\n\nWorkspace=%s\nProject=%s\nFile=%s", workspaceName, projectName, fileName));

        return null;
    }

    private boolean extractProjectAndFileFromInitiatingEvent(ExecutionEvent event) {
        // ============================================================================================================
        // The execute method of the handler is invoked to handle the event. As we only contribute to Explorer
        // Navigator views we expect to get a selection tree event
        // ============================================================================================================
        this.window = HandlerUtil.getActiveWorkbenchWindow(event);
        // Get the active WorkbenchPage
        this.activePage = this.window.getActivePage();

        // Get the Selection from the active WorkbenchPage page
        ISelection selection = this.activePage.getSelection();
        if(selection instanceof ITreeSelection) {
            TreeSelection treeSelection = (TreeSelection) selection;
            TreePath[] treePaths = treeSelection.getPaths();
            TreePath treePath = treePaths[0];

            // The TreePath contains a series of segments in our usage:
            // o The first segment is usually a project
            // o The last segment generally refers to the file

            // The first segment should be a IProject
            Object firstSegmentObj = treePath.getFirstSegment();
            this.theProject = (IProject) ((IAdaptable) firstSegmentObj).getAdapter(IProject.class);
            if(this.theProject == null) {
                MessageDialog.openError(this.window.getShell(), "Navigator Popup", getClassHierarchyAsMsg(
                                "Expected the first segment to be IAdapatable to an IProject.\nBut got the following class hierarchy instead.", "Make sure to directly select a file.",
                                firstSegmentObj));
                return false;
            }

            // The last segment should be an IResource
            Object lastSegmentObj = treePath.getLastSegment();
            this.theResource = (IResource) ((IAdaptable) lastSegmentObj).getAdapter(IResource.class);
            if(this.theResource == null) {
                MessageDialog.openError(this.window.getShell(), "Navigator Popup", getClassHierarchyAsMsg(
                                "Expected the last segment to be IAdapatable to an IResource.\nBut got the following class hierarchy instead.", "Make sure to directly select a file.",
                                firstSegmentObj));
                return false;
            }

            // As the last segment is an IResource we should be able to get an IFile reference from it
            this.theFile = (IFile) ((IAdaptable) lastSegmentObj).getAdapter(IFile.class);

            // Extract additional information from the IResource and IProject
            this.workspaceName = this.theResource.getWorkspace().getRoot().getLocation().toOSString();
            this.projectName = this.theProject.getName();
            this.fileName = this.theResource.getName();

            return true;
        } else {
            String selectionClass = selection.getClass().getSimpleName();
            MessageDialog.openError(this.window.getShell(), "Unexpected Selection Class", String.format("Expected a TreeSelection but got a %s instead.\nProcessing Terminated.", selectionClass));
        }

        return false;
    }

    @SuppressWarnings("rawtypes")
    private static String getClassHierarchyAsMsg(String msgHeader, String msgTrailer, Object theObj) {
        String msg = msgHeader + "\n\n";

        Class theClass = theObj.getClass();
        while(theClass != null) {
            msg = msg + String.format("Class=%s\n", theClass.getName());
            Class[] interfaces = theClass.getInterfaces();
            for(Class theInterface : interfaces) {
                msg = msg + String.format("    Interface=%s\n", theInterface.getName());
            }
            theClass = theClass.getSuperclass();
        }

        msg = msg + "\n" + msgTrailer;

        return msg;
    }
}

以及在其自己的java文件上运行插件的结果。

插件结果

Since I wrote the previous answer I have written another couple of utility plugins and now have a generic starter for Eclipse Navigator Popups. The files are as follows:

Basic manifest file

MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: NavigatorPopup
Bundle-SymbolicName: com.nsd.NavigatorPopup;singleton:=true
Bundle-Version: 1.0.0.1
Bundle-Vendor: NSD
Require-Bundle: org.eclipse.ui,
 org.eclipse.core.resources,
 org.eclipse.core.runtime
Bundle-RequiredExecutionEnvironment: JavaSE-1.6

Basic properties file

build.properties

source.. = src/
output.. = bin/
bin.includes = plugin.xml,\
               META-INF/,\
               .

Plugin file

In particular note how <command commandId=...> of the <menuContribution...> <menu..> in the <extension point="org.eclipse.ui.menus"> extension point links to the <handler commandId=...> in the <extension point="org.eclipse.ui.handlers"> extension point this permits us to link multiple menu contributions to a single handler.

Also of note is the fact that there are multiple locationURI's as these can change from one perspective to another.

plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
    <extension point="org.eclipse.ui.commands">
        <category name="NSD Category" id="com.nsd.NavigatorPopup.commands.category"/>
        <command name="Navigator Popup" categoryId="com.nsd.NavigatorPopup.commands.category" id="com.nsd.NavigatorPopup.commands.navigatorPopupCommand"/>
    </extension>
    <extension point="org.eclipse.ui.handlers">
        <handler commandId="com.nsd.NavigatorPopup.commands.navigatorPopupCommand" class="com.nsd.navigatorpopup.NavigatorPopupHandler"/>
    </extension>
    <extension point="org.eclipse.ui.menus">
        <menuContribution locationURI="popup:org.eclipse.jdt.ui.PackageExplorer?after=additions">
            <menu label="Popup Utilities">
                <command commandId="com.nsd.NavigatorPopup.commands.navigatorPopupCommand" id="com.nsd.NavigatorPopup.menus.navigatorPopupCommand"/>
            </menu>
        </menuContribution>
        <menuContribution locationURI="popup:org.eclipse.ui.navigator.ProjectExplorer#PopupMenu?after=additions">
            <menu label="Popup Utilities">
                <command commandId="com.nsd.NavigatorPopup.commands.navigatorPopupCommand" id="com.nsd.NavigatorPopup.menus.navigatorPopupCommand"/>
            </menu>
        </menuContribution>
    </extension>
</plugin>

To find out more about the plugin for the current selection click on a file and use ALT-SHIFT-F1 for the Plug-in Selection Spy

Plug-in Selection Spy

Use ALT-SHIFT-F2 for the Plug-in Menu Spy. Note press the ALT-SHIFT-F2 combination before right clicking and selecting the popup menu item of interest.
Plug-in Menu Spy

Finally the code for the plug-in.

NavigatorPopupHandler.java

package com.nsd.navigatorpopup;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;

// ====================================================================================================================
// This handler will obtain the core information about a file from a navigator popup menu
// ====================================================================================================================
public class NavigatorPopupHandler extends AbstractHandler {
    private IWorkbenchWindow window;
    private IWorkbenchPage activePage;

    private IProject theProject;
    private IResource theResource;
    private IFile theFile;

    private String workspaceName;
    private String projectName;
    private String fileName;

    public NavigatorPopupHandler() {
        // Empty constructor
    }

    public Object execute(ExecutionEvent event) throws ExecutionException {
        // Get the project and file name from the initiating event if at all possible
        if(!extractProjectAndFileFromInitiatingEvent(event)) {
            return null;
        }

        // CODE THAT USES THE FILE GOES HERE
        MessageDialog.openInformation(this.window.getShell(), "NavigatorPopup", String.format("File Details.\n\nWorkspace=%s\nProject=%s\nFile=%s", workspaceName, projectName, fileName));

        return null;
    }

    private boolean extractProjectAndFileFromInitiatingEvent(ExecutionEvent event) {
        // ============================================================================================================
        // The execute method of the handler is invoked to handle the event. As we only contribute to Explorer
        // Navigator views we expect to get a selection tree event
        // ============================================================================================================
        this.window = HandlerUtil.getActiveWorkbenchWindow(event);
        // Get the active WorkbenchPage
        this.activePage = this.window.getActivePage();

        // Get the Selection from the active WorkbenchPage page
        ISelection selection = this.activePage.getSelection();
        if(selection instanceof ITreeSelection) {
            TreeSelection treeSelection = (TreeSelection) selection;
            TreePath[] treePaths = treeSelection.getPaths();
            TreePath treePath = treePaths[0];

            // The TreePath contains a series of segments in our usage:
            // o The first segment is usually a project
            // o The last segment generally refers to the file

            // The first segment should be a IProject
            Object firstSegmentObj = treePath.getFirstSegment();
            this.theProject = (IProject) ((IAdaptable) firstSegmentObj).getAdapter(IProject.class);
            if(this.theProject == null) {
                MessageDialog.openError(this.window.getShell(), "Navigator Popup", getClassHierarchyAsMsg(
                                "Expected the first segment to be IAdapatable to an IProject.\nBut got the following class hierarchy instead.", "Make sure to directly select a file.",
                                firstSegmentObj));
                return false;
            }

            // The last segment should be an IResource
            Object lastSegmentObj = treePath.getLastSegment();
            this.theResource = (IResource) ((IAdaptable) lastSegmentObj).getAdapter(IResource.class);
            if(this.theResource == null) {
                MessageDialog.openError(this.window.getShell(), "Navigator Popup", getClassHierarchyAsMsg(
                                "Expected the last segment to be IAdapatable to an IResource.\nBut got the following class hierarchy instead.", "Make sure to directly select a file.",
                                firstSegmentObj));
                return false;
            }

            // As the last segment is an IResource we should be able to get an IFile reference from it
            this.theFile = (IFile) ((IAdaptable) lastSegmentObj).getAdapter(IFile.class);

            // Extract additional information from the IResource and IProject
            this.workspaceName = this.theResource.getWorkspace().getRoot().getLocation().toOSString();
            this.projectName = this.theProject.getName();
            this.fileName = this.theResource.getName();

            return true;
        } else {
            String selectionClass = selection.getClass().getSimpleName();
            MessageDialog.openError(this.window.getShell(), "Unexpected Selection Class", String.format("Expected a TreeSelection but got a %s instead.\nProcessing Terminated.", selectionClass));
        }

        return false;
    }

    @SuppressWarnings("rawtypes")
    private static String getClassHierarchyAsMsg(String msgHeader, String msgTrailer, Object theObj) {
        String msg = msgHeader + "\n\n";

        Class theClass = theObj.getClass();
        while(theClass != null) {
            msg = msg + String.format("Class=%s\n", theClass.getName());
            Class[] interfaces = theClass.getInterfaces();
            for(Class theInterface : interfaces) {
                msg = msg + String.format("    Interface=%s\n", theInterface.getName());
            }
            theClass = theClass.getSuperclass();
        }

        msg = msg + "\n" + msgTrailer;

        return msg;
    }
}

And the result of running the plug-in on its own java file.

Plugin Result

離人涙 2024-12-04 17:30:57

我花了很长的一天时间研究这里的答案和很多其他答案,发现最终让我到达那里的是做一个 Java 反射循环来研究从树中选择的类和接口结构航海家。类内省循环处于其最终的休息位置,但最初更接近执行方法的顶部。

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;

public class MyHandler extends AbstractHandler {
/**
 * The constructor.
 */
public MyHandler() {
}

public Object execute(ExecutionEvent event) throws ExecutionException {
    IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
    IWorkbenchPage activePage = window.getActivePage();
    ISelection selection = activePage.getSelection();
    if (selection != null) {
        System.out.println("Got selection");
        if (selection instanceof IStructuredSelection) {
            System.out.println("Got a structured selection");
            if (selection instanceof ITreeSelection) {
                TreeSelection treeSelection = (TreeSelection) selection;
                TreePath[] treePaths = treeSelection.getPaths();
                TreePath treePath = treePaths[0];

                System.out.println("Last");
                Object lastSegmentObj = treePath.getLastSegment();
                Class currClass = lastSegmentObj.getClass();
                while(currClass != null) {
                    System.out.println("  Class=" + currClass.getName());
                    Class[] interfaces = currClass.getInterfaces();
                    for(Class interfacey : interfaces) {
                        System.out.println("   I=" + interfacey.getName());
                    }
                    currClass = currClass.getSuperclass();
                }
                if(lastSegmentObj instanceof IAdaptable) {
                    IFile file = (IFile) ((IAdaptable) lastSegmentObj).getAdapter(IFile.class);
                    if(file != null) {
                        System.out.println("File=" + file.getName());
                        String path = file.getRawLocation().toOSString();
                        System.out.println("path: " + path);
                    }
                }
            }
        }
    }
    return null;
}
}

Had a very long day working my way through the answers here and a whole lot of other answers and found the bit that finally got me there was to do a Java Reflection loop to study the Class and Interface structure of the selection from the Tree in the navigator. The Class introspection loop is in its final resting place but was originally much closer to the top of the execute method.

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;

public class MyHandler extends AbstractHandler {
/**
 * The constructor.
 */
public MyHandler() {
}

public Object execute(ExecutionEvent event) throws ExecutionException {
    IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
    IWorkbenchPage activePage = window.getActivePage();
    ISelection selection = activePage.getSelection();
    if (selection != null) {
        System.out.println("Got selection");
        if (selection instanceof IStructuredSelection) {
            System.out.println("Got a structured selection");
            if (selection instanceof ITreeSelection) {
                TreeSelection treeSelection = (TreeSelection) selection;
                TreePath[] treePaths = treeSelection.getPaths();
                TreePath treePath = treePaths[0];

                System.out.println("Last");
                Object lastSegmentObj = treePath.getLastSegment();
                Class currClass = lastSegmentObj.getClass();
                while(currClass != null) {
                    System.out.println("  Class=" + currClass.getName());
                    Class[] interfaces = currClass.getInterfaces();
                    for(Class interfacey : interfaces) {
                        System.out.println("   I=" + interfacey.getName());
                    }
                    currClass = currClass.getSuperclass();
                }
                if(lastSegmentObj instanceof IAdaptable) {
                    IFile file = (IFile) ((IAdaptable) lastSegmentObj).getAdapter(IFile.class);
                    if(file != null) {
                        System.out.println("File=" + file.getName());
                        String path = file.getRawLocation().toOSString();
                        System.out.println("path: " + path);
                    }
                }
            }
        }
    }
    return null;
}
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文