目次へ

Download NetBeans! 使ってみる?でも3.4用のプラグインは3.6で動かない鴨。クエ〜。

NetBeansでも俺プラグイン

まったくこのごろあどいつもこいつもEclipse、Eclipseってヨ。そんなにプラグインが作りてえのかい。プラグインだったらNetbeansだって作れるんだゼ!ほとんど手探りだがな!・・・ほとんどサバイバルに等しい、俺プラグイン開発修行の記。積み上げ方式にさせていただきます。積み上がるのかッ?

*プラグインを入れるとNetBeansていうかSun ONE Studio自体が不安定になることがあります。マジで。お仕事用の開発ツールでのプラグイン実験はおサケください。ヒック。

/ファイル名取得の試み/外部コマンドの起動(未完成)/作成するファイル名を指定する/最初のモジュール実行結果/最初の実行プログラムJustMenu/最初のmanifest.mf/最初のLayer.xml/最初のモジュールjustmenu/環境/資料/目的/


ファイル名取得の試み

 外部コマンドの起動はエラー含みでちと怪しいが、とにかく不可能ではないということがわかった。もうひとつの柱は、エクスプローラからファイルを選んでそれに対して外部コマンドをぶちかますことである。
 いろいろ調べた結果、エクスプローラウィンドウに対して独自の操作を行わせるには、エクスプローラウィンドウから自分で作ったほうがいいらしいとわかってきた。それも面白かろう。ぜひ作ってみたい、いつかは。
 だが今それをやっていると日が暮れる。今はとにかく既存のエクスプローラーのファイルリストからこのファイルを選んで・・・というのを実現させなければならない。
 それでまたいろいろ調べて結局こんなものを作ってみた。

 まず、s4.selecttestというパッケージを作る。

 次に、このパッケージ内で「新規作成」->「NetBeans拡張子」->「Actions API」->「Node Action」を選ぶ。初めての試みである。オブジェクト名は「myNodeAction」にする。
 すると、またいろいろなものが自動作成される。

 作成されたものから、myNodeAction.javaファイルだけを残してみんな消しちゃう。そしてそのファイルの中身もほとんど消しちゃってこんなふうにする。

package s4.selecttest;

import org.openide.nodes.Node;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.actions.NodeAction;

import org.openide.TopManager;
import org.openide.NotifyDescriptor;

/** Action sensitive to the node selection that does something useful.
* Consider using a cookie action instead if you can define what the
* action is applicable to in terms of cookies.
* @author noniko
*/
public class myNodeAction extends NodeAction {



protected void performAction(Node[] nodes) {

}//何も書かない

protected boolean enable(Node[] nodes) {
// e.g.:
return nodes.length == 1;//手をつけない
}

public String getName() {
return "just Select";//名前がどう関わってくるのかわかんないけど念のためてきとーにつけた
}

//以下、手をつけない。たぶんアイコンなんか全然機能してないけど消すのもなんだしさわらない。

protected String iconResource() {
return "myNodeActionIcon.gif";
}

public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
// If you will provide context help then use:
// return new HelpCtx (myNodeAction.class);
}



/** Perform extra initialization of this action's singleton.
* PLEASE do not use constructors for this purpose!
* protected void initialize () {
* super.initialize ();
* putProperty (Action.SHORT_DESCRIPTION, NbBundle.getMessage (myNodeAction.class, "HINT_Action"));
* }
*/



}

こうしておいて、同じパッケージ内に今までさんざ使ってきたCallable Actionのファイル、selectNode.javaをまた作る。中身はこう。

package s4.selecttest;

import org.openide.util.actions.CallableSystemAction;
import org.openide.util.HelpCtx;
import org.openide.TopManager;
import org.openide.NotifyDescriptor;

import org.openide.nodes.Node;
import org.openide.util.actions.NodeAction;

public class SelectNode extends CallableSystemAction{

public org.openide.util.HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}

public String getName() {
return "SelectNode";
}

public void performAction() {

NodeAction naction=new myNodeAction();
// インターフェイスNodeActionから、今作ったmyNodeActionへ、こういうのダウンキャストっていうのかな?

Node[] currentNodes=naction.getActivatedNodes();
Node mynode=currentNodes[0];  //ほしいノードは一個だけ。

String nodestr=mynode.toString(); //これで何が出るのか!?

TopManager.getDefault().notify(
new NotifyDescriptor.Message(
"Selected File: "+nodestr
)
);

}

}

APIをいろいろしらべて、「今アクティブになってるノード」つまり「選択したノード」を取得する方法はわかった。
じゃあそのノードの情報を得たい。どうすれば?とりあえず、toString()メソッドがあったので、かましてみて何が出力されるか当たってくだけてみることにした。

Layer.xmlやmanifestファイルの書き方はこれまでと同じだ。Main-ClassにselectNodeを指定すればよい。
実行してみる。 エクスプローラから適当なファイルのノードを選んで選択。「SelectNode」と名付けたメニューを選択して起動する。

おお、なんかそれらしいものが現れたぞ。どうやらプロパティの列挙のようだ。クラスのようなもの、IDのようなもの、Name=以下やdisplayName=あたりがファイル情報として使えそうだ!

2003年8月28日

ページ先頭に戻る


外部コマンドの起動(未完成)

 次は外部コマンドの起動。Open APIsにはExecution APIというAPIがあるのだが、詳しく調べてみるとどーも外部のjavaコマンドを起動するために用意されているらしい。ま〜そりゃそうだろな。ガンバって手を加えれば他のコマンドにも使えるのだろうが・・・。ここでは、フツーにjavaで外部コマンドを起動する方法を試してみた。
これまでと全く同様の作り方で、performAction()メソッド中にRuntimeクラスのexecコマンドをかますというものだ。ここではNetscapeを起動するようにしてみた。

package s4.exeQ;


import org.openide.util.actions.CallableSystemAction;
import org.openide.util.HelpCtx;
import org.openide.TopManager;
import org.openide.NotifyDescriptor;

import org.openide.filesystems.FileObject;
import org.openide.filesystems.Repository;

public class myexeQ extends CallableSystemAction{

public org.openide.util.HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}

public String getName() {
return "Exec Command";
}

public void performAction() {

try{
Runtime myrun=Runtime.getRuntime();
myrun.exec("/export/home/noniko/Netscape/netscape");
}
catch(Exception e){
TopManager.getDefault().notify(
new NotifyDescriptor.Message(
"Exception in Running command: "+e.getMessage()
)
);
System.exit(1);
}
System.exit(0);
}

}

モジュールをインストールして起動すると、エラーメッセージが出る。
「Illegal attempt to exit early」
というのがその骨子のようだ。 だが、ねすけ自体は起動する。
exitが早すぎる、というのは上のソースの中のexitコマンドがよくないのかな?
と、この部分を削除してみた。だがエラーは変わらなかった。 他の部分のエラーなのか、ちゃんと修正結果が反映されていないのかは、まだ謎だ。

2003年8月28日

ページ先頭に戻る


作成するファイル名を指定する

Open APIsのチュートリアルをたくさん探すと、最初の一歩は「空のファイルを作成する」モジュールであることがわかってくる。
これは、すでに「/sub/NewFile.java」という特定のファイル名をプログラム中に書き込んであり、この名前のファイルが作成される。もちろんわたしの目的は任意のファイルに外部コマンドをかますことであるから、ファイル名を任意に指定したい。
でもディレクトリから指定するのは大変なので、作業フォルダの下、ファイル名だけを指定できるようにしよう。

サンプルには、ダイアログボックスのテキストフィールドに名前を入力して「OK」とやると、あなたの名前はそれですねと返してくるプログラムがある。こいつをファイル名の入力に使えばいい。二つのサンプルプログラムの合体だ。

ディレクトリ階層を作る。

/lib
/manifests
/s4/nonimenu の3つをさっき作ったところだ。

createmyfileフォルダを/s4/の下に、nonimenuフォルダに横付けする感じで作る。
/s4/createmyfile

/s4/createmyfile/Layer.xmlはさっきとおんなじ。

<?xml version="1.0" encoding="UTF-8"?>

<filesystem>
<folder name="Menu">
<folder name="Noniko">
<file name="s4-createmyfile-CreateMyFile.instance"/>
</folder>
</folder>
</filesystem>

/manifests/createmyfile.mfである。

Manifest-Version: 1.0
OpenIDE-Module: s4.createmyfile
OpenIDE-Module-Name: Create my File
OpenIDE-Module-Layer: s4/createmyfile/Layer.xml
OpenIDE-Module-Specification-Version: 1.2
OpenIDE-Module-Module-Dependencies: org.openidex.util/2 > 2.1

Name: s4/createmyfile/CreateMyFile.class
OpenIDE-Module-Class: Action

まず、入力用ダイアログボックスを作るクラス、/s4/createmyfile/CreateFilePanel.java

package s4.createmyfile;

import org.openide.TopManager;
import org.openide.NotifyDescriptor;
import org.openide.util.HelpCtx;

public class CreateFilePanel extends javax.swing.JPanel {

public CreateFilePanel() {
initComponents ();
}

private void initComponents() {
jLabel1 = new javax.swing.JLabel();
jTextField1 = new javax.swing.JTextField();

setLayout(new java.awt.GridLayout(1, 1));

setBackground(new java.awt.Color(204, 204, 204));
setBorder(new javax.swing.border.TitledBorder("Dialog"));
setMinimumSize(new java.awt.Dimension(300, 50));
setPreferredSize(new java.awt.Dimension(300, 50));
jLabel1.setText("File Path: ");
add(jLabel1);

jTextField1.setText("Name");
jTextField1.addInputMethodListener(new java.awt.event.InputMethodListener() {
public void inputMethodTextChanged(java.awt.event.InputMethodEvent evt) {
jTextField1InputMethodTextChanged(evt);
}
public void caretPositionChanged(java.awt.event.InputMethodEvent evt) {
}
});

add(jTextField1);

}

private void jTextField1InputMethodTextChanged(java.awt.event.InputMethodEvent evt) {//GEN-FIRST:event_jTextField1InputMethodTextChanged
}

public void requestFocus () { //set focus for one components (myField in this case)
jTextField1.requestFocus();
}

public javax.swing.JTextField getTextField(){ return jTextField1; }

private javax.swing.JTextField jTextField1;
private javax.swing.JLabel jLabel1;

}

もう、明らかにGUIエディタで使ったなと言わんばかり、Sun ONE Studioの特徴でもある変数定義がプログラムの一番最後に来る形だ。ちなみに本当にこれはただのSwingプログラムのようである。

実際の実行プログラムはこっちのCreateMyFile.java

package s4.createmyfile;

import java.awt.Dialog;
import org.openide.TopManager;
import org.openide.DialogDescriptor;
import org.openide.NotifyDescriptor;
import org.openide.util.HelpCtx;
import org.openide.util.actions.CallableSystemAction;

import java.io.*;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.Repository;

public class CreateMyFile extends CallableSystemAction {


public String getName () {
return "Create File";
}

public HelpCtx getHelpCtx () {

return HelpCtx.DEFAULT_HELP;
}

public void performAction () {

String title = "Insert FilePath to Create";
CreateFilePanel cfp = new CreateFilePanel(); // create new DialogPanel

DialogDescriptor dd = new DialogDescriptor (cfp, title);
//入力パネルを材料に、 DialogDescriptorというものを作るようだ

cfp.requestFocus(); // 入力パネルが現れたらフォーカスを当てる

TopManager.getDefault ().createDialog (dd).show ();
//出動するのは入力パネルを材料にしたDialogDiscriptorなわけだ

if (dd.getValue () == DialogDescriptor.OK_OPTION) { //OK送信されたらTextFieldの内容を読み込めというのか。
String filename=cfp.getTextField().getText(); //ファイル名をゲット
DoCreate(filename);//これはのに子が作ったメソッドだよ。
}
else{
String theMessage = "An Error Occured";
TopManager.getDefault ().notify (new NotifyDescriptor.Message(theMessage));
// これはまた別のエラー表示用のツールらしい
}
}

private void DoCreate(String filename){
Repository repo=TopManager.getDefault().getRepository();
FileObject folder=repo.find("s4.createmyfile",null,null);
//Repositoryは「パッケージ」を指定することによりファイルの位置を指定するらしい???

try{
FileObject newfile=folder.createData(filename, "txt");//ゲットしたファイル名でテキストファイルを作る
}
catch(IOException e){
e.printStackTrace();
}

}
}

あいにく、作るのがイッパイイッパイだったので、ファイル名を入力してOKを送信してやると何の応答も返さずただファイルを作成するだけのブキッチョなモジュールだ。でも少し制御性が高まったぞ。


goPluginというファイルを作成したところ。

2003年7月23日

ページ先頭に戻る


最初のモジュール実行結果

これをモジュールとしてインストールする方法は、やはり「資料」にご紹介した本やウェブサイトでくあーしく解説されてあるのでここでは割愛する。
でも全然書かないのもなんだから、/libフォルダを右クリックして、「New」->「NetBeans拡張子」->「Modules API」->「Module JAR」を選び、あとはウィザードに従ってパッケージ化するということだけご紹介。
できたモジュールをExecuteして、I/Oウィンドウに数行のコメントのあと最後に「Done」と書かれれば成功だ。
実はバージョン違いなどにより成功せず、エラーメッセージを吐き出されたことが何度もある。

するとIDメニューにこんなものが生意気にもできている。

かなり感動的だ。おそれおおくもSun ONE StudioにNonikoメニューなどが。よくあることだがこのショットも他に二つほどモジュールを作った後なので、肝心のReportアイテムは最下段に表示させてオリヤス。すみません。
さて、「Report」を選択してみよう。

グレート。最初はのにがなんだか全然わからなかったモジュール開発コードだが、案外行けそうだ!

2003年7月23日

ページ先頭に戻る


最初の実行プログラムJustMenu

では実行プログラムを作る。ソースファイルは次の位置に配置する。

/s4/nonimenu/JustMenu.java

内容は以下のとおり。

package s4.nonimenu;

import org.openide.util.actions.CallableSystemAction;
import org.openide.util.HelpCtx;
import org.openide.TopManager;
import org.openide.NotifyDescriptor;

public class JustMenu extends CallableSystemAction{

public org.openide.util.HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}

public String getName() {
return "Report"; //メニューアイテムに「Report」と表示させるためのもの。
}

public void performAction() {

TopManager.getDefault().notify( //メッセージボックスに文字列を表示させる
new NotifyDescriptor.Message(
"Just Created a Menu"//表示させたい文字列
)
);

}

}

2003年7月23日

ページ先頭に戻る


最初のmanifest.mf

実際justmenu.mfという名前で他のプログラムのマニフェストファイルと区別する。

Manifest-Version: 1.0
OpenIDE-Module: s4.justmenu
OpenIDE-Module-Name: Just Menu
OpenIDE-Module-Layer: s4/nonimenu/Layer.xml
OpenIDE-Module-Specification-Version: 1.2
OpenIDE-Module-Module-Dependencies: org.openidex.util/2 > 2.1

Name: s4/nonimenu/JustMenu.class
OpenIDE-Module-Class: Action

これはサンプルファイルをほとんどパクったものだ。

2003年7月23日

ページ先頭に戻る


最初のLayer.xml

さてLayer.xmlというのは何か。要するにメニューバーや右クリックメニューにメニューアイテムを表示させるための設定ファイルのようだ。その一番簡単な形は。

<?xml version="1.0" encoding="UTF-8"?>
<filesystem>
<folder name="Menu">
<folder name="Noniko">
<file name="s4-nonimenu-JustMenu.instance"/>
<attr name="s4-nonimenu-JustMenu.instance"/>
</folder>
</folder>
</filesystem>

チュートリアルによると、この意味は以下の通りらしい。システムのfilesystemフォルダにはMenuフォルダを初めIDEのいろいろなコンポーネントのフォルダがあるんだそうだ。
filesystem/Menuフォルダまではシステムに用意されているので、そこにNonikoというフォルダを作る。
そこにs4-nonimenu-JustMenu.instanceというファイルを作る。
そのファイルにs4-nonimenu-JustMenu.instanceという属性を与える。

ところがわたしが探したところでは、そんなフォルダはついぞ見つからなかった。何かファイルが新しく作られた形跡もない。
だがこれでモジュールは動いた。ということは何か仮想的な階層構造なんだろうか?どこかに圧縮された形であるのか?今のところ謎だ!

でも、これでメニュー->Noniko->これから作るモジュール という感じのものがなんとなくつかめた。

2003年7月23日

ページ先頭に戻る


最初のモジュールjustmenu

では最初のモジュールを作ってみよう。

1)モジュールの機能

メニューバーに「Noniko」オプションを表示させ、ここをクリックすると「Report」というメニューアイテムが現れる。
それを選ぶと、メッセージボックスに適当なメッセージが表示される。

2)上記機能を生じさせる目的

サンプルではまずとにかくメニューが表示されることになっているが、そのしくみを知りたい。
メッセージは最初フツーのSystem.out.printlnメソッドを試みたがむしろうまく行かなかった。

3)ディレクトリ構造

SampleFourというフォルダを作って、それをSun ONE Studioでマウントした。Fourというのはつまり3回ほど失敗しているという意味だ。
そのフォルダ内にこういうディレクトリを作る。

/lib
/manifests
/s4/nonimenu

s4.nonimenu が、これから作るプログラムのパッケージ階層だ。次に、

/manifests/nonimenu.mf
/s4/nonimenu/Layer.xml

というファイルをそれぞれ作る。まずは名前だけの空ファイルだ。

2003年7月23日

ページ先頭に戻る


環境

最新の環境を使いたいところだが、あいにくOpen APIs はバージョン依存性がかなり強いようだ。

わたしがゲットしたサンプルコードは、

「詳解Sun ONE Application Server7 パーフェクトガイド(サン・マイクロシステムズ(株)Sun ONE事業本部 著、技術評論社発行)」

の付録CD中のものだ。これはSun ONE Studio4で、Open APIs Supportのバージョンは2.10.2である。
今回Sun ONE Studio4のアップデートセンターから自動インストールしたのもこのバージョンだった。そして上記のサンプルコードは全部元気よく動いてくれた。

だが、最新のNetbeans3.5ではより新しいOpen APIs Supportのバージョンが自動インストールされ、これでは上記のコードは動いてくれなかった。

というわけでとりあえず動くSun ONE Studio4 Community Editionを使うことにした。これでもうちょっと勉強したら、バージョンアップに対応できるようになるのか!?

OpenAPIsの導入やモジュールのインストール・実行法については下の「資料」で詳解したサイトに詳しく書いてあるので、そっちを見てネ!このサイトでは実際のコードを集中的に詳解するつもりです。

2003年7月23日

ページ先頭に戻る


資料

ほとんどない。

Sunのサイトに、 ひと世代前の「Forte4jカスタマイズ」チュートリアルというのはある。
http://sdc.sun.co.jp/sunone/tutorial/forte4j/ というのがそれだ。非常に詳しく書いてある・・・のは、やはりサンプルの配備と実行の仕方だ。そして、ここからダウンロードできるサンプルは、初めの一件だけはSun ONE Studio4で実行できたが、他のほとんどは実行エラーを起こした。ほとんどというのは最後まで試す前に挫折したからである。どうやらOpen APIsはバージョンによって激しく違うらしい。

最近のバージョンに合ったpdfチュートリアルは見つけた。

http://developers.sun.com/tools/javatools/articles/handbook.pdf というのがそれだ。ただ、わたしにとっては到底初めの一歩を踏み出せそうなシロモノでは、ない。

サンプルコードと、上記の最新pdfを何度も見比べて、なんとなく感じをつかんで行くというのが勉強方法だ。

2003年7月23日

ページ先頭に戻る


目的

Relaxerのように、外部コマンドでjavaプログラムを扱う場合、作業場がターミナルだとjavaファイルの管理がめんどくさい。Sun ONE Studioのような開発ツール上でjava以外の外部コマンドも自由に扱えたらステキだろう。エクスプローラ上でファイルを右クリックすると、「relaxer」とか「gcc」とかいうメニューがあって、テキストフィールドに必要パラメータを入力してエイっとやればI./Oウィンドウに実行結果が現れる・・・
環境としてはPeggyに近いってか。確かに・・・

2003年7月23日

ページ先頭に戻る