| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
| <html xmlns="http://www.w3.org/1999/xhtml"> |
| <head> |
| <meta http-equiv="content-type" content="text/html; charset=UTF-8"> |
| <!-- -*- xhtml -*- --> |
| <title>Руководство по инфраструктуре языка Java для платформы NetBeans 6.0</title> |
| <link rel="stylesheet" type="text/css" href="../../../netbeans.css"> |
| <meta name="AUDIENCE" content="NBUSER"> |
| <meta name="TYPE" content="ARTICLE"> |
| <meta name="EXPIRES" content="N"> |
| <meta name="developer" content="geertjan.wielenga@sun.com"> |
| <meta name="indexed" content="y"> |
| <meta name="description" |
| content="A walk-through of the Retouche approach."> |
| <!-- Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. --> |
| <!-- Use is subject to license terms.--> |
| </head> |
| <body> |
| <h1>Руководство по инфраструктуре языка Java в среде NetBeans</h1> |
| |
| <p>В этом руководстве описываются аспекты новых интерфейсов API инфраструктуры "Retouche" в среде NetBeans 6.0, которые предоставляют доступ к редактору Java, предусмотренному в этой среде. |
| |
| </p><p><b>Содержание</b></p> |
| |
| <img src="../../images/articles/60/netbeans-stamp60-61.gif" class="stamp" width="114" height="114" alt="Содержимое на этой странице относится к среде IDE NetBeans 6.1" title="Содержимое на этой странице относится к среде IDE NetBeans 6.1"> </p> |
| <ul class="toc"> |
| <li><a href="#intro">Введение в инфраструктуру языка Java</a></li> |
| <li><a href="#setting-up-the-module">Настройка модуля</a></li> |
| <li><a href="#creating-a-context-sensitive-toolbar-button">Создание контекстно-зависимой кнопки на панели инструментов</a></li> |
| <li><a href="#identifying-java-source-files">Идентификация исходных файлов Java</a></li> |
| <li><a href="#determining-open-state">Определение состояния открытия</a></li> |
| <li><a href="#detecting-the-element-under-the-caret">Обнаружение элемента под курсором</a></li> |
| <li><a href="#doing-something-useful">Применение на практике</a></li> |
| </ul> |
| |
| <p><b>Для работы с этим руководством требуется программное обеспечение и ресурсы, перечисленные в следующей таблице. </b></p> |
| |
| <table> |
| <tbody> |
| <tr> |
| <th class="tblheader" scope="col">Программное обеспечение или ресурс</th> |
| <th class="tblheader" scope="col">Требуемая версия</th> |
| </tr> |
| <tr> |
| <td class="tbltd1">Среда IDE NetBeans</td> |
| <td class="tbltd1">версия <a href="http://download.netbeans.org/netbeans/6.1/final/">версия 6.1</a> или<br> |
| версия 6.0</td> |
| </tr> |
| <tr> |
| <td class="tbltd1">Комплект для разработчика на языке Java (JDK)</td> |
| <td class="tbltd1"><a href="http://java.sun.com/javase/downloads/index.jsp">версия 6</a> или<br> |
| версия 5</td> |
| </tr> |
| </tbody> |
| </table> |
| |
| <p class="tips">Дополнительно, в целях поиска и устранения ошибок, можно <a href="http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=2753">загрузить готовые примеры</a> и изучить исходный код. |
| |
| </p><p></p><h2><a name="intro"></a>Введение в инфраструктуру языка Java</h2> |
| |
| <p>До появления среды IDE NetBeans 6.0 инфраструктура языка Java, поддерживавшая редактор Java, включая создание и реорганизацию кода Java, была основана на так называемом "JMI для Java" (Java Metadata Interface – интерфейс метаданных Java), также известном как "MDR" (MetaData Repository – хранилище метаданных). В JMI для Java имелся ряд архитектурных проблем, например, блокировка для единственной операции чтения. Другими словами, блокировка применялась просто для чтения информации из модели, в то время как обычно она требуется только для записи. В течение нескольких лет проводилась отладка и улучшение производительности JMI. Еще одна проблема состояла в использовании внутренней копии синтаксического анализатора Java, что предполагало собственный подход к интерпретации исходного кода Java, который отличался от компилятора Java в JDK. После появления общих объектов в JDK 5, в результате чего в языке Java появились намного более сложные и тонкие конструкции, преодолеть это расхождение стало еще труднее. Поэтому из-за проблем с производительностью JMI и из-за того, что благодаря разработке формальной модели языка компилятор Java из JDK стал программно доступным средством, JMI для Java был заменен новым подходом, основанным на компиляторе Java из JDK. |
| |
| </p><p>Именно тогда появилась инфраструктура "Retouche" (французское слово, означающее "мелкий ремонт" или "доработку"). "Retouche" – это новая и быстрая инфраструктура языка Java в среде IDE NetBeans, способная к поддержке всех превосходных компонентов редактора Java, реализованных в среде NetBeans 6.0. Суть состоит в том, что "Retouche" обеспечивает обертку экземпляра компилятора Java в JDK и использует его артефакты, такие как абстрактное синтаксическое дерево (также известное как "AST") и разрешение символических ссылок, производимое на различных этапах процесса синтаксического анализа. При работе с "Retouche" необходимо иметь дело с некоторыми из этих артефактов. Одним из них, например, является <a href="http://java.sun.com/javase/6/docs/jdk/api/javac/tree/index.html">интерфейс API дерева компиляции</a>. Пакеты классов в интерфейсе API дерева компиляции начинаются с <tt>com.sun.*</tt>. Поэтому технически этот интерфейс не является интерфейсом API JDK, но фактически происходит из компилятора Java в JDK. Другим примером артефактов компилятора Java в JDK, используемых при работе с инфраструктурой "Retouche", является формальная модель языка в интерфейсах API в JDK, представленная пакетами <tt>javax.language.model.*</tt>. |
| |
| |
| </p><p></p><h2><a name="setting-up-the-module"></a>Настройка модуля</h2> |
| |
| <p>Этот раздел посвящен созданию проекта модуля и настройке зависимостей от соответствующих модулей NetBeans с помощью программ-мастеров. |
| |
| </p><ol> |
| |
| <li>Выберите "File > New Project". В мастере создания проекта выберите "NetBeans Modules" в области "Categories" и "Module Project" в области "Projects", а затем нажмите кнопку "Next". |
| |
| </li><li>Введите <tt>CopyFQN</tt> в поле "Project Name" и укажите соответствующую папку на диске в поле "Project Location". Выберите "Standalone Module" и "Set as Main Project", если эти параметры не выбраны. Нажмите кнопку "Next". |
| |
| </li><li>Введите <tt>org.netbeans.modules.copyfqn</tt> в поле "Code Name Base" и <tt>CopyFQN</tt> в поле "Module Display Name". Нажмите кнопку "Finish". |
| |
| </li><li>Щелкните проект правой кнопкой мыши, выберите "Properties", щелкните "Libraries" в диалоговом окне "Project Properties" и установите зависимость от следующих интерфейсов API: |
| |
| <p></p><ul> |
| <li>Datasystems API |
| </li><li>Editor Library 2 |
| </li><li>File System API |
| </li><li>Javac API Wrapper |
| </li><li>Java Source |
| </li><li>Nodes API |
| </li><li>Text API |
| </li><li>UI Utilities API |
| </li><li>Utilities API |
| </li><li>Window System API |
| </li></ul> |
| |
| <p>Экран должен выглядеть следующим образом: |
| |
| </p><p align="left"><img border="1" src="../../images/tutorials/copyfqn/proj-props-copyfqn-60.png" alt="CopyFQN"> |
| |
| |
| |
| </p><p>Нажмите кнопку "OK". |
| |
| </p></li> |
| |
| <p></p><h2><a name="creating-a-context-sensitive-toolbar-button"></a>Создание контекстно-зависимой кнопки на панели инструментов</h2> |
| |
| <p>В этом разделе будет рассмотрено создание контекстно-зависимой кнопки на панели инструментов. Это не связано с новыми интерфейсами API инфраструктуры "Retouche", но позволяет создать элемент интерфейса пользователя для взаимодействия с нашей реализацией этих интерфейсов, описанных далее в настоящем руководстве. |
| |
| </p><ol> |
| <li>Щелкните проект модуля правой кнопкой мыши, выберите "New > Other", затем выберите "Action" из категории "Module Development". Нажмите кнопку "Next". |
| |
| </li><li>Выберите "Conditionally Enabled" и сохраните все значения по умолчанию, как показано ниже. Действие должно зависеть от <tt>DataObjects</tt>, и его выполнение должно быть возможно только при выборе какого-либо <tt>DataObject</tt>.</p> |
| |
| |
| <p align="left"><img border="1" src="../../images/tutorials/copyfqn/cookie-action-60.png" alt="CookieAction"> |
| |
| </p><p>Нажмите кнопку "Next". |
| |
| </p></li><li>Выберите "Edit" в поле "Category" и "Edit" в поле "Toolbar". </p> |
| |
| <p>Экран должен выглядеть следующим образом: |
| |
| </p><p align="left"><img border="1" src="../../images/tutorials/copyfqn/gui-registration-60.png" alt="Экран "GUI Registration""> |
| |
| </p><p>Нажмите кнопку "Next".</p> |
| |
| </li><li>Введите <tt>CopyFQNAction</tt> в поле "Class Name" и <tt>CopyFQN</tt> в поле "Display Name". |
| |
| </li><li>Найдите значок, который должен отображаться на кнопке панели инструментов. Например, выберите значок, который используется в этом руководстве:</p> |
| |
| <p align="left"><img border="1" src="../../images/tutorials/copyfqn/icon.png" alt="Значок"> |
| |
| </p><p>Нажмите кнопку "Finish".</p> |
| |
| <p>В новом классе <tt>CopyFQNAction.java</tt> должен быть представлен следующий код: |
| |
| </p><pre class="examplecode">public final class CopyFQNAction extends CookieAction { |
| |
| protected void performAction(Node[] activatedNodes) { |
| DataObject dataObject = activatedNodes[0].getLookup().lookup(org.openide.loaders.DataObject.class); |
| // Добавить: использование dataObject |
| } |
| |
| protected int mode() { |
| return CookieAction.MODE_EXACTLY_ONE; |
| } |
| |
| public String getName() { |
| return NbBundle.getMessage(CopyFQNAction.class, "CTL_CopyFQNAction"); |
| } |
| |
| protected Class[] cookieClasses() { |
| return new Class[] { |
| DataObject.class |
| }; |
| } |
| |
| protected String iconResource() { |
| return "org/netbeans/modules/copyfqn/icon.png"; |
| } |
| |
| public HelpCtx getHelpCtx() { |
| return HelpCtx.DEFAULT_HELP; |
| } |
| |
| protected boolean asynchronous() { |
| return false; |
| } |
| |
| }</pre> |
| |
| <p><b class="notes">Примечание:</b> В оставшейся части этого руководства описывается метод <tt>performAction()</tt>.</p> |
| |
| <p>Было создано действие, зависящее от объектов данных. Теперь выясним, что это означает. |
| |
| </p></li><li>Щелкните модуль правой кнопкой мыши и выберите "Install".</p> |
| |
| <p>После установки модуля на панели инструментов должна появиться новая кнопка. |
| |
| </p></li><li>Выберите узел в окне "Projects" и проверьте кнопку на панели инструментов. При выборе узла, соответствующего файлу или папке (в том числе пакет), кнопка активна, как показано ниже:</p> |
| |
| <p align="left"><img border="1" src="../../images/tutorials/copyfqn/ctx-sensitive-on.png" alt="Значок"> |
| |
| </p><p>Однако при выборе узла, соответствующего проекту, кнопка отключается, как показано ниже:</p> |
| |
| <p align="left"><img border="1" src="../../images/tutorials/copyfqn/ctx-sensitive-off.png" alt="Значок"> |
| |
| </p></li> |
| </ol> |
| <p>В следующем разделе будут рассмотрены не только различия между узлами проекта и узлами файла/папки, но и различия между узлами файлов для классов Java и всеми остальными видами узлов файлов. |
| |
| |
| </p><p></p><h2><a name="identifying-java-source-files"></a>Идентификация исходных файлов Java</h2> |
| |
| <p>В этом разделе рассматривается использование одного из новых интерфейсов API инфраструктуры "Retouche", называемого <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-java-source/overview-summary.html">Java Source</a>. Здесь используется класс <a href="http://www.netbeans.org/download/dev/javadoc/org-netbeans-modules-java-source/org/netbeans/api/java/source/JavaSource.html">JavaSource</a>, представляющий исходный файл Java. Возвращается экземпляр этого класса для объекта файла, связанного с объектом данных. Если возвращается пустое значение, объект файла не является исходным файлом Java. При нажатии кнопки после выбора файла в строке состояния отображается результат. |
| |
| </p><ol> |
| |
| <li>Заполните метод <tt>performAction()</tt> путем добавления строк, выделенных ниже: |
| |
| <pre class="examplecode">protected void performAction(Node[] activatedNodes) { |
| DataObject dataObject = activatedNodes[0].getLookup().lookup(org.openide.loaders.DataObject.class); |
| // Добавить: использование dataObject |
| |
| <b>FileObject fileObject = dataObject.getPrimaryFile(); |
| |
| <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-java-source/org/netbeans/api/java/source/JavaSource.html">JavaSource</a> javaSource = <a href="http://www.netbeans.org/download/dev/javadoc/org-netbeans-modules-java-source/org/netbeans/api/java/source/JavaSource.html#forFileObject(org.openide.filesystems.FileObject)">JavaSource.forFileObject(fileObject)</a>; |
| if (javaSource == null) { |
| StatusDisplayer.getDefault().setStatusText("Not a Java file: " + fileObject.getPath()); |
| } else { |
| StatusDisplayer.getDefault().setStatusText("Hurray! A Java file: " + fileObject.getPath()); |
| }</b> |
| }</pre> |
| |
| </li><li>Проверьте, что используются следующие операторы импорта: |
| |
| <pre class="examplecode">import org.netbeans.api.java.source.JavaSource; |
| import org.openide.awt.StatusDisplayer; |
| import org.openide.filesystems.FileObject; |
| import org.openide.loaders.DataObject; |
| import org.openide.nodes.Node; |
| import org.openide.util.HelpCtx; |
| import org.openide.util.NbBundle; |
| import org.openide.util.actions.CookieAction;</pre> |
| |
| </li><li>Установите модуль еще раз. |
| |
| </li><li>Выберите узел файла и нажмите кнопку.</p> |
| |
| <p> Обратите внимание, что сообщение "Hurray!" появляется только при выборе файла Java, как показано ниже: |
| |
| </p><p align="left"><img border="1" src="../../images/tutorials/copyfqn/message-java-file-60.png" alt="message-java-file-60"> |
| |
| |
| </p><p>Альтернативный подход заключается во <i>включении кнопки только при выборе файла Java</i>. Для этого необходимо переопределить метод <tt>CookieAction.enable()</tt> следующим образом: |
| |
| </p><pre class="examplecode">@Override |
| protected boolean enable(Node[] activatedNodes) { |
| if (super.enable(activatedNodes)) { |
| DataObject dataObject = activatedNodes[0].getLookup().lookup(org.openide.loaders.DataObject.class); |
| FileObject fileObject = dataObject.getPrimaryFile(); |
| JavaSource javaSource = JavaSource.forFileObject(fileObject); |
| if (javaSource == null) { |
| return false; |
| } |
| return true; |
| } |
| return false; |
| }</pre> |
| |
| <p>Показанный выше метод отфильтровывает любой файл, <i>не</i> являющийся файлом Java. В результате кнопка включается только тогда, когда текущий файл является файлом Java. |
| |
| </p></li> |
| |
| |
| <p></p><h2><a name="determining-open-state"></a>Определение состояния открытия</h2> |
| |
| <p>В этом разделе мы обратимся к нашей первой явно вызываемой задаче в инфраструктуре "Retouche". Такая задача представлена методом <tt>runUserActionTask</tt> класса JavaSource. Задача этого вида позволяет управлять этапами процесса синтаксического анализа и применяется при необходимости немедленной реакции на пользовательский ввод. Все действия задачи выполняются единым блоком. В данном случае необходимо, чтобы действие, представленное кнопкой на панели инструментов, немедленно сопровождалось появлением текста в строке состояния. |
| |
| </p><ol> |
| |
| <li> Замените сообщение "Hurray!" в методе <tt>performAction()</tt> следующей строкой: |
| |
| <pre class="examplecode"><a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-java-source/org/netbeans/api/java/source/JavaSource.html#runUserActionTask(org.netbeans.api.java.source.Task,%20boolean)">javaSource.runUserActionTask</a>(new <a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-java-source/org/netbeans/api/java/source/Task.html">Task</a><<a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-java-source/org/netbeans/api/java/source/CompilationController.html">CompilationController</a>>());</pre> |
| |
| <p>Теперь в левом столбце редактора должен появиться значок лампочки, показанный ниже: |
| |
| </p><p align="left"><img border="1" src="../../images/tutorials/copyfqn/runuserasactiontask-60.png" alt="Значок"> |
| |
| </p></li><li>Щелкните значок лампочки. В качестве альтернативы можно установить курсор на строку и нажать Alt-Enter. Теперь позволим среде IDE реализовать метод. |
| |
| </li><li>Незначительно измените метод путем добавления в его конец логической переменной <tt>true</tt>. Среда IDE перенесет фрагмент в блок try/catch. Конечный результат должен выглядеть следующим образом: |
| |
| <pre class="examplecode">protected void performAction(Node[] activatedNodes) { |
| DataObject dataObject = activatedNodes[0].getLookup().lookup(org.openide.loaders.DataObject.class); |
| // Добавить: использование dataObject |
| |
| FileObject fileObject = dataObject.getPrimaryFile(); |
| |
| JavaSource javaSource = JavaSource.forFileObject(fileObject); |
| if (javaSource == null) { |
| StatusDisplayer.getDefault().setStatusText("Not a Java file: " + fileObject.getPath()); |
| } else { |
| |
| <b>try { |
| javaSource.runUserActionTask(new Task<CompilationController>() { |
| |
| public void run(CompilationController arg0) throws Exception { |
| throw new UnsupportedOperationException("Not supported yet."); |
| } |
| }, true); |
| } catch (IOException ex) { |
| Exceptions.printStackTrace(ex); |
| }</b> |
| |
| } |
| |
| }</pre> |
| |
| </li><li>Реализуйте метод <tt>run()</tt> следующим образом: |
| |
| <pre class="examplecode">public void run(CompilationController compilationController) throws Exception { |
| |
| <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-java-source/org/netbeans/api/java/source/CompilationController.html#toPhase(org.netbeans.api.java.source.JavaSource.Phase)">compilationController.toPhase(Phase.ELEMENTS_RESOLVED)</a>; |
| |
| <a href="http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/text/Document.html">Document</a> document = <a href="https://netbeans.org/download/dev/javadoc/org-netbeans-modules-java-source/org/netbeans/api/java/source/CompilationController.html#getDocument()">compilationController.getDocument()</a>; |
| if (document != null) { |
| StatusDisplayer.getDefault().setStatusText("Hurray, the Java file is open!"); |
| } else { |
| StatusDisplayer.getDefault().setStatusText("The Java file is closed!"); |
| } |
| |
| }</pre> |
| |
| </li><li>Проверьте, что используются следующие операторы импорта: |
| |
| <pre class="examplecode">import java.io.IOException; |
| import javax.swing.text.Document; |
| import org.netbeans.api.java.source.CompilationController; |
| import org.netbeans.api.java.source.JavaSource; |
| import org.netbeans.api.java.source.JavaSource.Phase; |
| import org.netbeans.api.java.source.Task; |
| import org.openide.awt.StatusDisplayer; |
| import org.openide.filesystems.FileObject; |
| import org.openide.loaders.DataObject; |
| import org.openide.nodes.Node; |
| import org.openide.util.Exceptions; |
| import org.openide.util.HelpCtx; |
| import org.openide.util.NbBundle; |
| import org.openide.util.actions.CookieAction;</pre> |
| |
| </li><li>Установите модуль еще раз. |
| |
| </li><li>Выберите узел файла и нажмите кнопку.</p> |
| |
| <p> Обратите внимание, что сообщение "Hurray!" появляется только при выборе файла Java, открытого в редакторе Java (см. ниже): |
| |
| </p><p align="left"><img border="1" src="../../images/tutorials/copyfqn/message-java-file-open-60.png" alt="message-java-file-open-60"> |
| |
| </p></li> |
| |
| |
| <p></p><h2><a name="detecting-the-element-under-the-caret"></a>Обнаружение элемента под курсором</h2> |
| |
| <p>В этом разделе, зная, что мы имеем дело с открытым файлом Java, можно приступить к обнаружению типа элемента, находящегося под курсором в любой определенный период времени. |
| |
| </p><ol> |
| |
| <li>Начните с объявления зависимости от интерфейсов API ввода/вывода, чтобы результаты выводились в окне "Output". |
| |
| </li><li> Замените сообщение "Hurray!" в методе <tt>run()</tt> выделенными строками, как показано ниже: |
| |
| <pre class="examplecode">public void run(CompilationController compilationController) throws Exception { |
| |
| compilationController.toPhase(Phase.ELEMENTS_RESOLVED); |
| Document document = compilationController.getDocument(); |
| |
| if (document != null) { |
| <b>new MemberVisitor(compilationController).scan(compilationController.getCompilationUnit(), null);</b> |
| } else { |
| StatusDisplayer.getDefault().setStatusText("The Java file is closed!"); |
| } |
| |
| }</pre> |
| |
| |
| <p></p></li><li>Здесь представлен класс <tt>MemberVisitor</tt>, определенный как внутренний класс класса <tt>CopyFQNAction</tt>: |
| |
| |
| <pre class="examplecode">private static class MemberVisitor extends TreePathScanner<Void, Void> { |
| |
| private CompilationInfo info; |
| |
| public MemberVisitor(CompilationInfo info) { |
| this.info = info; |
| } |
| |
| @Override |
| public Void visitClass(ClassTree t, Void v) { |
| Element el = info.getTrees().getElement(getCurrentPath()); |
| if (el == null) { |
| StatusDisplayer.getDefault().setStatusText("Cannot resolve class!"); |
| } else { |
| TypeElement te = (TypeElement) el; |
| List<? extends Element> enclosedElements = te.getEnclosedElements(); |
| InputOutput io = IOProvider.getDefault().getIO("Analysis of " |
| + info.getFileObject().getName(), true); |
| for (int i = 0; i < enclosedElements.size(); i++) { |
| Element enclosedElement = (Element) enclosedElements.get(i); |
| if (enclosedElement.getKind() == ElementKind.CONSTRUCTOR) { |
| io.getOut().println("Constructor: " |
| + enclosedElement.getSimpleName()); |
| } else if (enclosedElement.getKind() == ElementKind.METHOD) { |
| io.getOut().println("Method: " |
| + enclosedElement.getSimpleName()); |
| } else if (enclosedElement.getKind() == ElementKind.FIELD) { |
| io.getOut().println("Field: " |
| + enclosedElement.getSimpleName()); |
| } else { |
| io.getOut().println("Other: " |
| + enclosedElement.getSimpleName()); |
| } |
| } |
| io.getOut().close(); |
| } |
| return null; |
| } |
| |
| }</pre> |
| |
| </li><li>Установите модуль еще раз и откройте класс Java. Затем нажмите кнопку и обратите внимание на то, что конструкторы, методы и поля отображаются в окне "Output", как показано ниже:</p> |
| |
| |
| <p align="left"><img border="1" src="../../images/tutorials/copyfqn/output-window-60.png" alt="message-constructor-60"> |
| |
| |
| </p></li><li>Затем вместо того, чтобы выводить все элементы в окне "Output", выведем в это окно только тот элемент, на котором установлен курсор. Просто замените метод <tt>visitClass</tt> выделенным кодом, показанным ниже: |
| |
| <pre class="examplecode">private static class MemberVisitor extends TreePathScanner<Void, Void> { |
| |
| private CompilationInfo info; |
| |
| public MemberVisitor(CompilationInfo info) { |
| this.info = info; |
| } |
| |
| <b>@Override |
| public Void visitClass(ClassTree t, Void v) { |
| try { |
| JTextComponent editor = EditorRegistry.lastFocusedComponent(); |
| if (editor.getDocument() == info.getDocument()) { |
| int dot = editor.getCaret().getDot(); |
| TreePath tp = info.getTreeUtilities().pathFor(dot); |
| Element el = info.getTrees().getElement(tp); |
| if (el == null) { |
| StatusDisplayer.getDefault().setStatusText("Cannot resolve class!"); |
| } else { |
| InputOutput io = IOProvider.getDefault().getIO("Analysis of " |
| + info.getFileObject().getName(), true); |
| if (el.getKind() == ElementKind.CONSTRUCTOR) { |
| io.getOut().println("Hurray, this is a constructor: " |
| + el.getSimpleName()); |
| } else if (el.getKind() == ElementKind.METHOD) { |
| io.getOut().println("Hurray, this is a method: " |
| + el.getSimpleName()); |
| } else if (el.getKind() == ElementKind.FIELD) { |
| io.getOut().println("Hurray, this is a field: " |
| + el.getSimpleName()); |
| } else { |
| io.getOut().println("Hurray, this is something else: " |
| + el.getSimpleName()); |
| } |
| io.getOut().close(); |
| } |
| } |
| } catch (IOException ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| return null; |
| }</b> |
| |
| }</pre> |
| |
| </li><li>Установите модуль. |
| |
| </li><li>Установите курсор в любом месте кода Java и нажмите кнопку. В окне "Output" появится информация о коде под курсором (если применимо). Например, при нажатии кнопки после помещения курсора на метод, как показано ниже, в окне "Output" сообщается, что курсор установлен на данном методе:</p> |
| |
| <p align="left"><img border="1" src="../../images/tutorials/copyfqn/message-constructor-60.png" alt="message-constructor-60"> |
| |
| |
| </p></li><li>Однако в это окно можно вывести гораздо больше информации, чем название элемента под курсором. В методе <tt>visitClass</tt> замените выделенные полужирным строки, показанные ниже: |
| |
| |
| <pre class="examplecode">@Override |
| public Void visitClass(ClassTree t, Void v) { |
| try { |
| JTextComponent editor = EditorRegistry.lastFocusedComponent(); |
| if (editor.getDocument() == info.getDocument()) { |
| int dot = editor.getCaret().getDot(); |
| TreePath tp = info.getTreeUtilities().pathFor(dot); |
| Element el = info.getTrees().getElement(tp); |
| if (el == null) { |
| StatusDisplayer.getDefault().setStatusText("Cannot resolve class!"); |
| } else { |
| InputOutput io = IOProvider.getDefault().getIO("Analysis of " |
| + info.getFileObject().getName(), true); |
| <b>String te = null; |
| if (el.getKind() == ElementKind.CONSTRUCTOR) { |
| te = ((TypeElement) ((ExecutableElement) el).getEnclosingElement()).getQualifiedName().toString(); |
| io.getOut().println("Hurray, this is a constructor's qualified name: " + te); |
| } else if (el.getKind() == ElementKind.METHOD) { |
| te = ((ExecutableElement) el).getReturnType().toString(); |
| io.getOut().println("Hurray, this is a method's return type: " + te); |
| } else if (el.getKind() == ElementKind.FIELD) { |
| te = ((VariableElement) el).asType().toString(); |
| io.getOut().println("Hurray, this is a field's type: " + te); |
| }</b> else { |
| io.getOut().println("Hurray, this is something else: " |
| + el.getSimpleName()); |
| } |
| io.getOut().close(); |
| } |
| } |
| } catch (IOException ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| return null; |
| }</pre> |
| |
| </li><li>Установите модуль еще раз. На этот раз после нажатия кнопки при условии, что курсор находится на конструкторе, методе или поле, в окне "Output" отображается более подробная информация об этом элементе. |
| |
| </li></ol> |
| |
| <p>На данном этапе можно определить, является ли текущий файл файлом Java, открыт ли документ и к какому типу относится элемент под курсором. Как можно использовать эту информацию? В следующем разделе представлен простой сценарий, при работе с которым приобретенное знание окажется полезным.</p> |
| |
| |
| <p></p><h2><a name="doing-something-useful"></a>Применение на практике</h2> |
| |
| <p>В этом разделе описано определение содержимого буфера обмена, представленного <tt>java.awt.datatransfer.Clipboard</tt>, в соответствии с элементом под курсором. При нажатии кнопки элемент под курсором помещается в буфер обмена, после чего его можно переместить в другое место кода. |
| |
| </p><ol> |
| |
| <li>Сначала необходимо объявить буфер обмена и определить конструктор: |
| |
| <pre class="examplecode">private Clipboard clipboard; |
| |
| public CopyFQNAction() { |
| clipboard = Lookup.getDefault().lookup(ExClipboard.class); |
| if (clipboard == null) { |
| clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); |
| } |
| }</pre> |
| |
| </li><li> Затем замените каждую строку "Hurray!" в коде строкой, передающей элемент в качестве строки методу, который будет определен на следующем этапе. Дадим методу имя <tt>setClipboardContents</tt>. Затем, например, замените первую строку "Hurray!" на следующую: |
| |
| <pre class="examplecode">setClipboardContents(te);</pre> |
| |
| <p> Выполните аналогичные операции для других строк "Hurray!", убедившись в том, что в метод была передана корректная строка. |
| |
| </p><p><b class="notes">Примечание:</b> Поскольку метод <tt>setClipboardContents</tt> еще не определен, каждая из добавляемых на этом этапе строк подчеркивается красным цветом. На следующем этапе мы добавим новый метод. |
| |
| </p></li><li>Добавьте следующий код (вплоть до конца класса). Этот метод получает строку и помещает ее в буфер обмена: |
| |
| <pre class="examplecode">private void setClipboardContents(String content) { |
| if (clipboard != null) { |
| if (content == null) { |
| StatusDisplayer.getDefault().setStatusText(""); |
| clipboard.setContents(null, null); |
| } else { |
| StatusDisplayer.getDefault().setStatusText("Clipboard: " + content); |
| clipboard.setContents(new StringSelection(content), null); |
| } |
| } |
| }</pre> |
| |
| |
| </li></ol> |
| |
| <br> |
| <div class="feedback-box"><a href="https://netbeans.org/about/contact_form.html?to=3&subject=Feedback:%20Java%20Language%20Infrastructure%20Tutorial%20Part%201">Мы ждем ваших отзывов</a></div> |
| <br style="clear:both;" /> |
| |
| |
| <!-- ======================================================================================== --> |
| |
| <h2><a name="nextsteps"></a>Дополнительная информация</h2> |
| |
| <p>Для получения дополнительной информации о создании и разработке модуля NetBeans см. следующие материалы: |
| </p><ul> |
| <li><a href="http://wiki.netbeans.org/Java_DevelopersGuide">Руководство разработчика Java</a></li> |
| <li><a href="http://wiki.netbeans.org/RetoucheDeveloperFAQ">Часто задаваемые вопросы по разработке в инфраструктуре "Retouche" </a></li> |
| <li><a href="https://netbeans.org/kb/trails/platform.html">Другие связанные руководства</a></li> |
| <li><a href="https://netbeans.org/download/dev/javadoc/">Документация Javadoc по интерфейсам API в среде NetBeans</a></li> |
| </ul> |
| |
| <hr> |
| |
| <!-- ======================================================================================== --> |
| |
| </ol></ol></ol></body> |
| </html> |