Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Разработка плагина IntelliJ IDEA. Часть 2

Anna | 5.06.2014 | нет комментариев

Каждая функциональность, предоставляемая плагином, а также изложение и данные об авторе перечисляются в файле plugin.xml.
Разглядим конструкцию файла, в котором присутствуют фактически все важные элементы.

<!-- url="..." определяет URL домашней страницы плагина (отображается на Welcome Screen и в настройках "Plugins") -->
<idea-plugin url="http://www.jetbrains.com/idea">
    <!-- Имя плагина -->
    <name>VssIntegration</name>

    <!-- Неповторимый идентификатор плагина. Не может быть изменен в последующих версиях. Если не указан, то по-умолчанию равен <name> -->
    <id>VssIntegration</id>

    <!-- Изложение плагина -->
    <description>Vss integration plugin</description>

    <!-- Изложение изменений в последних версиях. Отображается в настройках плагинов и Web-интерфейсе -->
    <change-notes>Initial release of the plugin.</change-notes>

    <!-- Версия плагина -->
    <version>1.0</version>

    <!-- Разработчик плагина. Добровольный признак "url" указывает на домашнюю страницу разработчика. Добровольный признак "email" содержит адрес электронной почты разработчика. Добровольный признак "logo" указывает на логотип 16х16, сохраненный в JAR  -->
    <vendor url="http://www.jetbrains.com" email="support@jetbrains.com" logo="icons/plugin.png">Foo Inc.</vendor>

    <!-- Уникальные идентификаторы плагинов от которых зависит нынешний -->
    <depends>MyFirstPlugin</depends>
    <!-- Опциональные зависимости -->
    <depends optional="true" config-file="mysecondplugin.xml">MySecondPlugin</depends>

    <!-- Разрешает плагину интегрировать его справочную систему (в JavaHelp формате) с IDEA. Признак "file" определяет имя JAR в поддиректории "help". Признак "path" определяет имя файла с helpset. -->
    <helpset file="myhelp.jar" path="/Help.hs" />

    <!-- Наименьший и наивысший номер билда, совместимого с плагином -->
    <idea-version since-build="3000" until-build="3999"/>    

    <!-- Имя бандла с текстовыми источниками -->
    <resource-bundle>messages.MyPluginBundle</resource-bundle>

    <!-- Компоненты яруса приложения -->
    <application-components>
        <component>
            <!-- Интерфейс -->
            <interface-class>com.foo.Component1Interface</interface-class>
            <!-- Класс с реализацией -->
            <implementation-class>com.foo.impl.Component1Impl</implementation-class>
        </component>
    </application-components>

    <!-- Компоненты яруса плана -->
    <project-components>
        <component>
            <!-- Интерфейс и реализация совпадают -->
            <interface-class>com.foo.Component2</interface-class>
            <!-- Если "workspace" установлено в "true", компонент сберегает состояние в *.iws файл взамен *.ipr (имеет толк только для реализации JDOMExternalizable). -->
            <option name="workspace" value="true" />            
            <!-- Если представлен тег "loadForDefaultProject", компонент загружается для плана по-умолчанию -->
            <loadForDefaultProject>
        </component>
    </project-components>

    <!-- Компоненты яруса модуля -->
    <module-components>
        <component>
            <interface-class>com.foo.Component3</interface-class>
        </component>
    </module-components>

    <!-- Действия -->
    <actions>    
        <action id="VssIntegration.GarbageCollection" text="Collect _Garbage" description="Run garbage collector">
            <keyboard-shortcut first-keystroke="control alt G" second-keystroke="C" keymap="$default"/>
        </action>
    </actions>

    <!-- Точки растяжения, определенные в плагине. Точки растяжения разрешают иным плагинам предоставлять разные данные. Признак "beanClass" определяет реализацию, используемую при растяжении. -->
    <extensionPoints>    
        <extensionPoint 
name="testExtensionPoint" beanClass="com.foo.impl.MyExtensionBean"/>
    </extensionPoints>

    <!-- Растяжения, которые плагин добавляет к точкам растяжения, 
         определенным в ядре IDEA либо других плагинах.  Признак "defaultExtensionNs" должен соответствовать ID расширяемого плагина либо "com.intellij" если применяется растяжение из IDEA Core. 
         Имя тегов внутри <extensions> должно совпадать с точками растяжения -->
    <extensions xmlns="VssIntegration">    
        <testExtensionPoint implementation="com.foo.impl.MyExtensionImpl"/>
    </extensions>
</idea-plugin>

 

Выполнение и обновление действий

Система действий разрешает плагинам добавлять личные пункты в меню и тулбары IDEA. Действие – это класс, унаследованный от AnAction, чей способ actionPerformed() вызывается, когда выбран элемент меню либо соответствующая ему кнопка тулбара. Скажем, один и тот же класс действия отвечает за пункт меню «File | Open File…» и кнопку «Open File» на тулбаре.

Действия дозволено объединять в группы, которые, в свою очередь, могут содержать подгруппы.
Всякому действию либо группе должен быть присвоен неповторимый идентификатор. Идентификаторы большинства стандартных действий определены в классе com.intellij.openapi.actionSystem.IdeActions.
Всякое действие может быть включено в несколько групп, таким образом, они способны отображаться в разных местах пользовательского интерфейса. Места, в которых могут отображаться действия, определены как константы в интерфейсе ActionPlaces (из того же пакета). Для всякого места создается экземпляр класса Presentation, следственно одно и то же действие может иметь разный текст либо иконку в различных местах интерфейса. Различные представления создаются копированием возвращаемого значения из способа AnAction.getTemplatePresentation().

Для обновления состояния действия периодично вызывается способ AnAction.update(). В способ передается объект типа AnActionEvent, давая информацию о нынешнем контексте и, в частности, специфическое представление, которое следует обновить.

Для приобретения информации о нынешнем состоянии IDE, включая энергичный план, выделенный файл, выделенный текст в редакторе и т.д., может быть использован способ AnActionEvent.getData(). Разные ключи, принимаемые этим способом, описаны в классе DataKeys. Объект типа AnActionEvent также передается в способ actionPerformed().

Регистрация действий

Существует два варианта регистрации действия: перечислением в файле plugin.xml, либо вручную на стадии инициализации компонента.
Разглядим 1-й вариант.

<actions>
    <!-- Элемент <action> определяет действие, которое мы хотим зарегистрировать.
         Непременный признак "id" содержит неповторимый идентификатор действия.
         Непременный признак "class" определяет имя класса, реализующего действие.
         Непременный признак "text" определяет наименование элемента меню либо тулбара.
         Опциональный признак "use-shortcut-of" содержит идентификатор иного действия, дозволяя переиспользовать связанную с ним комбинацию клавиш.  
         Добровольный признак "description" определяет подсказку в строке состояния.
         Добровольный признак "icon" указывает какую иконку отображать пользователю. -->
        <action id="VssIntegration.GarbageCollection" text="Collect _Garbage" description="Run garbage collector"
                icon="icons/garbage.png">
    <!-- Узел <add-to-group> указывает, что действие нужно добавить к присутствующей группе (нескольким группам).
         Непременный признак "group-id" указывает на идентификатор группы.
         Группа должна реализовать класс DefaultActionGroup.
         Непременный признак "anchor" определяет относительную позицию ("first", "last", "before" либо "after").
         Признак "relative-to-action" непременен, если anchor равен "before" либо "after". -->
    <add-to-group group-id="ToolsMenu" relative-to-action="GenerateJavadoc" anchor="after"/>
    <!-- Узел <keyboard-shortcut> определяет комбинации клавиш. 
         Непременный признак "first-keystroke" определяет основную комбинацию. Значение должно быть правильной Swing-комбинацией.
         Добровольный параметр "second-keystroke" определяет дополнительное сочетание.
         Непременный признак "keymap" определяет раскладку. Идентификаторы описаны в классе com.intellij.openapi.keymap.KeymapManager. -->
    <keyboard-shortcut first-keystroke="control alt G" second-keystroke="C" keymap="$default"/>
    <!-- Узел <mouse-shortcut> определяет сочетания с клавишами мыши.
         Они определяются как последовательность слов, поделенных пробелами: "button1", "button2", "button3" для мыши; "shift", "control", "meta", "alt", "altGraph" для клавиатуры; "doubleClick" – для двойного клика. -->
       <mouse-shortcut keystroke="control button3 doubleClick" keymap="$default"/>
     </action>
        <!-- Элемент <group> определяет группу. Элементы <action>, <group> и <separator> определенные внутри механически добавляются в группу.
               Добровольный признак "popup" определяет, как будет показано меню. Если popup="true", действия будут в подменю; если popup="false", действия расположатся в родительском меню. -->
        <group id="TestActionGroup" text="Test Group" description="Group with test actions"
               icon="icons/testgroup.png" popup="true">
            <action id="VssIntegration.TestAction" text="My Test Action" description="My test action"/>
            <!-- Элемент <separator> определяет разграничитель между пунктами. Он может иметь дочерний элемент <add-to-group>. -->
            <separator/>
            <group id="TestActionGroup"/>
             <!-- Элемент <reference> разрешает добавить существующее действие к группе. Непременный признак "ref" содержит идентификатор действия. -->
            <reference ref="EditorCopy"/>
            <add-to-group 
                  group-id="MainMenu" relative-to-action="HelpMenu" anchor="before"/>
        </group>
    </actions>

В случае регистрации действия непринужденно из Java кода, следует исполнить два шага. Для начала, экземпляр класса, производного от AnAction нужно передать в способ ActionManager.registerAction() для создания привязки к идентификатору. Дальше, действие необходимо добавить к одной либо больше группам. Для приобретения экземпляра группы по идентификатору, следует вызвать ActionManager.getAction() и привести итог к типу DefaultActionGroup.
Дальнейшая последовательность шагов требуется для регистрации действий во время запуска IDEA:

  1. сделать класс, реализующий интерфейс ApplicationComponent;
  2. переопределить способы getComponentName, initComponent, и disposeComponent;
  3. зарегистрировать класс в сегменты <application-components> файла plugin.xml.

Для наглядности приведем пример кода, исполняющий описанную процедуру.

public class MyPluginRegistration implements ApplicationComponent {
// Должен возвращать неповторимое имя компонента
    @NotNull public String getComponentName() {
        return "MyPlugin";               
    }
// Позже регистрации класса MyPluginRegistration в сегменты <application-components>
// данный способ выполнится при старте IDEA.
    public void initComponent() {
        ActionManager am = ActionManager.getInstance();
        TextBoxes action = new TextBoxes();
      // Регистрируем действие.
        am.registerAction("MyPluginAction", action);
      // Получаем группу, к которой будет присоединено наше действие.
        DefaultActionGroup windowM = (DefaultActionGroup) am.getAction("WindowMenu");
      // Добавляем к группе разграничитель и действие. 
        windowM.addSeparator();
        windowM.add(action);
    }
// Данный способ применяется для освобождения источников.
    public void disposeComponent() {       
    }
}

 

Создание интерфейса для действий

Если плагину нужно отобразить тулбар либо всплывающее меню со специфическим интерфейсом это может быть исполнено с поддержкой классов ActionPopupMenu и ActionToolbar. Их объекты могут быть сделаны вызовами способа ActionManager.createActionPopupMenu() и ActionManager.createActionToolbar().

Если действие содержится в специфическом компоненте (скажем, панели), обыкновенно требуется вызвать ActionToolbar.setTargetComponent() и передать ему экземпляр компонента как параметр. Это гарантирует, что состояние кнопок тулбара зависит только от состояния связанного компонента, а не от фокуса на фрейме IDE.

Сохранение состояния компонентов

IntelliJ IDEA предоставляет API, дозволяющий компонентам либо сервисам сберегать их состояние между запусками IDE. Сберегать дозволено как простые типы, так и комбинированные объекты вследствие применению интерфейса PersistentStateComponent.

Применение PropertiesComponent для хранения примитивных значений

Если требуетсясберечь лишь несколько простых типов, то примитивный путь достичь этого – применять сервис com.intellij.ide.util.PropertiesComponent. Он может применяться для сохранения значений как яруса приложения, так и яруса плана (данные помещаются в файл workspace).
Для сохранения значений яруса приложения применяется способ PropertiesComponent.getInstance(), а для значений яруса плана – PropertiesComponent.getInstance(Project).

Применение интерфейса PersistentStateComponent

Интерфейс PersistentStateComponent дает больше эластичные вероятности управления сберегаемыми значениями, их форматом и расположением хранилища. Для того Дабы применять его, нужно реализовать в сервисе либо компоненте сам интерфейс, определить класс, отвечающий за состояние, а также указать место хранения применяя аннотацию @State.
Нужно подметить, что экземпляры растяжений не могут сберегать свое состояние с поддержкой PersistentStateComponent. Если это нужно, то рекомендуется сделать обособленный сервис, ответственный за управление состоянием данного растяжения.

Реализация интерфейса PersistentStateComponent

При реализации интерфейс нужно параметризовать классом, описывающим состояние. Класс состояния может быть обыкновенным JavaBean-классом либо же самосильно реализовывать PersistentStateComponent.
В первом случае, экземпляр класса состояния обыкновенно сохраняется как поле в классе компонента.

class MyService implements PersistentStateComponent<MyService.State> {
  class State {
    public String value;
  }

  State myState;

  public State getState() {
    return myState;
  }

  public void loadState(State state) {
    myState = state;
  }
}

Во втором случае, дозволено применять дальнейший образец:

class MyService implements PersistentStateComponent<MyService> {
  public String stateValue;

  public MyService getState() {
    return this;
  }

  public void loadState(MyService state) {
    XmlSerializerUtil.copyBean(state, this);
  }
}

 

Реализация класса состояния

Перед сохранением публичные поля и свойства bean-класса сериализуются в XML-формат. Следующие типы могут быть сохранены:

  • целые и дробные числа;
  • булевы значения;
  • строки;
  • коллекции;
  • словари;
  • перечисления.

Для того Дабы исключить публичное поле из сериализуемых значений, его нужно пометить аннотацией@Transient.
Класс состояния обязан иметь конструктор без параметров, тот, что инициализирует все поля значениями по-умолчанию (это нужно для приведения класса в консистентное состояние до сохранения в XML-файл).

Определение места хранения

Для того Дабы задать где определенно сберегать данные, следует добавить аннотацию @State к классу компонента, в которой нужно указать следующие поля:

  • «Name» (непременно) – определяет имя состояния (наименование корневого тега);
  • одна либо несколько аннотаций @Storage (непременно) – определяет места хранения *.ipr файлов;
  • «roamingType» – тип роуминга (опционально) – определяет, будет ли синхронизироваться состояние между разными экземплярами IDEA, когда использован плагин Server;
  • «Reloadable» (опционально) – если равно false требуется полный перезапуск среды для перезагрузки изменившегося файла состояния.

Примеры применения аннотации @Storage:

  • @Storage(id="other", file = StoragePathMacros.APP_CONFIG "/other.xml") – для значений яруса приложения;
  • @Storage(id="other", file = StoragePathMacros.PROJECT_FILE) – для значений, сберегаемых в файле плана (.ipr);
  • @Storage(id = "dir", file = StoragePathMacros.PROJECT_CONFIG_DIR "/other.xml", scheme = StorageScheme.DIRECTORY_BASED)}) – для значений, сберегаемых в директории плана;
  • @Storage(id="other", file = StoragePathMacros.WORKSPACE_FILE) – для значений, сберегаемых в workspace-файле.

Параметр «id» аннотации @Storage может быть использован для исключения полей при сериализации в определенный формат.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB