Geertjan is a DZone Zone Leader and has posted 457 posts at DZone. You can read more from them at their website. View Full User Profile

Integrating YouTube into IntelliJ (Part 2)

02.25.2008
| 4107 views |
  • submit to reddit
All my questions have now been answered and I've completed my YouTube-IntelliJ integration. The three things I will highlight here are (1) how to add Swing components to the IntelliJ toolbar, (2) how to run a background task, and (3) how to start up the external browser. These are the three elements that make up my integration of YouTube into IntelliJ. In the end, you'll be able to type a search string into the Settings dialog:

And then, when you select the YouTube Search menu item under the Window menu...

...the new JComboBox in the toolbar will be filled, during a background task, with movies that match your search string:

The JComboBox tooltip shows the number of results and reminds you of your search string. Finally, when you select an entry in the list, the external browser will open, displaying the selected movie from YouTube, which you can then watch in the browser.

Firstly, how did I get that JComboBox, which should probably be a JList, into the toolbar? The question isn't exactly correct, because there isn't simply a JComboBox in the toolbar, there's a whole JPanel. That's all thanks to the confusingly named ComboBoxAction.createCustomComponent method. I mean, why is that class called "ComboBoxAction"? I think it's ended up being able to do more than was originally intended, perhaps, or I've missed something here. After all, ANYTHING could be in there, so long as the method returns a JComponent. But the method suggests that it is only intended for JComboBoxes, which is why I created a JComboBox initially and didn't go back to change it to a JList. (I ended up putting a JPanel in there, with the JComboBox inside of it, because I also wanted to have a JLabel there temporarily, to show some test information during development.)

Let's start by remembering where the action can be called from, according to our META-INF/plugin.xml file from yesterday:

        <action id="SearchYouTube" class="com.intellij.tutorial.youtube.YouTubeAction" text="Search YouTube">
<add-to-group group-id="WindowMenu" anchor="first"/>
<add-to-group group-id="MainToolBar" anchor="before" relative-to-action="HelpTopics"/>
</action>

So, it can be called both from the Window menu and from the toolbar. The ComboBoxAction class is useful for both, its "performAction" event is invoked from a menu item, while its "createPopupActionGroup" and "createCustomComponent" populate the toolbar.

Here's the complete code listing for my ComboBoxAction class, with lots of comments interspersed. At some point, the "YouTubeApplicationComponent" class is referred to, this is the class that implements ApplicationComponent, Configurable, JDOMExternalizable (though the latter is deprecated), and which also houses the methods that interact with the YouTube APIs. Nonetheless, hope the following makes sense and that it will be helpful to someone:

package com.intellij.tutorial.youtube;

import com.intellij.ide.BrowserUtil;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.actionSystem.ex.ComboBoxAction;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

public class YouTubeAction extends ComboBoxAction {

ComboBoxModel movieModel;
String[] results;
String phrase;
Application application = ApplicationManager.getApplication();
YouTubeApplicationComponent youTubeComponent = application.getComponent(YouTubeApplicationComponent.class);
JComboBox resultsComboBox = new JComboBox();
JPanel youTubePanel = new JPanel();
JLabel textLabel = new JLabel();

//When the menu item is called under the Window menu,
//the movies are retrieved in a background task,
//this is essentially a "refresh" action, because the "createCustomComponent"
//method, called at the creation of the action, initially fills the JComboBox:
public void actionPerformed(AnActionEvent event) {
getVideos();
}

//Register the action into the DefaultActionGroup,
//via its "id", as expressed in the XML snippet above:
protected DefaultActionGroup createPopupActionGroup(JComponent jComponent) {
DefaultActionGroup group = new DefaultActionGroup();
group.add(ActionManager.getInstance().getAction("SearchYouTube"));
return group;
}

//This method is called when the action is created,
//which is at startup, via the XML tags above.
//It gets the movies and then creates the custom component,
//a JPanel, in the toolbar:
public JComponent createCustomComponent(Presentation presentation) {
getVideos();
youTubePanel.setBorder(BorderFactory.createLineBorder(Color.orange, 2));
youTubePanel.add(resultsComboBox, BorderLayout.WEST);
//For testing purposes, I created a JLabel, which displayed the URL:
//youTubePanel.add(textLabel, BorderLayout.EAST);
return youTubePanel;
}

//Utility method for retrieving the movies,
//notice that ApplicationManager.getApplication().invokeLater() is used,
//which creates our background task, so that the ui isn't frozen
//while YouTube is searched:
public void getVideos() {
application.invokeLater(new Runnable() {
public void run() {
results = youTubeComponent.searchYouTube();
phrase = youTubeComponent.getPhrase();
movieModel = new DefaultComboBoxModel(results);
resultsComboBox.setModel(movieModel);
resultsComboBox.addItemListener(new MovieSelectionListener());
resultsComboBox.setToolTipText(results.length + " results for:\"" + phrase + "\"");
}
});
}

//When an item is selected, the browser needs to start, with the movie's URL:
private class MovieSelectionListener implements ItemListener {
public void itemStateChanged(ItemEvent evt) {
JComboBox cb = (JComboBox) evt.getSource();
String urlToMovie = youTubeComponent.getURLToMovie((String) cb.getSelectedItem());
//For testing purposes, I displayed the URL in the JLabel:
//textLabel.setText("\"" + urlToMovie + "\"");
if (evt.getStateChange() == ItemEvent.SELECTED) {
//Here's the IntelliJ way of starting the browser from code:
BrowserUtil.launchBrowser(urlToMovie);
}
}
}

}

Finally, I've made a first attempt at making this plugin available in the IntelliJ plugin repository. Probably completely wrong in many ways, but here it is. Please let me know if I've broken some conventions somehow or if the plugin itself doesn't work.

 

Published at DZone with permission of its author, Geertjan Wielenga.