К сожалению, выполнение чего-либо в Eclipse в первый раз может быть очень трудоемким и разочаровывающим. Платформа Eclipse огромна, мощна и иногда сложна. Может быть трудно определить, какие функции доступны и как их использовать.
В этом руководстве объясняются основы всех функций Eclipse, необходимых для автоматизации простой задачи рефакторинга Java. Он показывает, как добавлять новые элементы в меню и как анализировать, изменять и форматировать исходный код Java. Также показано, как использовать диалоги для общения с пользователями.
Он разделен на две части. Этот пост объясняет всю необходимую теорию. К концу этой части вы уже будете знать достаточно об Eclipse framework, чтобы иметь возможность закончить плагин с небольшим поиском. Практически, мы создадим плагин, который добавляет новые пункты в меню и собирает всю информацию, необходимую для выполнения рефакторинга.
Следующая часть этого урока покажет, как создавать диалоги и как изменять исходные коды Java из плагина. Это еще не было выпущено.
Пример плагина
Мы создаем пример плагина с двумя функциями:
- проверить ненулевые параметры — изменяет выбранный метод, чтобы проверить, не являются ли его параметры
null
, - пользовательская генерация toString — добавляет метод
toString
к выбранному классу.
Обе функции добавят новый пункт в исходное меню. Элемент проверки ненулевых параметров будет включен, только если пользователь выберет метод Java. Функция показывает диалог, который позволяет пользователю выбрать подмножество аргументов метода. Выбранный метод затем изменяется, чтобы проверить, являются ли выбранные аргументы нулевыми:
1
2
|
if (arg1== null || arg2== null || ... || argn== null ) throw new IllegalStateException( "The parameter may not be null." ); |
Пользовательский элемент toString будет генерироваться, только если пользователь выберет класс Java. Появится диалог со списком всех его свойств. Пользователь выбирает, какие свойства принадлежат методу toString. Если пользователь выбрал менее четырех свойств, функция добавляет следующий код в класс:
1
2
3
4
5
6
7
8
|
@Override public String toString() { StringBuilder builder = new StringBuilder( this .getClass() .getSimpleName()); builder.append( " [ " ); builder.append(b).append( ", " ).append(c).append( " ]" ); return builder.toString(); } |
Если пользователь выбрал менее четырех или более свойств, функция добавляет следующий код в класс:
01
02
03
04
05
06
07
08
09
10
11
|
public String toString() { StringBuilder builder = new StringBuilder( this .getClass() .getSimpleName()); builder.append( " [ \n" ); builder.append( " a" + ": " ).append(a).append( "\n" ); builder.append( " b" + ": " ).append(b).append( "\n" ); builder.append( " c" + ": " ).append(c).append( "\n" ); builder.append( " d" + ": " ).append(d).append( "\n" ); builder.append( " ]" ); return builder.toString(); } |
Вот и все. Плагин доступен на Github .
Каждый выпуск Eclipse выпускается в нескольких вариантах. Версия, наиболее подходящая для авторов плагинов, называется «Eclipse для разработчиков RCP и RAP». RCP расшифровывается как «платформа для богатых клиентов», что является еще одним названием платформы Eclipse.
Загрузите и установите Eclipse для разработчиков RCP и RAP со страницы загрузки .
Первое, что нужно сделать, это настроить целевую платформу. Целевая платформа — еще один пример затмения. Он представляет минимальную конфигурацию, с которой будет работать ваш плагин. Ваш плагин будет скомпилирован на целевой платформе. Он также будет установлен в него и будет запускаться внутри него всякий раз, когда вы захотите его протестировать.
Все рабочее пространство может иметь только одну активную целевую платформу. Это не конкретный проект, хотя это будет иметь больше смысла.
Самая простая целевая платформа
Самым простым является разработка для той же версии Eclipse, на которой вы работаете. Это опция по умолчанию. Если это так, все, что вам нужно сделать, это добавить в него eclipse SDK.
Установите Eclipse SDK:
- Перейдите в «Справка» -> «Установить новое программное обеспечение…».
- Выберите свой сайт обновлений eclipse, в нашем случае «Обновления проекта Eclipse»
http://download.eclipse.org/eclipse/updates/3.
обновить сайт. - Проверьте Eclipse SDK и Eclipse Platform SDK.
- Нажмите Далее, примите лицензию и завершите установку.
Вот и все. Больше ничего не нужно, вы готовы создать первый проект плагина .
Усовершенствованная целевая платформа
Можно загрузить и поддерживать целевую платформу отдельно. Используйте эту опцию, если вы хотите быть совместимыми со старым выпуском или если вы хотите иметь больший контроль над конфигурацией целевой платформы.
Если вам это не интересно, перейдите к следующей главе.
Найдите и загрузите SDK того, что, по вашему мнению, будет у ваших пользователей. Вы также можете использовать «обычную» версию, если не можете найти SDK. Однако, если вы загрузите SDK, у вас будет доступный исходный код и javadocs.
Например, наш плагин требует выпуска Eclipse Indigo. Номер версии Eclipse Indigo — 3.7, поэтому мы должны загрузить Eclipse 3.7 SDK . Полный список даже более старых версий Eclipse SDK доступен на странице архивных выпусков .
Наш плагин будет зависеть только от самого затмения, поэтому все, что нам нужно сделать, это распаковать куда-нибудь загруженный SDK. Если для этого потребуются дополнительные плагины, нам придется искать и загружать их SDK. Мы также распаковываем их и копируем в ту же директорию, что и eclipse SDK.
Теперь нам нужно настроить затмение RCP для использования подготовленной целевой платформы.
Определите и активируйте целевую платформу:
- Перейдите в «Окно» -> «Настройки» -> «Разработка плагинов» -> «Целевая платформа».
- Нажмите Добавить.
- Выберите «Ничего: начать с пустого определения цели» и нажмите «Далее».
- Введите имя цели.
- Нажмите «Добавить», выберите каталог, перейдите к распакованному пакету eclipse SDK и завершите.
- Проверьте новую целевую платформу как «Активную».
Наконец, перейдите на страницу настроек «Разработка плагинов» и отметьте «Включить все плагины из цели в поиск Java».
В этой главе показано, как создать простой проект плагина и как его отладить. Простой плагин не делает ничего полезного. Он может только показать сообщение, чтобы доказать, что оно существует.
В конце этой главы мы удалим образец сообщения и в итоге получим пустой скелет плагина.
Мы будем использовать мастер Eclipse для создания плагина. Вызовите мастера из проводника пакетов:
- щелкните правой кнопкой мыши в проводнике пакетов,
- выберите «New» -> «Other ..».,
- выберите «Plug-in Project» и нажмите «Далее».
Мастер имеет несколько страниц. Настройте имя проекта и целевую платформу на первом. Вы можете использовать любое имя проекта по своему усмотрению, но соглашение заключается в том, чтобы называть проект в честь корневого пакета Java. Например, поскольку мы хотим поместить все классы в пакет org.meri.eclipse.defensiveapitools
, наше имя проекта будет org.meri.eclipse.defensiveapitools
Поле целевой платформы содержит версию Eclipse, для которой вы разрабатываете. Если кто-то хочет использовать ваш плагин, он должен будет загрузить Eclipse с тем же или большим номером. Старый несовместимый Eclipse откажется загружать его. Мы в порядке с разработкой для текущего Eclipse, поэтому мы выберем 3.7.
Нажмите «Далее’.
Вторая страница содержит основную информацию о проекте. Введите идентификатор, версию плагина, имя и провайдера, как вам нравится. Первым важным параметром является среда исполнения. Плагин будет работать только на указанной или никогда Java. Затмение, работающее на более старой JVM, просто проигнорирует его. Мы выбрали J2SE-1.6.
Подтвердите это:
- установлен флажок «Сгенерировать активатор, Java…»,
- установлен флажок «Этот плагин будет вносить вклад в пользовательский интерфейс»,
- ответ на «Хотите создать приложение с расширенной клиентской платформой» — нет.
Нажмите «Далее’.
Выберите шаблон «Hello, World Command» и нажмите «Готово». Это создаст новый плагин с примером пункта меню.
Плагин работает только внутри запущенного Eclipse. Eclipse поддерживает как ручное, так и автоматическое тестирование JUnit. В обоих случаях плагин устанавливается и запускается на целевой платформе, настроенной в первой главе .
В этой главе показано только, как выполнить ручное тестирование. Обратитесь к другим ресурсам, чтобы узнать, как писать тесты junit для плагинов Eclipse.
Установите и запустите плагин:
- щелкните правой кнопкой мыши на проекте плагина,
- нажмите «Отладка как» -> «Приложение Eclipse».
Система запустит новый экземпляр затмения. В его главном меню появилась новая запись, которая называется «Пример меню».
Теперь у вас есть два запущенных экземпляра затмения. Один для разработки, а другой для тестирования. Тестовое затмение проходит внутри разработки. Все инструменты отладки доступны. Вы можете устанавливать точки останова, проверять переменные и так далее:
- открыть сгенерированный класс
SampleHandler
в затмении разработки, - поставить точку останова внутри метода
execute
, - вернуться к тестовому затмению,
- выберите «Пример меню» и «Пример команды»
Выполнение остановится на новой точке останова.
Мы видели, что плагин работает, поэтому мы можем удалить сгенерированное примерное меню из него.
Удалить образец меню и его обработчик:
- Откройте файл plugin.xml, перейдите на вкладку расширений и удалите все расширения.
- Найдите и удалите сгенерированный класс
SampleHandler
.
Тег plugin
внутри файла plugin.xml теперь должен быть пустым. Откройте файл plugin.xml и перейдите на вкладку plugin.xml:
1
2
3
4
|
<?xml version= "1.0" encoding= "UTF-8" ?> <?eclipse version= "3.4" ?> <plugin> </plugin> |
Eclipse — это огромный фреймворк, и в него можно установить огромное количество плагинов. Это создает огромную систему функций и плагинов, которые должны взаимодействовать друг с другом. Чтобы сохранить эту систему максимально изолированной и расширяемой, Eclipse Framework использует шаблон проектирования адаптера . Этот шаблон настолько распространен, что вы, вероятно, столкнетесь с ним независимо от того, какой плагин вы напишете.
Этот шаблон проектирования преобразует класс или интерфейс в другой класс или интерфейс. Класс, который выполняет преобразование, называется адаптером. У шаблона есть два разных варианта, и eclipse framework поддерживает оба. Разница между этими двумя разновидностями заключается в том, кто создает адаптер. Это может быть сделано либо непосредственно объектом для преобразования, либо независимой фабрикой адаптеров.
В первом подразделе показано, как написать адаптер. Вторая глава посвящена объектам, способным создавать свои собственные адаптеры, а третья — независимым фабрикам адаптеров. В последней подзаголовке все собрано и показано, как преобразовать объект неизвестного типа.
Адаптер — это объект, который преобразует один тип в другой. Он должен представлять другой тип, например, если он преобразует объекты в класс, он должен расширять этот класс. Если он преобразует их в интерфейс, он должен реализовать этот интерфейс.
Как правило, адаптер преобразует объект, который обладает всеми необходимыми функциями, но не имеет нужного API. Иначе говоря, типичный адаптер содержит очень мало логики. Он только оборачивает исходный объект и делегирует всю работу ему.
Следующий адаптер может преобразовать реализацию интерфейса Minus
интерфейс Plus
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
public class MinusToPlusAdapter implements Plus { private final Minus adaptee; public MinusToPlusAdapter(Minus minus) { super (); this .adaptee = minus; } @Override public int plus( int x, int y) { return adaptee.minus(x, -y); } } |
В более простой версии этого шаблона проектирования преобразовываемый объект создает свои собственные адаптеры.
Мы покажем, как создавать адаптируемые объекты, совместимые с платформой eclipse. В оставшейся части этого подраздела перечислены преимущества и недостатки этого варианта шаблона адаптера.
IAdaptable
объект должен реализовывать интерфейс IAdaptable
. Интерфейс имеет только один метод getAdapter(Class type)
. Возвращает адаптер к запрошенному типу или null
.
Адаптируемый объект:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
public class MinusImpl implements Minus, IAdaptable { public int minus( int x, int y) { return x - y; } public Object getAdapter(Class type) { if (Plus. class .equals(type)) return new MinusToPlusAdapter( this ); return null ; } } |
Метод getAdapter
может вызывать или не вызывать глобальный диспетчер адаптеров для создания адаптера. Некоторые объекты Eclipse называют это, некоторые нет.
Адаптируемые объекты просты в использовании и отладке. Шаблон помогает поддерживать чистоту иерархий классов и интерфейсов. Это также обеспечивает некоторую связь между преобразованным типом и требуемым типом.
Используйте это когда:
- Преобразованный тип уже реализует слишком много интерфейсов.
- Преобразованный тип должен быть совместим с двумя различными функциями, и для каждого требуется расширение другого класса.
- Вы хотите сохранить преобразованный тип и требуемый интерфейс / класс отдельно.
- Адаптеру необходим доступ к закрытым полям методов.
Плагин, который опирается только на эту версию шаблона, не является расширяемым. Сторонние плагины не смогут добавлять в него новые адаптеры.
Вторая версия этого шаблона использует независимую фабрику для создания адаптеров.
Мы покажем, как вызывать фабрики адаптеров в рамках Eclipse. В оставшейся части этого подраздела перечислены преимущества и недостатки этого варианта шаблона адаптера.
Адаптеры создаются фабриками адаптеров. Чтобы добиться независимости, фабрики адаптеров скрыты за глобальным менеджером адаптеров. Код клиента никогда не связывается напрямую с фабрикой адаптеров.
Диспетчер адаптеров предоставляет getAdapter(Object obj, Class type)
который делегирует вызовы установленным фабрикам адаптеров. Этот метод возвращает адаптер или null
.
Используйте диспетчер адаптеров для создания адаптера:
1
|
(Plus) Platform.getAdapterManager().getAdapter(minus, Plus. class ); |
Фабрики адаптеров регистрируются в диспетчере адаптеров либо программно, либо в plugin.xml. Поскольку нашему плагину это не нужно, мы пропустим эту информацию. Для получения дополнительной информации прочитайте угловую статью Eclipse или учебник по адаптерам Eclipse .
Примечание: фабрике адаптеров не разрешается вызывать метод getAdapter(Class type)
для преобразованного объекта. Это вызвало бы бесконечный цикл, потому что метод getAdapter
адаптируемого объекта может вызывать диспетчер адаптеров.
Адаптерные фабрики обеспечивают высокую развязку и расширяемость. Разделение исходного объекта и требуемого типа является абсолютным. Между ними нет зависимости. Вместо этого независимая фабрика адаптеров зависит от обоих.
Запрос диспетчера адаптера для адаптера делает вашу функцию расширяемой. Любой может предоставить адаптеры для интеграции своих объектов с вашим плагином.
Используйте это, чтобы:
- сделать ваш плагин расширяемым сторонними авторами плагинов,
- интегрировать два плагина.
Разделение происходит с более высокой сложностью. Если что-то идет не так, может быть трудно определить, откуда появился неисправный адаптер. Аналогично, поиск доступных адаптеров занимает больше времени, чем в версии этого шаблона для «адаптируемых объектов».
Если вы ожидаете, что другие расширят ваш плагин, укажите, какие адаптеры ожидаются. Документируйте также фабрики адаптеров, которые вы добавляете в систему. Поиск всей этой информации в XML-файлах может занять очень много времени.
Наиболее правильный способ адаптации объекта к желаемому интерфейсу не предполагает предположения о версии шаблона адаптера, используемого объектом.
Выполните три шага, чтобы адаптировать объект к нужному интерфейсу или классу:
- Если объект реализует или расширяет желаемый интерфейс, используйте объект.
- Если объект может адаптироваться сам, используйте адаптер, предоставленный объектом.
- Используйте глобальный менеджер адаптеров для адаптации объекта.
Адаптируйте объект к типу, полная реализация:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
public static Object getAdapter(Object obj, Class type) { // if the object implements or extends the desired interface, use it if (type.isInstance(obj)) return obj; // if the object is able to adapt itself, let it do it if (obj instanceof IAdaptable) { IAdaptable adaptable = (IAdaptable) obj; Object adapter = adaptable.getAdapter(type); if (adapter != null ) return adapter; } // delegate to the global adapter manager return Platform.getAdapterManager().getAdapter(obj, type); } |
Абстрактное дерево синтаксиса и модель Java
Платформа Eclipse использует две разные иерархии для представления исходного кода Java. Первый называется моделью Java, а второй называется абстрактным синтаксическим деревом. Эти иерархии в основном независимы и имеют разные цели и использование.
Иерархия моделей Java легка, отказоустойчива, быстро воссоздается и ее возможности ограничены. Абстрактное синтаксическое дерево обеспечивает полный контроль над исходным кодом Java, но гораздо медленнее воссоздать. По этим причинам Eclipse Framework использует везде, где это возможно, иерархию моделей Java. Абстрактное синтаксическое дерево используется только при необходимости.
Первая глава показывает, как включить эти иерархии в плагине. Вторая подглава содержит обзор модели Java, а последняя содержит обзор абстрактного синтаксического дерева.
Обе иерархии относятся к плагину org.eclipse.jdt.core
. Мы должны добавить плагин ядра jdt к зависимостям плагинов, если мы хотим их использовать:
- Откройте файл plugin.xml и перейдите на вкладку «Зависимости».
- Нажмите кнопку «Добавить» в разделе «Необходимые плагины».
- Выберите плагин
org.eclipse.jdt.core
.
Eclipse автоматически добавит зависимость плагина в раздел Require-Bundle
файла MANIFEST.MF
.
Модель Java представляет собой набор интерфейсов, которые представляют методы Java, классы, интерфейсы и другие элементы. Это легкий, отказоустойчивый и быстро воссоздать.
Модель иерархии Java предоставляет базовую информацию о структуре кода Java. Он также может вносить в него простые изменения. Например, его можно использовать для переименования или добавления новых методов, классов или интерфейсов.
Основным недостатком иерархии моделей Java является то, что она не содержит полную информацию о исходном коде. Например, он не содержит методов тела. В результате невозможно выполнить более сложные изменения исходного кода.
Корнем иерархии модели Java является интерфейс IJavaElement
. Все интерфейсы, которые расширяют его, принадлежат этой иерархии.
Абстрактное синтаксическое дерево
Абстрактное синтаксическое дерево — это набор классов, которые представляют Java-методы, классы, интерфейсы и другие элементы. Он предоставляет полную информацию о структуре кода Java и может вносить в нее любые изменения.
Основным недостатком абстрактной иерархии синтаксического дерева является то, что его воссоздать медленнее, чем в Java-модели. Это также менее отказоустойчиво.
Корнем абстрактной синтаксической иерархии является класс ASTNode
. Все классы, которые его расширяют, относятся к этой иерархии.
Эта глава содержит краткий обзор пользовательского интерфейса Eclipse. Мы объясним только абсолютные основы тех частей пользовательского интерфейса, которые понадобятся позже в этом посте.
Первая глава посвящена наиболее заметной части пользовательского интерфейса Eclipse: представлениям и редакторам. Вторая глава посвящена услуге выбора.
Двумя наиболее важными визуальными компонентами пользовательского интерфейса Eclipse являются представления и редакторы. И редакторы, и представления могут показывать любой контент и представлять его в любой форме. Оба могут быть редактируемыми или только для чтения, но только редактор может сохранять содержимое в несохраненном грязном состоянии.
И редакторы, и представления называются частями. Документация Eclipse использует слово part в качестве ярлыка для «редактора или представления».
Каждая часть должна иметь уникальный идентификатор. Технически, id — это произвольная строка. Тем не менее, соглашение, которому следуют все официальные плагины, заключается в добавлении префикса id к имени плагина. Поскольку имя плагина обычно совпадает с именем корневого пакета плагина, соглашение гарантирует уникальность идентификатора.
Каждая часть должна реализовывать интерфейс IWorkbenchPart
. Интерфейс был расширен дважды, что привело к интерфейсам IWorkbenchPart2
и IWorkbenchPart3
. Вы можете реализовать их напрямую или расширить реализацию по умолчанию, называемую WorkbenchPart
.
Все части являются адаптируемыми . Интерфейс IWorkbenchPart
расширяет интерфейс IAdaptable
. Реализация по умолчанию делегирует метод getAdapter
глобальному менеджеру адаптеров.
Редактор обычно используется для редактирования или просмотра документа или объекта ввода. Изменения, сделанные в редакторе, не сохраняются сразу. Редактор с измененным содержимым находится в грязном состоянии, пока не будет запущена операция сохранения. Если редактор закрыт без сохранения, все несохраненные изменения будут потеряны. Его реализация по умолчанию называется EditorPart
.
Все редакторы появляются в одном и том же регионе страницы и не могут быть свернуты. Может быть несколько экземпляров редактора одного типа.
Панель инструментов редактора отображается вместе с глобальной панелью инструментов, и их меню является частью главного меню.
Документ или входной объект, отредактированный редактором, идентифицируется с использованием экземпляра интерфейса IEditorInput
.
Представление обычно используется для навигации по иерархии информации, открытия редактора или отображения дополнительной информации о предмете, открытом в активном редакторе. Изменения, сделанные в представлении, сохраняются немедленно. Его реализация по умолчанию называется ViewPart
.
Представления могут быть перемещены в любую часть страницы и могут быть свернуты. Как правило, существует только один экземпляр данного представления на странице рабочей среды.
Каждый вид имеет свою локальную панель инструментов и меню. Им также разрешено добавлять кнопки на глобальную панель инструментов и пункты меню в главное меню.
Система выбора Eclipse довольно стандартная. Каждый вид и редактор генерирует свой выбор. Фреймворк также имеет глобальный выбор. Обычно содержит выбор активной части.
Если плагин должен знать выбранные объекты, независимо от того, откуда они берутся, он должен использовать глобальный выбор. Если плагин хочет интегрироваться только с несколькими представлениями и редакторами, он может прослушивать только их выбор.
В этой главе показано, как интерпретировать выбор, как только вы его получите. Как получить текущий выбор, описано в угловой статье Eclipse .
Текущий выбор всегда реализует интерфейс ISelection
. Этот интерфейс чрезвычайно минималистичен. Его единственный метод может определить, является ли выбор пустым или нет.
Чтобы получить более подробную информацию, вы должны привести ее к одному из ее подтипов. Для нашего плагина интересны два подтипа:
-
ITextSelection
— информация о выделенном тексте. Если текст не выделен, содержит позицию курсора. -
IStructuredSelection
— содержит список выбранных объектов.
Структурированный выбор может содержать любые типы объектов. Лучший способ преобразовать их в требуемые классы или интерфейсы — использовать шаблон адаптера . Простого instanceof
и cast может быть недостаточно. Объекты, летящие в затмении, часто можно адаптировать ко многим типам, но они реализуют или расширяют только некоторые из них.
Система меню Eclipse удивительно богата и сложна. Существует как минимум пять типов меню. Одно и то же или похожее меню может быть вызвано несколькими способами. Чтобы сделать его еще более интересным, в Eclipse есть две разные платформы, способные добавлять новые элементы во все эти меню.
Каждая структура меню затмения имеет свою собственную главу, и эти две главы следуют за этой. Эта глава содержит только обзор различных типов меню, обзор меню, в которое наш плагин добавляет свои пункты, и обзор этих двух структур меню.
Eclipse имеет пять типов меню:
- Контекстное меню — меню, вызываемое щелчком правой кнопки мыши. Иногда вызывается также всплывающее меню.
- Главное меню — меню всегда отображается в верхней части графического интерфейса.
- Основная панель инструментов — всегда видимая панель инструментов, доступная в главном меню.
- Меню View — меню, доступное в представлении. Нажмите на белую стрелку вниз в представлении, чтобы вызвать это.
- Панель инструментов представления — небольшая панель инструментов, доступная в большинстве представлений.
В отличие от представлений, редакторы не имеют своего собственного меню или панели инструментов. Они всегда вносят вклад в главное меню или в главную панель инструментов.
Исходное меню содержит такие элементы, как «Организовать импорт» или «Создать методы делегата» и является логическим местом для наших двух функций. Он был добавлен плагином инструментов разработки Java (JDT).
Это меню находится либо в главном меню, либо в контекстном меню. Оба местоположения показывают это только при некоторых обстоятельствах.
Главное меню содержит исходный пункт меню, только если его поддерживает активный вид или редактор. Следующий список содержит примеры видов и редакторов, которые вызывают появление меню источника. Активируйте любой из них, чтобы увидеть его в главном меню:
- Редактор Java,
- Вид иерархии типов,
- Просмотр проводника,
- Project Explorer View.
Контекстное меню содержит исходный пункт меню, если хотя бы один выбранный элемент представляет собой файл Java, класс, метод пакета или другой элемент Java. Конечно, это включает выделение текста в редакторе исходного кода Java. Активировать контекстное меню с исходным подменю:
- откройте исходный файл Java в редакторе и щелкните правой кнопкой мыши внутри,
- выберите файл Java или класс в проводнике пакетов и щелкните правой кнопкой мыши.
Меню источника также можно вызвать с помощью комбинации клавиш «Alt + Shift + S».
Eclipse имеет две разные среды, способные добавлять новые элементы в меню:
- рамки действий,
- командная структура.
Структура действий устарела и устарела. Командная структура является более новой, гибкой и немного более сложной. Это превосходно и должно использоваться для любой новой функциональности.
Командная структура совместима с большинством, но не со всеми меню. Некоторые меню еще не были переписаны, поэтому вы должны использовать структуру действий, чтобы внести в них свой вклад. Например, подменю источника в главном меню совместимо только с каркасом действий.
Некоторые меню несовместимы с обеими платформами. Исходное меню, вызываемое сочетанием клавиш CTRLS + ALT + S, является таким меню. Нельзя этому способствовать.
Примечание: невозможно внести свой вклад в меню редко.
Командная структура может добавлять элементы в большинство меню затмений. Он был разработан как мини-контроллер представления модели и отделяет пользовательский интерфейс от выполняемых действий.
Эта глава содержит основы командной структуры. Мы объясним компоненты командной структуры и используем их для добавления новых элементов в исходное меню. Затем мы покажем, как сделать пункты меню включенными и отключенными. Новые пункты меню будут включены, только если они будут полезны при текущем выборе.
Новое дополнение к меню называется вкладом меню. Каждый вклад в меню должен знать, где рисовать новые элементы, какие элементы рисовать и что должно происходить, когда кто-то нажимает на них.
Большинству меню Eclipse присвоен уникальный идентификатор. Если вы хотите внести свой вклад в меню, вы должны найти этот идентификатор, составить из него так называемый URI местоположения и назначить его для добавления в меню.
Помимо прочего, каждый вклад в меню может добавлять разделители и команды в меню. Разделителями являются те серые линии между различными частями меню. Команды, размещенные внутри меню, представляют собой интерактивные пункты меню. Каждый из них имеет метку, может иметь значок и может быть включен или отключен.
Однако команда не может выполнить действие. Это только абстрактная вещь, предназначенная для отделения GUI от реального действия. Реальная работа выполняется внутри обработчиков команд.
Идентификатор меню — это произвольная строка, назначенная меню или подменю. Каждое меню может иметь несколько идентификаторов. Поиск идентификатора меню в Eclipse может быть очень неприятным и трудным.
Если вам повезет, идентификатор будет раскрыт с помощью Plugin Spy, доступного в Eclipse RCP. Он может отображать информацию об элементах меню, элементах пользовательского интерфейса и работающих плагинах Eclipse. Если вам не повезло, вам придется найти идентификатор самостоятельно.
Все просто, если вы хотите добавить элемент в верхний уровень меню или панели инструментов.
Список общих меню приложений:
- Главное меню Eclipse использует
org.eclipse.ui.main.menu
. Идентификатор относится только к верхнему уровню меню, например, элемент будет помещен вместе с «Файл», «Редактировать» и «Справка». - Панель инструментов Eclipse использует
org.eclipse.ui.main.toolbar
. - В контекстном меню используется идентификатор
org.eclipse.ui.popup.any
.
Если вы хотите внести свой вклад в меню или панель инструментов внутри какого-либо вида, используйте идентификатор вида. К счастью, шпион плагинов может помочь найти идентификатор просмотра. Откройте представление в RCP Eclipse и нажмите «Alt + Shift + F1». Плагин Spy откроет всплывающее окно с просмотром информации:
Поиск идентификатора подменю может быть более сложным, поскольку шпион плагина может не найти его.
Используйте комбинацию клавиш Alt + Shift + F2, чтобы запустить шпион плагина и открыть меню, в которое вы хотите внести свой вклад. Нажмите на любой пункт меню, и Plugin Spy покажет различную информацию о нем.
Используйте Plugin Spy, чтобы получить URI расположения исходного меню:
- открыть любой файл Java в затмении разработки,
- нажмите Alt + Shift + F2,
- щелкните правой кнопкой мыши внутри Java-файла
- наведите курсор на пункт меню «Источник»,
- нажмите на пункт «Очистить …».
Eclipse покажет следующее всплывающее окно:
Если всплывающее окно содержит URI местоположения, то мы почти на месте. Скопируйте и вставьте его куда-нибудь. Предупреждение: всплывающее окно «Плагин-шпион» добавляет новую строку до и после скопированного текста, поэтому может показаться, что ничего не было скопировано.
Часть между: и? это идентификатор меню. Например, если плагин показывает шпион
menu:org.eclipse.jdt.ui.source.menu?after=CleanUp
, идентификатор меню
menu:org.eclipse.jdt.ui.source.menu?after=CleanUp
1
|
org.eclipse.jdt.ui.source.menu |
Если шпион плагина не показывает URI местоположения, это означает, что пункт меню или само меню еще не были переписаны в командную среду. Вот так выглядит всплывающее окно «Плагин-шпион» для старого пункта меню:
Лучше всего поискать в Google и посмотреть на plugin.xml плагинов, которые вносят вклад в это меню. Скорее всего, у кого-то была такая же проблема, и ей удалось ее решить.
Вы можете начать со старого, но все еще хорошего списка контекстных меню, доступных на jdg2e. Если меню уже существовало в Eclipse 3.0, оно отображается там вместе с идентификатором меню. Исходное меню недоступно в этой таблице.
Однако идентификатором его родительского меню, например, меню, доступного при щелчке правой кнопкой мыши в любом файле Java, является #CompilationUnitEditorContext
. Это был бы приемлемый второй приз.
Хотя вклад в меню верхнего уровня с помощью командной структуры прост, неизвестные идентификаторы меню делают вклад в различные подменю трудным или даже невозможным. Если вам не повезло найти его, вы должны использовать старую платформу действий .
Строка URI местоположения состоит из трех частей: схема, идентификатор меню и модификатор размещения:
1
|
< scheme >:< menu-id >[?< placement-modifier >] |
Затмение имеет три схемы:
-
menu
— либо главное меню приложения, либо меню просмотра, -
toolbar
— либо главная панель инструментов приложения, либо панель инструментов просмотра, -
popup
— контекстное меню, например, любое меню, вызываемое по щелчку правой кнопкой мыши.
Модификатор размещения является необязательным. Он имеет форму <placement>=<id>
. Часть размещения либо after
либо before
. Идентификатор — это имя разделителя, идентификатор меню или идентификатор элемента. Будьте внимательны, если в меню нет указанного идентификатора, оно будет игнорировать ваш вклад.
По соглашению каждое меню должно объявлять специальный элемент с идентификатором «дополнения». Это где авторы меню через что вы должны разместить свои пункты. Вы не должны уважать их желание, и в некоторых меню такого пункта нет. Вы можете разместить свои предметы где угодно, даже если в меню есть пункт специальных дополнений.
Несколько примеров:
-
menu:org.eclipse.ui.main.menu?after=file
— добавить элемент в главное меню, между подменю File и Edit. -
toolbar:org.eclipse.ui.main.toolbar
— добавить элемент на главную панель инструментов. -
menu:org.eclipse.ui.navigator.ProjectExplorer
— добавить элемент в меню, доступный в представлении проводника проекта. -
toolbar:org.eclipse.ui.navigator.ProjectExplorer
— добавить элемент на панель инструментов, доступную в представлении проводника проекта. -
popup:org.eclipse.ui.popup.any
— добавить пункт в контекстное меню.
Поместите элемент в исходное меню, не привлекая точное местоположение:
1
|
popup:org.eclipse.jdt.ui.source.menu |
Примечание: мы опускаем необязательное точное местоположение в нашем URI местоположения, потому что это может быть сложно. Если вы также хотите указать точное местоположение, вы должны быть уверены, что выбранное место существует при каждом вызове меню. К сожалению, просто потому, что пункт меню выглядит одинаково, это не означает, что это действительно тот же самый пункт меню.
Например, если бы мы добавили ?after=CleanUp
в конец предыдущего местоположения, наш пункт меню был бы помещен сразу после пункта «Очистить…» в подменю источников, вызываемом щелчком правой кнопкой мыши в редакторе Java. Тем не менее, он будет невидимым в исходном подменю, вызываемом при щелчке правой кнопкой мыши в представлении проводника пакетов.
Команда — это абстрактная вещь, которая представляет действие и имеет уникальный идентификатор. Его можно поместить в меню и назначить ему ярлык.
Команды настраиваются в файле plugin.xml. Откройте его и перейдите на вкладку расширений. Используйте левую часть под названием «Все расширения»:
- Нажмите «Добавить» и выберите точку расширения
org.eclipse.ui.commands
. - Щелкните правой кнопкой мыши новую точку расширения и выберите «Создать» -> «Команда».
- Заполните идентификатор. Соглашение заключается в использовании имени плагина в качестве префикса идентификатора команды.
- Заполните имя.
Мы создали две команды. Один из них называется «Создать пользовательскую строку toString», а другой — «Проверить ненулевой параметр». Их идентификаторы:
-
org.meri.eclipse.defensiveapitools.generatetostring
-
org.meri.eclipse.defensiveapitools.checknonnullparameter
Eclipse автоматически генерирует соответствующий xml и помещает его в файл plugin.xml. Перейдите на вкладку plugin.xml, чтобы увидеть его:
01
02
03
04
05
06
07
08
09
10
11
|
< extension point = "org.eclipse.ui.commands" > < command id = "org.meri.eclipse.defensiveapitools.generatetostring" name = "Generate Custom toString" > </ command > < command id = "org.meri.eclipse.defensiveapitools.checknonnullparameter" name = "Check Non-Null Parameter" > </ command > </ extension > |
Вклад в меню является дополнением к меню. Он знает, где рисовать сам и содержит список элементов, которые должны быть нарисованы. Все элементы, помещенные в меню, отображаются вместе в порядке, определяемом их положением в этом списке.
Мы настроим новый вклад в меню и добавим в него два пункта меню и два разделителя. Добавление других типов элементов в него аналогично.
Пункты меню настраиваются в файле plugin.xml. Откройте его и перейдите на вкладку расширений. Используйте левую часть под названием «Все расширения»:
- Нажмите «Добавить» и выберите
org.eclipse.ui.menus
точку расширения. - Щелкните правой кнопкой мыши на новой точке расширения и выберите «New» -> «menuContribution».
- Заполните местоположение URI .
- Установите allPopups на
true
.
Напомним, что расположение исходного контекстного меню:
-
popup:org.eclipse.jdt.ui.source.menu
Добавьте команды в меню вклада:
- Щелкните правой кнопкой мыши на вкладке меню и выберите «Создать» -> «Команда».
- Нажмите Обзор и найдите ранее созданную команду.
- Заполните этикетку.
Eclipse автоматически генерирует соответствующий xml и помещает его в файл plugin.xml. Перейдите на вкладку plugin.xml, чтобы увидеть его:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
< extension point = "org.eclipse.ui.menus" > < menuContribution allPopups = "true" locationURI = "popup:org.eclipse.jdt.ui.source.menu" > < command commandId = "org.meri.eclipse.defensiveapitools.generatetostring" label = "Generate Custom toString" style = "push" > </ command > < command commandId = "org.meri.eclipse.defensiveapitools.checknonnullparameter" label = "Check Non-Null Parameter" style = "push" > </ command > </ menuContribution > </ extension > |
Проверьте меню. Запустите или отладьте плагин и откройте любой файл Java в тестовом Eclipse. Щелкните правой кнопкой мыши и выберите подменю «Источник». Меню содержит два новых пункта. Поскольку нашим командам не назначены обработчики, оба элемента отключены.
Добавьте разделитель к вкладке меню:
- Щелкните правой кнопкой мыши на вкладке меню и выберите «Новый» -> «Разделитель».
- Установить видимым для
true
. - Введите имя
Порядок элементов в вкладке меню определяет порядок соответствующих элементов в меню. Перетащите новый разделитель туда, где вы хотели бы его видеть.
Eclipse автоматически генерирует соответствующий xml и помещает его в файл plugin.xml. Перейдите на вкладку plugin.xml, чтобы увидеть его:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
< menuContribution allPopups = "true" locationURI = "popup:org.eclipse.jdt.ui.source.menu" > < separator name = "org.meri.eclipse.defensiveapitools.begin" visible = "true" > </ separator > ... commands ... < separator name = "org.meri.eclipse.defensiveapitools.end" visible = "true" > </ separator > </ menuContribution > |
Проверьте меню снова. Запустите или отладьте плагин и откройте любой файл Java в тестовом Eclipse. Щелкните правой кнопкой мыши и выберите подменю «Источник». Наши пункты меню окружены разделителями меню.
Обработчик команд — это класс, который выполняет действие всякий раз, когда пользователь нажимает на элемент меню. Как только мы назначим это команде, пункт меню, созданный в предыдущей главе, будет включен.
Этот раздел состоит из трех частей. Первые два раздела показывают, как создать и настроить фиктивный обработчик. В третьем разделе объясняется, где обработчик может получить информацию о текущих выбранных элементах, активном редакторе и других состояниях пользовательского интерфейса.
Простейший командный обработчик
Обработчик команд должен реализовывать IHandler2
интерфейс. Самый простой способ реализовать это — расширить абстрактный AbstractHandler
класс. Этот класс обеспечивает стандартную реализацию всех необходимых методов, кроме execute
метода.
Метод execute вызывается всякий раз, когда пользователь вызывает команду. У него есть один параметр, который содержит информацию о текущем состоянии приложения. Метод execute должен возвращаться null
.
Наш первый обработчик команд очень прост:
01
02
03
04
05
06
07
08
09
10
|
public class GenerateToStringHandler extends AbstractHandler { @Override public Object execute(ExecutionEvent event) throws ExecutionException { System.out.println( "GenerateToStringHandler" ); // must return null return null ; } } |
Единственное, что нам нужно настроить, — это какие команды должен обрабатывать наш обработчик.
Примечание. Можно также назначить несколько обработчиков для одной команды, но мы не будем этого делать. Это сложная тема, обсуждаемая в дополнительных ресурсах .
Как обычно, обработчики команд настраиваются в файле plugin.xml. Откройте его и перейдите на вкладку расширений. Используйте левую часть под названием «Все расширения»:
- Нажмите «Добавить» и выберите
org.eclipse.ui.handlers
точку расширения. - Щелкните правой кнопкой мыши новую точку расширения и выберите «Создать» -> «Обработчик».
- Найдите идентификатор команды.
- Найдите класс, реализующий обработчик команд.
Eclipse автоматически генерирует соответствующий xml и помещает его в файл plugin.xml. Перейдите на вкладку plugin.xml, чтобы увидеть его:
01
02
03
04
05
06
07
08
09
10
11
|
< extension point = "org.eclipse.ui.handlers" > < handler class = "org.meri.eclipse.defensiveapitools.generatetostring.GenerateToStringHandler" commandId = "org.meri.eclipse.defensiveapitools.generatetostring" > </ handler > < handler class = "org.meri.eclipse.defensiveapitools.checknonnullparameter.CheckNonNullParameterHandler" commandId = "org.meri.eclipse.defensiveapitools.checknonnullparameter" > </ handler > </ extension > |
Запустите или отладьте плагин и откройте любой файл Java в тестовом Eclipse. Щелкните правой кнопкой мыши и выберите подменю «Источник». Пункт меню «Создать пользовательскую строку» включен. Если вы щелкнете по нему, командный обработчик выведет «GenerateToStringHandler» в консоль в RCP Eclipse.
Поскольку мы собираемся вызывать нашу функцию из двух разных мест, наш обработчик команд будет делегировать всю реальную функциональность еще одному классу.
Это другому классу понадобится некоторая информация о контексте, окружающем команду. А именно, «Generate Custom toString» должен знать, какой класс был выбран, а «Проверка ненулевых параметров» должен знать, какой метод был выбран.
Примечание: Eclipse генерирует мини-выборку каждый раз, когда вы помещаете курсор куда-либо. Вам не нужно выделять текст внутри редактора.
execute
Метод получает экземпляр в ExecutionEvent
качестве параметра. Событие выполнения имеет ссылку на контекст приложения, который содержит различную информацию о состоянии затмения.
Используйте, HandlerUtil
чтобы получить эту информацию из события выполнения. Обработчик util является статическим классом и имеет множество getWHATEVER
методов. Нам понадобится четыре из них:
-
getCurrentSelection
— возвращает текущий выбор, -
getActivePartId
— возвращает идентификатор активного просмотра или редактора, -
getActiveEditorInput
— возвращает объект, отредактированный открытым редактором, -
getActiveShell
— возвращаемый объект будет необходим для нашего диалога плагинов.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
private static final String JAVA_EDITOR_ID = "org.eclipse.jdt.ui.CompilationUnitEditor" ; public Object execute(ExecutionEvent event) throws ExecutionException { //this object is needed to render wizards, messages and so on Shell activeShell = HandlerUtil.getActiveShell(event); //get selected items or text ISelection currentSelection = HandlerUtil.getCurrentSelection(event); //identify active GUI part String activePartId = HandlerUtil.getActivePartId(event); if (JAVA_EDITOR_ID.equals(activePartId)) { //get edited file IEditorInput input = HandlerUtil.getActiveEditorInput(event); //currentSelection contains text selection inside input file //... locate class selected in that file ... } else { //currentSelection contains all selected classes //... collect all selected classes ... } return null ; } |
Включение, отключение и видимость
Пункт меню не обязательно должен быть виден и включен постоянно. Большинство команд не универсально применимы.
Обе наши функции будут видны все время. Однако они будут включены только при определенных условиях. «Проверка ненулевых параметров» будет включена:
- внутри редактора Java,
- если текущий выбор содержит только модифицируемые методы Java.
«Generate Custom toString» будет включен:
- внутри редактора Java,
- если текущий выбор содержит только модифицируемые классы Java или исходные файлы.
Во-первых, самый короткий раздел показывает, где настроить видимость и включение. Далее описывается язык xml, используемый для определения видимости и включения условий. Третий раздел использует этот язык для тестирования активного редактора и четвертый тестирует выбранные объекты. Последние два раздела собирают все вместе и показывают условия, необходимые для нашего плагина.
Если вы хотите сделать пункт меню невидимым, используйте visibleWhen
тег в справочнике по командам внутри меню. Если вы хотите отключить элемент, используйте enabledWhen
тег в обработчике команд. Оба тега работают точно так же.
Откройте plugin.xml в редакторе и перейдите на вкладку расширений. Щелкните правой кнопкой мыши ссылку на вкладку меню или обработчик команды и выберите либо, visibleWhen
либо enabledWhen
.
Если вы щелкнете правой кнопкой мыши visibleWhen
или enabledWhen
пометите тегом, Eclipse покажет список возможных под-тегов. Все эти теги являются частью языка булевых выражений xml, и мы будем использовать их для определения условия. Если условие выполнено, пункт меню будет виден или активирован. Если условие не выполняется, пункт меню либо отключен, либо невидим.
Одно предупреждение: не каждый тег, показанный в списке, может использоваться напрямую. В этом случае Eclipse просто показывает все теги, которые определяют условие.
Использование всех перечисленных тегов описано на странице справки Eclipse . Мы объясним только пять тегов, необходимых для наших условий:
-
or
— логично или, -
with
— указать объект при условии, -
iterate
— итератор над коллекцией, -
equals
— сравнивает объект при условии со значением, -
adapt
— приспосабливает объект при условии к указанному.
Or
Элемент or
делает логическим или. Его дочерние теги должны представлять условия. Если хотя бы один из них возвращает true, результат равен true.
With
Элемент with
указывает объект при условии. Этот тег может обращаться к различным переменным, которые описывают состояние Eclipse. У каждой переменной есть имя. Все дочерние элементы with
тега проверят свое состояние на соответствие значению указанной переменной.
Этот тег имеет одно обязательное свойство variable
. Используйте его, чтобы указать имя переменной. Мы будем использовать две переменные:
- activeMenuSelection — коллекция всех объектов, выбранных пользователем,
- activePartId — идентификатор активной в данный момент части графического интерфейса пользователя (просмотр, редактор, страница настроек…).
Поскольку любой плагин может добавить свою собственную переменную, полный список всех переменных найти невозможно. Список переменных по умолчанию доступен на вики-странице Eclipse .
Iterate
Элемент iterate
может использоваться только внутри with
тега и только в том случае, если этот тег указывает коллекцию в качестве объекта в тесте. Его дочерние теги должны представлять условия. Итерация повторяет все объекты внутри коллекции и запускает все дочерние условия для этих объектов.
iterate
Тег имеет два аргумента: operator
и ifempty
. Значение первого аргумента может быть либо and
или or
. Выбранный оператор будет применен к результатам оцениваемых условий. Если оператор не указан, итератор использует and
.
ifempty
Может быть true
или false
. Это значение будет возвращено, если тестируемая коллекция пуста. Если не указано, то true
возвращается, когда оператор равен, and
и false
возвращается, если оператор равен or
.
Equals
Элемент equals
сравнивает тестируемый объект с его value
аргументом. Поскольку тестируемый объект не может быть строкой, аргумент значения преобразуется в объект. Точный алгоритм преобразования описан в руководстве по Eclipse .
Adapt
Элемент adapt
адаптирует тестируемый объект к интерфейсу или классу, указанному в его type
аргументе. У него могут быть дочерние теги, которые могут обрабатывать его дальше, но мы будем использовать его исключительно для проверки того, может ли тестируемый объект адаптироваться к желаемому интерфейсу.
Если меню вызывалось из редактора Java, то идентификатор активной части совпадает с идентификатором редактора Java. Поэтому мы должны получить идентификатор редактора Java и сравнить его со значением activePartId
переменной выражения.
Чтобы получить идентификатор, откройте любой файл Java в RCP Eclipse и нажмите ALT + SHIFT + F1. Плагин Spy покажет всплывающее окно с различной информацией об активной части графического интерфейса. Согласно этому всплывающему окну, идентификатор редактора Java является org.eclipse.jdt.ui.CompilationUnitEditor
.
Объедините теги with
и и equals
сравните идентификатор:
1
2
3
|
<with variable= "activePartId" > <equals value= "org.eclipse.jdt.ui.CompilationUnitEditor" /> </with> |
Текущий выбор может содержать несколько элементов, и все они должны представлять то, с чем мы можем работать. Шаблон адаптера и ява модель иерархия были разработаны именно для такого рода ситуации.
Три интерфейса из иерархии моделей Java имеют отношение к нашим функциям:
-
org.eclipse.jdt.core.IMethod
— представляет методы Java, -
org.eclipse.jdt.core.IType
— представляет Java-классы и интерфейсы, -
org.eclipse.jdt.core.ICompilationUnit
Представляет исходный файл Java.
Поэтому мы будем перебирать activeMenuSelection
переменную и проверять, может ли каждый выбранный объект адаптироваться к одному из необходимых типов. Если элемент не выбран, условие должно вернуться false
.
Метод выбирается, если возможно адаптировать все выбранные объекты в IMethod
интерфейс:
1
2
3
4
5
|
<with variable= "activeMenuSelection" > <iterate ifEmpty= "false" operator= "and" > <adapt type= "org.eclipse.jdt.core.IMethod" /> </iterate> </with> |
Исходный файл java или класс выбирается, если есть возможность адаптировать все выбранные объекты либо в интерфейс, ICompilationUnit
либо в IType
интерфейс:
1
2
3
4
5
6
7
8
|
<with variable= "activeMenuSelection" > <iterate ifEmpty= "false" operator= "and" > <or> <adapt type= "org.eclipse.jdt.core.IType" /> <adapt type= "org.eclipse.jdt.core.ICompilationUnit" /> </or> </iterate> </with> |
Примечание 1: К сожалению, язык выражений xml недостаточно выразителен, чтобы различать классы и интерфейсы. Экземпляр IType
интерфейса представляет класс, если его isClass
метод возвращает true
, но язык XML не поддерживает вызовы метода.
Примечание 2: Мы немного обманываем здесь. Невозможно изменить скомпилированные java-методы и классы внутри jar-пакетов, но они также адаптируются к интерфейсам java-моделей. Эти объекты могут быть изменены, только если метод getCompilationUnit
не возвращает null
. Как и в предыдущем примечании, это невозможно проверить с помощью языка выражений xml. К счастью, мы вносим свой вклад в подменю исходного кода, которое доступно только для изменяемых элементов Java, поэтому нам не нужно решать эту проблему.
Примечание 3: В обоих случаях правильным решением было бы создание собственной with
переменной и решение обеих проблем в Java. Это возможно и просто, но выходит за рамки данной статьи. Если вы хотите знать, как это сделать, прочитайте пост в блоге Lars Vogel .
Проверьте включение ненулевых параметров
Повторим, пункт меню «Проверка ненулевых параметров» будет включен:
- внутри редактора Java,
- если текущий выбор содержит только модифицируемые методы Java.
Используйте or
для объединения условий, созданных в предыдущих главах. Это последнее условие:
01
02
03
04
05
06
07
08
09
10
11
12
|
<enabledWhen> <or> <with variable= "activePartId" > <equals value= "org.eclipse.jdt.ui.CompilationUnitEditor" /> </with> <with variable= "activeMenuSelection" > <iterate ifEmpty= "false" operator= "and" > <adapt type= "org.eclipse.jdt.core.IMethod" /> </iterate> </with> </or> </enabledWhen> |
Генерация пользовательского включения toString
Напомним, что пункт меню «Generate Custom toString» будет включен:
- внутри редактора Java,
- всякий раз, когда выбран класс Java,
- всякий раз, когда выбран файл Java.
Используйте or
для объединения условий, созданных в предыдущих главах. Это последнее условие:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<enabledWhen> <or> <with variable= "activePartId" > <equals value= "org.eclipse.jdt.ui.CompilationUnitEditor" /> </with> <with variable= "activeMenuSelection" > <iterate ifEmpty= "false" operator= "and" > <or> <adapt type= "org.eclipse.jdt.core.IType" /> <adapt type= "org.eclipse.jdt.core.ICompilationUnit" /> </or> </iterate> </with> </or> </enabledWhen> |
Язык выражения — дополнительные ресурсы
Полное объяснение того, как работают эти условия, выходит за рамки этого поста. Если вы хотите узнать больше, основная и короткая статья находится в блоге eclipse-tips, а подробная — в блоге Lars Vogel .
В подробном посте также объясняется, как повторно использовать условия и как создать новую with
переменную. Это определенно стоит прочитать, особенно если вы планируете сделать что-то сложное.
Command Framework — Дополнительные ресурсы
Мы немного упростили вещи в этой главе. Полная функциональность и возможности командной структуры выходят за рамки данной статьи.
Если вы хотите узнать больше, хорошие учебники доступны в блоге Lars Vogel или в библиотеке IBM .
Теоретически, рамки действий устарели и устарели. Более новая структура команд должна использоваться для большинства целей. К сожалению, еще не все меню были переписаны.
Если интересующее вас меню еще не было переписано, вы должны использовать старую платформу действий, чтобы внести в нее свой вклад.
Поскольку большинство меню уже совместимы с новой структурой команд, мы покажем только ту часть структуры действий, которая может вносить вклад в подменю источника в главном меню. Если вы хотите узнать больше о каркасе действий, в последнем подразделе приведены ссылки на более подробные статьи.
Два наиболее важных элемента в структуре действий — действие и делегат действия. Действие назначается элементам меню и знает меню, в котором оно должно быть нарисовано. Действие делегата — это класс, который выполняет всю работу всякий раз, когда вызывается пункт меню.
Каждому делегату действия может быть назначено любое количество действий. Однако каждое действие может иметь только один делегат действия.
Определения элементов и меню хранятся либо внутри набора действий, либо внутри чего-либо, называемого вкладом. Между ними нет большой разницы, и набор действий, и вклад содержат список действий и подменю, которые должны отображаться в системе меню.
Платформа Eclipse имеет три типа вкладов действий, и каждый может указать простое условие, которое должно быть выполнено, чтобы иметь видимое действие:
-
viewerContribution
— действие доступно только внутри указанного представления, -
objectContribution
— действие доступно, только если выбран тип объекта, -
editorContribution
— действие доступно только внутри меню редактора или панели инструментов.
Примечание: также возможно назначить условие для действия. Условия действия являются мощными, но выходят за рамки этой статьи.
И вклад, и набор действий размещаются непосредственно внутри точки расширения. Каждый тип меню имеет свою собственную точку расширения:
-
org.eclipse.ui.actionSets
— главное меню или основная панель инструментов, -
org.eclipse.ui.popupMenus
— контекстное меню, -
org.eclipse.ui.viewActions
— локальное меню или панель инструментов в представлении, -
org.eclipse.ui.editorActions
— локальное меню или панель инструментов в редакторе (напомним, что меню редакторов отображается внутри главного меню / панели инструментов), -
org.eclipse.ui.perspectiveExtensions
— мы будем игнорировать это.
Итак, нам нужно создать класс делегата действия, определить меню, в которое мы хотим внести вклад, и настроить действие внутри набора действий.
Реализация делегата действия зависит от того, где вы хотите разместить связанное действие. Меню предоставляют делегату действия дополнительную информацию, которая зависит от типа меню. Таким образом, каждый тип меню требует реализации различного интерфейса.
Каждый делегат действия должен реализовывать IActionDelegate
интерфейс. Позднее этот интерфейс был расширен с помощью некоторых методов жизненного цикла, поэтому, если вам нужно инициализировать делегат действия или узнать, когда он удаляется, реализуйте также IActionDelegate2
интерфейс.
Какой метод вызывается при нажатии на пункт меню, зависит от реализованных интерфейсов. Делегат действия, который НЕ реализует IActionDelegate2
интерфейс, должен поместить всю работу в run
метод. Однако делегат действия, который реализует IActionDelegate2
интерфейс, должен поместить всю работу в runWithEvent
. В этом случае run
метод никогда не вызывается.
Какие подинтерфейсы IActionDelegate
интерфейса вы должны использовать, зависит от того, где вы хотите разместить действие. Некоторые родительские меню отправляют дополнительную информацию об активных частях, и делегат действия должен иметь возможность ее получить.
Список меню затмений и интерфейсов делегатов ожидаемых действий:
- главное меню или панель инструментов —
IWorkbenchWindowActionDelegate
, - просмотреть меню или панель инструментов —
IViewActionDelegate
, - просмотреть контекстное меню —
IViewActionDelegate
илиIObjectActionDelegate
, - меню редактора или панель инструментов —
IEditorActionDelegate
, - контекстное меню редактора
IObjectActionDelegate
.
Родительское меню использует метод selectionChanged
для информирования делегата действия о текущих изменениях выбора. Однако изменения выбора отправляются делегату действия только после его первого вызова. Все предыдущие изменения выбора игнорируются.
selectionChanged
Метод вызывается в первый раз прямо перед первым вызовом run
или runWithEvent
метода.
Мы готовы реализовать наши действия делегатов. Как и в случае с обработчиком команд в среде команд, наш делегат действия будет собирать только информацию о текущем редакторе и выбранных объектах или тексте. Настоящая работа делегирована еще одному классу.
Поскольку мы хотим поместить наше действие в главное меню, мы должны реализовать IWorkbenchWindowActionDelegate
интерфейс. Главное меню отправляет изменения текущего выделения его делегатам действий, поэтому все, что нам нужно сделать, это сохранить его:
1
2
3
4
5
|
private ISelection selection; public void selectionChanged(IAction action, ISelection selection) { this .selection = selection; } |
Получить текущий редактор немного сложнее. Главное меню не информирует свои пункты об активных частях пользовательского интерфейса. Тем не менее, он отправляет им экземпляр IWorkbenchWindow
после инициализации. К счастью, объект окна рабочего места знает почти обо всем, что происходит в затмении.
Объяснение объекта окна рабочего места заняло бы слишком много места, и это не так важно. Важно то, что он обеспечивает доступ ко всей информации о пользовательском интерфейсе Eclipse.
Используйте окно рабочей среды, чтобы получить активный редактор и его идентификатор:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
private IWorkbenchWindow window; public void init(IWorkbenchWindow window) { this .window = window; } private String getActivePartId() { return window.getPartService().getActivePartReference().getId(); } private IEditorPart getActiveEditor() { return window.getActivePage().getActiveEditor(); } |
Наконец, мы готовы реализовать метод run:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public class GenerateToStringActionDelegate implements IWorkbenchWindowActionDelegate { private static final String JAVA_EDITOR_ID = "org.eclipse.jdt.ui.CompilationUnitEditor" ; public void run(IAction action) { //this object is needed to render wizards, messages and so on Shell activeShell = window.getShell(); //get selected items or text ISelection currentSelection = selection; //identify active GUI part String activePartId = getActivePartId(); //java editor must be handled differently than view selection if (JAVA_EDITOR_ID.equals(activePartId)) { //get edited file IEditorInput input = getActiveEditor().getEditorInput(); //currentSelection now contains text selection inside input file //... locate class selected in that file ... } else { //currentSelection now contains all classes inside //... collect all selected classes ... } System.out.println( "GenerateToStringActionDelegate" ); } } |
Прежде чем настраивать действие, вы должны найти путь к меню или панели инструментов. Он определяет меню или панель инструментов, где будут показаны ваши действия.
Каждое меню или подменю имеет свое имя и путь к меню или на панели инструментов для навигации по этим именам. Он начинается с имени меню верхнего уровня и продолжается со всеми именами подменю. Последняя часть является необязательной и указывает местоположение в последнем меню. Если он отсутствует, элемент помещается в конец указанного меню.
Например, путь меню #menuName/subMenuName/additions
следует читать как «поместить элемент в конце additions
группы , которая находится внутри подменю subMenuName
в #menuName
меню».
Или, путь меню #menuName/subMenuName/
следует читать как «поместить элемент в конце подменю subMenuName
в #menuName
меню».
Важно: Идентификаторы меню такие же, как описано в главе «Структура команд» . Идентификатор ид меню источника org.eclipse.jdt.ui.source.menu
. Поскольку главное меню источника — это меню верхнего уровня, menubarPath — это:
1
|
org.eclipse.jdt.ui.source.menu/ |
Конфигурация действий довольно проста. Добавьте точку расширения, поместите в нее либо набор действий, либо вклад и поместите действие.
Какую из пяти точек расширения следует использовать, зависит от меню. Мы хотим добавить действие в главное меню, поэтому мы должны использовать точку расширения наборов действий.
Откройте файл plugin.xml и перейдите на вкладку расширений. Используйте левую часть под названием «Все расширения». Сначала настройте набор действий:
- Нажмите «Добавить» и выберите
org.eclipse.ui.actionSets
точку расширения. - Щелкните правой кнопкой мыши на новой точке расширения и выберите «New» -> «actionSet».
- Введите идентификатор набора действий. Соглашение заключается в использовании имени плагина в качестве префикса. Важно: это поле имеет некоторые странные ограничения. Мы не могли их понять, поэтому все, что мы можем сказать, это:
-
org.meri.eclipse.defensiveapitools.mainmenucontrib
работает -
org.meri.eclipse.defensiveapitools.sourcemenu
работает, -
org.meri.eclipse.defensiveapitools.mainsource
не работает, -
org.meri.eclipse.defensiveapitools.actionset
не работает.
В любом случае, если в меню ничего не появляется, попробуйте изменить этот идентификатор.
-
- Заполните этикетку. Это может быть что угодно.
- Установить видимым для
true
.
Во-вторых, добавьте действия в набор действий:
- Щелкните правой кнопкой мыши на наборе действий и выберите «Создать» -> «Действие».
- Введите идентификатор действия. Соглашение заключается в использовании имени плагина в качестве префикса id.
- Заполните этикетку. Это может быть что угодно.
- Заполните либо menubarPath, либо toolbarPath.
- Прокрутите вниз и найдите делегата действия в поле класса.
Eclipse автоматически генерирует соответствующий xml и помещает его в файл plugin.xml. Перейдите на вкладку plugin.xml, чтобы увидеть его:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
< extension point = "org.eclipse.ui.actionSets" > < actionSet id = "org.meri.eclipse.defensiveapitools.sourcemenu" label = "Defensive API Tools " visible = "true" > < action class="org.meri.eclipse.defensiveapitools.generatetostring. GenerateToStringActionDelegate" id = "org.meri.eclipse.defensiveapitools.generatecustomtostring" label = "Generate Custom toString" menubarPath = "org.eclipse.jdt.ui.source.menu/" style = "push" > </ action > < action class="org.meri.eclipse.defensiveapitools.checknonnullparameter. CheckNonNullParameterActionDelegate" id = "org.meri.eclipse.defensiveapitools.checknonnullparameters" label = "Check Non-Null Parameters" menubarPath = "org.eclipse.jdt.ui.source.menu/" style = "push" > </ action > </ actionSet > </ extension > |
Запустите или отладьте плагин и откройте любой файл Java в тестовом Eclipse. Нажмите на пункт главного меню Source. Меню содержит два новых пункта. Нажмите на элемент меню Generate Custom toString, делегат действия напечатает «GenerateToStringActionDelegate» в консоли в RCP Eclipse.
Пошаговое руководство по всем видам действий доступно в угловой статье . Легко читаемая статья FAQ объясняет действия в главном меню.
Каркас действий поддерживает также сложные условия и фильтры для отображения действий только при некоторых обстоятельствах. Если у вас есть причина использовать это, лучшая отправная точка в документации затмения .
Все, что напрямую связано с главами этого поста, уже связано. Мы добавим только ссылку на очень хорошую серию с различными советами по разработке Eclipse .
Если у вас есть проблема и вы не можете найти ответ, вы также можете задать вопросы на официальном IRC-канале freenode #eclipse .
Хотя мы добавили в меню только некоторые новые элементы, почти все необходимое для завершения плагина уже есть. Если вы не настаиваете на том, чтобы сгенерированный код был отформатирован, вы сможете завершить функцию генерации toString, просто просмотрев API иерархии моделей Java.
Следующая часть этого урока покажет, как завершить обе функции, включая форматирование сгенерированного кода. Также будет объяснено, как создавать и работать с абстрактным синтаксическим деревом и как создавать диалог для взаимодействия с пользователем.
Ссылка: Написание учебника по плагинам Eclipse — часть 1 от нашего партнера по JCG Марии Юрковичовой вблоге This is Stuff .