Wednesday, November 28, 2007

New plugin for Intellij IDEA: CafeBabe Bytecode Editor plugin (ver. 0.8.0) is available for download

This plugin integrates CafeBabe Bytecode Editor with Intellij IDEA.

Update:

1. Initial implementation.

How to use it inside Intellij IDEA:

- Select class file in the files tree or click on "Open File" icon within plugin toolwindow;
- Activate context menu for the selected file;
- Select "Open in CafeBabe" item from the context menu;
- Class will be disassembled and represented in CafeBabe toolwindow;
- If you want to disassemble some method, navigate to methods list, select one method
and activate context menu. Follow "Go to method body" link. You will be redirected to
"Bytecode Editor" toolwindow;
- Now you can create/delete/edit bytecode instructions;
- If you want to get explanation for a given instruction, click on Help icon.

Tuesday, November 20, 2007

New maven-archetypes plugin (ver. 1.0.0) is available for Intellij IDEA

This plugin helps to generate initial java project layout with the help of Maven Archetypes.

Update:

1. Initial implementation.

How to use it inside IDEA editor:

1. Select Working Directory;
2. Select archetype group;
3. Select archetype;
4. Enter groupId, artifactId, version for your project;
5. Click on Generate button. New project will be generated in the working directory.

Saturday, November 17, 2007

Tips for Intellij IDEA plugins developers (my bloody experience)

1. How to get project with new API

Old fashion:


Project project = (Project)dataContext.getData(DataConstants.PROJECT);


New fashion:


Project project = DataKeys.PROJECT.getData(dataContext);


2. How to register tool window with new API


// Get toolwindow manager
ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);

// Register your tool window at desired location
ToolWindow toolWindow =
        toolWindowManager.registerToolWindow("your_toolwindow_id", true, ToolWindowAnchor.RIGHT);

// Prepare content panel of your tool window (all your controls)
JPanel yourContentPanel = ...

// Get peer factory
PeerFactory peerFactory = PeerFactory.getInstance();

// Create content
Content content = peerFactory.getContentFactory().createContent(yourContentPanel, "", false);

// Add created content
toolWindow.getContentManager().addContent(content);


3. How to persist plugin properties with new API

If you did it for previous versions of IDEA, you probably have the following code:


public class YourPluginConfiguration
       implements ProjectComponent, Configurable, JDOMExternalizable {
  private final String COMPONENT_NAME = ...;
 
  publuc String yourProperty; // property to be persisted

  public String getComponentName() {
    return COMPONENT_NAME;
  }

  public void readExternal(Element element) throws InvalidDataException {
    DefaultJDOMExternalizer.readExternal(this, element); // load
  }

  public void writeExternal(Element element) throws WriteExternalException {
    DefaultJDOMExternalizer.writeExternal(this, element); // save
  }

}


With new API you have to do something like this:


@State(
    name = YourPluginConfiguration.COMPONENT_NAME,
    storages = {@Storage(id = "your_id", file = "$PROJECT_FILE$")}
)
public final class YourPluginConfiguration
          implements ProjectComponent, Configurable, PersistentStateComponent<YourPluginConfiguration> {
  public static final String COMPONENT_NAME = ...;

  publuc String yourProperty; // property to be persisted

  public String getComponentName() {
    return COMPONENT_NAME;
  }

  public YourPluginConfiguration getState() {
    return this; // load
  }

  public void loadState(YourPluginConfigurationstate) {
    XmlSerializerUtil.copyBean(state, this); // save
  }

}


In this example we use $PROJECT_FILE$ macro. You have to use appropriates macros according to component level.

There are 3 types of component level. Each of them has unique, only for this level macros:

- application-level components (ApplicationComponent): $APP_CONFIG$, $OPTIONS$;
- project-level components (ProjectComponent): $PROJECT_FILE$, $WORKSPACE_FILE$, $PROJECT_CONFIG_DIR$;
- module-level components (ModuleComponent): $MODULE_FILE$


4. How to register intention action

Usually intention action should be assoсiated with some analytical tool that recognizes important situation and indicates about it the user. We also can assoсiate intention action with changes in the editor.

First, your class should implement IntentionAction. Additionally, if you want to listen to editor changes,it should extend EditorAction:


public class YourIntentionAction extends EditorAction implements IntentionAction {

  public YourIntentionAction() {
    super(new YourEditorActionHandler());
  }

  private static class YourEditorActionHandler extends EditorActionHandler /* or EditorWriteActionHandler */ {

    // This method is executed every time you do modifications in the editor.
    // Wev are trying to look for selections
    public void execute(Editor editor, DataContext dataContext) {
      String searchText = null;

      SelectionModel selection = editor.getSelectionModel();
      if (selection.hasSelection()) {
        searchText = selection.getSelectedText();
      }

      if (searchText != null && searchText.trim().length() > 0) {
        // Displays pop up

        Project project = DataKeys.PROJECT.getData(dataContext);

        showPopup(project, editor, searchText);
      }
    }
  }

 /**
   * Returns text to be shown in the list of available actions, if this action
   * is available.
   */
  @NotNull
  public String getText() {
    return "The text to show in the intention popup.";
  }

  /**
   * Returns the identifier of the family of intentions. This id is used to externalize
   * "auto-show" state of intentions. When user clicks on a lightbulb in intention list,
   * all intentions with the same family name get enabled/disabled. The identifier
   * is also used to locate the description and preview text for the intention.
   */
  @NotNull
  public String getFamilyName() {
    return "popup";
  }

  /**
   * Checks whether this intention is available at a caret offset in file.
   * If this method returns true, a light bulb for this intention is shown.
   */
  public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
    return editor.getSelectionModel().hasSelection();
  }

  /**
   * Called when user invokes intention. This method is called inside command.
   * If {@link #startInWriteAction()} returns true, this method is also called
   * inside write action.
   */
  public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
    String searchText = null;

    SelectionModel selection = editor.getSelectionModel();

    if (selection.hasSelection()) {
      searchText = selection.getSelectedText();
    }

    showPopup(project, editor, searchText);
  }

  /**
   * Indicate whether this action should be invoked inside write action.
   * Should return false if e.g. modal dialog is shown inside the action.
   * If false is returned the action itself is responsible for starting write action
   * when needed, by calling {@link com.intellij.openapi.application.Application#runWriteAction(Runnable)}.
   */
  public boolean startInWriteAction() {
    return false;
  }

 private static void showPopup(Project project, Editor editor, String searchText) {
    JPanel panel = ... // Create your content here

    JBPopup jbPopup = JBPopupFactory.getInstance()
        .createComponentPopupBuilder(panel, panel)
        .setDimensionServiceKey(project, "popup", false)
        .setRequestFocus(true)
        .setResizable(true)
        .setMovable(true)
        .setTitle("Your title")
        .createPopup();

    jbPopup.showInBestPositionFor(editor);
  }

}


You have to register your intention action. If you have project component, you can do it
in projectOpened() method:


  public void projectOpened() {
    IntentionManager.getInstance().addAction(new YourIntentionAction());
  }


Useful links

1. Tutorial

2. Plugin Development FAQ

3. The Basics of Plugin Development for IntelliJ IDEA

4. IntelliJ IDEA 7.x Developers Documentation

5. IntelliJ Developing Custom Language Plugins for IntelliJ IDEA 5.0

Thursday, November 15, 2007

New version of google-translate plugin for Intellij IDEA (1.0.5)

Google-Translate Plug-in version 1.0.5 is available for download
using IDEA's internal Plugin Manager or directly from the IDEA plug-ins
website at http://plugins.intellij.net/plugin/?id=1460.

Update:

1. Added Translation Preview feature. Select the text for preview and then intention icon will appear. Or press
"Alt-Enter" key combination to force the intention. Another way is to click on "Translation Preview" item
in editor pop-up.
2. Removed deprecated code.

How to use it in side IDEA editor:

1. In editor select the part to be translated;
2. Select "Translate" item from the editor popup menu;
3. (hidden) "translate.google.com" web site (service) will perform actual translation;
4. Response from the service will be inserted in place of your selection.