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

12 comments:

MrTickTock said...

Great article! There is very little information about new API so that short article is really helpful!!! Thanks!

Guy Mahieu said...

Your post was a great help to me! Thanks man!

Anonymous said...

It was extremely interesting for me to read that blog. Thanx for it. I like such topics and everything that is connected to them. I definitely want to read a bit more soon.

Anonymous said...

Don't stop posting such articles. I love to read blogs like this. BTW add some pics :)

Anonymous said...

[url=http://vegasonlines.net/casino-royal-lloret-de-mar.html]comercio digital escasino bonus [/url]
[url=http://vegasonlines.net/mystic-lake-casino.html]eurobet casino [/url]
[url=http://vegasonlines.net/casino-careers.html]casino terribles vegas [/url]
[url=http://vegasonlines.net/mount-airy-casino.html]casino resort rio vegas [/url]
[url=http://vegasonlines.net/casino-slot-games.html]mirage vegas casino [/url]
[url=http://www.netknowledgenow.com/members/casino_2D00_gamblings_2D00_online.aspx]pop 9 casino game [/url]
[url=http://vegasonlines.net/fort-mcdowell-casino.html]banda sonora casino royal [/url]
[url=http://vegasonlines.net/argosy-casino-kansas.html]bingos y casinos [/url]
[url=http://vegasonlines.net/south-point-casino.html]stardust casino vegas [/url]
[url=http://vegasonlines.net/oregon-casino.html]san juan intercontinental resort casino san juan [/url]
[url=http://vegasonlines.net/casino-st-louis-mo.html]best online casino directory [/url]
[url=http://vegasonlines.net/beau-rivage-resort-casino.html]casino streep poker [/url]
[url=http://vegasonlines.net/casino-in-louisiana.html]casino agua caliente tijuana [/url]
[url=http://vegasonlines.net/accommodation-casino.html]sabadell casino sevilla [/url]
[url=http://vegasonlines.net/riviera-casino.html]juego casino internet ruleta [/url]
linea casino
[b]fallsview casino niagara fall canada[/b]
descarga juego on line casino gratis
casinos online en espana
[b]black jack casino game[/b]
jeu casino
[u]add link online casino[/u]
sistemas casino
casinos en montevideo
[b]online casino[/b]
casino virtual pagina web
trucos casino

Anonymous said...

[url=http://seghan.ru/go.php?sid=35][img]http://s003.radikal.ru/i203/1001/17/1008f12c7936.jpg[/img][/url]












[url=http://members.multimania.co.uk/fjctuke/]buy cigarette cards [/url]
buy cigarettes online from the states buy cigarette tubes aqua filter cigarette holders buy online
[url=http://members.multimania.co.uk/laqoaom/]buy cigarette filters [/url]
buying cigarettes over the enternet buy carlton menthol 100 cigarettes where can you buy rockets cigarettes
[url=http://members.multimania.co.uk/eomuefm/]order newport cigarettes [/url]
were to buy charter menthol cigarettes to buy e cigarette buying cigarette receptacles calgary alberta
[url=http://members.multimania.co.uk/goxiucl/]buy cigarettes with check account [/url]
buying cigarettes online buy marlboro menthol cigarettes buying cigarettes on line
[url=http://members.multimania.co.uk/motluka/]buy malboro cigarettes [/url]
cigarettes native indian mail order alternative cigaretts buy buy barclay 100 cigarettes
[url=http://mitglied.multimania.de/mfoyjqw/]buy cigarettes online new york [/url]
safe site to buy cigarettes online buy some candy and cigarettes lyrics buy cigarettes in kentucky
[url=http://mitglied.multimania.de/hnlgiui/]how to order cigarettes online [/url]
cannabis cigarettes buy buy smokeless cigarettes uk law buying cigarette lighter

Invertir en oro said...

hello, i think that this post is the best that i have read.

buy Crestor said...

greatest post I have seen.

hosted virtual call center said...

Thanks for the list, just submitted to them. Keep up the good work.

Anonymous said...


Cheap Cialis Cheap Cialishttp://www.cheap-cialis.name

Anonymous said...

Duagegealiare Nike Justin Tucker Jersey
Duagegealiare Ray Lewis Jersey Super Bowl
usargoruist Jacoby Jones Super Bowl Jersey

Anonymous said...

Duagegealiare Ahmad Brooks Super Bowl Jersey
Duagegealiare Randy Moss Women's Jersey
usargoruist Haloti Ngata Super Bowl Jersey