File: plugin-implement.xml

package info (click to toggle)
jedit 4.5.2%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 12,252 kB
  • sloc: java: 90,581; xml: 88,372; makefile: 55; sh: 25
file content (1250 lines) | stat: -rw-r--r-- 55,004 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="plugin-implement">
    <!-- jEdit buffer-local properties: -->
    <!-- :xml.root=users-guide.xml: -->
    <!-- :maxLineLen=80:wrap=soft: -->
    <title>Implementing a Simple Plugin</title>
    <!-- jEdit 4 Plugin Guide, (C) 2001, 2002 John Gellene      -->
    <!-- jEdit 4.5 Plugin Guide, (C) 2005, 2011 Alan Ezust      -->

    <para>There are many applications for the leading operating systems that
    provide a <quote>scratch-pad</quote> or <quote>sticky note</quote> facility
    for the desktop display. A similar type of facility operating within the
    jEdit display would be a convenience. The use of dockable windows would
    allow the notepad to be displayed or hidden with a single mouse click or
    keypress (if a keyboard shortcut were defined). The contents of the notepad
    could be saved at program exit (or, if earlier, deactivation of the plugin)
    and retrieved at program startup or plugin activation.</para>

    <para>We will keep the capabilities of this plugin modest, but a few other
    features would be worthwhile. The user should be able to write the contents
    of the notepad to storage on demand. It should also be possible to choose
    the name and location of the file that will be used to hold the notepad
    text. This would allow the user to load other files into the notepad
    display. The path of the notepad file should be displayed in the plugin
    window, but will give the user the option to hide the file name. Finally,
    there should be an action by which a single click or keypress would cause
    the contents of the notepad to be written to the new text buffer for further
    processing.</para>

    <para>The full source code for QuickNotepad is contained in jEdit's source
    code distribution. We will provide excerpts in this discussion where it is
    helpful to illustrate specific points. You are invited to obtain the source
    code for further study or to use as a starting point for your own
    plugin.</para>

    <section id="plugin-load">
        <title><indexterm>
                <primary>Plugin API</primary>

                <secondary>loading at startup</secondary>
            </indexterm> How Plugins are Loaded</title>

        <para>We will discuss the implementation of the
        <application>QuickNotepad</application> plugin, along with the jEdit
        APIs it makes use of. But first, we describe how plugins are
        loaded.</para>

        <para>As part of its startup routine, jEdit's <function>main</function>
        method calls various methods to load and initialize plugins.</para>

        <para>Additionally, plugins using the jEdit 4.2 plugin API can be loaded
        and unloaded at any time. This is a great help when developing your own
        plugins -- there is no need to restart the editor after making changes
        (see <xref linkend="plugin-implement-reloading" /> ).</para>

        <para>Plugins are loaded from files with the <filename>.jar</filename>
        filename extension located in the <filename>jars</filename>
        subdirectories of the jEdit installation and user settings directories
        (see <xref linkend="settings-directory" />).</para>

        <para>For each JAR archive file it finds, jEdit scans its entries and
        performs the following tasks:</para>

        <itemizedlist>
            <listitem>
                <para>Adds to a collection maintained by jEdit a new object of
                type <ulink url="../api/org/gjt/sp/jedit/PluginJAR.html">
                <classname>PluginJAR</classname></ulink>. This is a data
                structure holding the name of the JAR archive file, a reference
                to the <ulink url="../api/org/gjt/sp/jedit/JARClassLoader.html">
                <classname>JARClassLoader</classname></ulink>, and a collection
                of plugins found in the archive file.</para>
            </listitem>

            <listitem>
                <para>Loads any properties defined in files ending with the
                extension <filename>.props</filename> that are contained in the
                archive. See <xref
                linkend="plugin-implement-properties" />.</para>
            </listitem>

            <listitem>
                <para>Reads action definitions from any file named
                <filename>actions.xml</filename> in the archive (the file need
                not be at the top level). See <xref
                linkend="plugin-implement-actions" />.</para>
            </listitem>

            <listitem>
                <para>Parses and loads the contents of any file named
                <filename>dockables.xml</filename> in the archive (the file need
                not be at the top level). This file contains BeanShell code for
                creating docking or floating windows that will contain the
                visible components of the plugin. Not all plugins define
                dockable windows, but those that do need a
                <filename>dockables.xml</filename> file. See <xref
                linkend="plugin-implement-dockables" />.</para>
            </listitem>

            <listitem>
                <para>Checks for a class name with a name ending with
                <filename>Plugin.class</filename>.</para>

                <para>Such a class is known as a <firstterm>plugin core
                class</firstterm> and must extend jEdit's abstract <ulink
                url="../api/org/gjt/sp/jedit/EditPlugin.html">
                <classname>EditPlugin</classname></ulink> class.</para>

                <para>The initialization routine checks the plugin's properties
                to see if it is subject to any dependencies. For example, a
                plugin may require that the version of the Java runtime
                environment or of jEdit itself be equal to or above some
                threshold version. A plugin can also require the presence of
                another plugin.</para>

                <para>If any dependency is not satisfied, the loader marks the
                plugin as <quote>broken</quote> and logs an error
                message.</para>
            </listitem>
        </itemizedlist>

        <para>After scanning the plugin JAR file and loading any resources, a
        new instance of the plugin core class is created and added to the
        collection maintained by the appropriate <ulink
        url="../api/org/gjt/sp/jedit/PluginJAR.html">
        <classname>PluginJAR</classname></ulink>. jEdit then calls the
        <function>start()</function> method of the plugin core class. The
        <function>start()</function> method can perform initialization of the
        object's data members. Because this method is defined as an empty
        <quote>no-op</quote> in the <ulink
        url="../api/org/gjt/sp/jedit/EditPlugin.html">
        <classname>EditPlugin</classname></ulink> abstract class, a plugin need
        not provide an implementation if no unique initialization is
        required.</para>

    </section>

    <section id="plugin-implement-quicknotepadplugin">
        <title>The QuickNotepadPlugin Class</title>

        <para>The major issues encountered when writing a plugin core class
        arise from the developer's decisions on what features the plugin will
        make available. These issues have implications for other plugin elements
        as well.</para>

        <itemizedlist>
            <listitem>
                <para>Will the plugin provide for actions that the user can
                trigger using jEdit's menu items, toolbar buttons and keyboard
                shortcuts?</para>
            </listitem>

            <listitem>
                <para>Will the plugin have its own visible interface?</para>
            </listitem>

            <listitem>
                <para>Will the plugin have settings that the user can
                configure?</para>
            </listitem>

            <listitem>
                <para>Will the plugin respond to any messages reflecting changes
                in the host application's state?</para>
            </listitem>

            <listitem>
                <para>Should the plugin do something special when it gets
                focus?</para>
            </listitem>
        </itemizedlist>

        <para>Recall that the plugin core class must extend <ulink
        url="../api/org/gjt/sp/jedit/EditPlugin.html">
        <classname>EditPlugin</classname></ulink>. In QuickNotepad's plugin core
        class, there are no special initialization or shutdown chores to
        perform, so we will not need a <function>start()</function> or
        <function>stop()</function> method.</para>

        <para>The resulting plugin core class is lightweight and straightforward
        to implement:</para>

        <itemizedlist>
            <listitem>
                <informalexample>
                    <programlisting>public class QuickNotepadPlugin extends EditPlugin {
	public static final String NAME = "quicknotepad";
	public static final String OPTION_PREFIX = "options.quicknotepad.";
}
</programlisting>
                </informalexample>

                <para>The class has been simplified since 4.1, and all we
                defined here were a couple of <classname>String</classname> data
                members to enforce consistent syntax for the name of properties
                we will use throughout the plugin.</para>
            </listitem>

            <listitem>
                <para>These names are used in <filename>actions.xml</filename>
                for each of the menu choices. This file is discussed in more
                detail in <xref linkend="plugin-implement-actions" />. Each
                action is a beanshell script.</para>

                <informalexample>
                    <programlisting>
&lt;!DOCTYPE ACTIONS SYSTEM "actions.dtd"&gt;
&lt;ACTIONS&gt;
	&lt;ACTION NAME="quicknotepad.choose-file"&gt;
		&lt;CODE&gt;
			wm.addDockableWindow(QuickNotepadPlugin.NAME);
			wm.getDockableWindow(QuickNotepadPlugin.NAME).chooseFile();
		&lt;/CODE&gt;
	&lt;/ACTION&gt;

	&lt;ACTION NAME="quicknotepad.save-file"&gt;
		&lt;CODE&gt;
			wm.addDockableWindow(QuickNotepadPlugin.NAME);
			wm.getDockableWindow(QuickNotepadPlugin.NAME).saveFile();
		&lt;/CODE&gt;
	&lt;/ACTION&gt;

	&lt;ACTION NAME="quicknotepad.copy-to-buffer"&gt;
		&lt;CODE&gt;
			wm.addDockableWindow(QuickNotepadPlugin.NAME);
			wm.getDockableWindow(QuickNotepadPlugin.NAME).copyToBuffer();
		&lt;/CODE&gt;
	&lt;/ACTION&gt;
&lt;/ACTIONS&gt;
</programlisting>
                </informalexample>
            </listitem>

            <listitem>
                <para>The names also come up in the properties file,
                <filename>QuickNotePad.props</filename> file. The properties
                define option panes and strings used by the plugin. It is
                explained in more detail in <xref
                linkend="plugin-implement-properties" /> and the <ulink
                url="../api/org/gjt/sp/jedit/EditPlugin.html">
                <classname>EditPlugin</classname></ulink> API docs.</para>

                <informalexample>
                    <programlisting>
# jEdit only needs to load the plugin the first time the user accesses it
# the presence of this property also tells jEdit the plugin is using the new API
plugin.QuickNotepadPlugin.activate=defer

# These two properties are required for all plugins
plugin.QuickNotepadPlugin.name=QuickNotepad
plugin.QuickNotepadPlugin.author=John Gellene

# version number == jEdit version number
plugin.QuickNotepadPlugin.version=4.4

# online help
plugin.QuickNotepadPlugin.docs=index.html

# we only have one dependency, jEdit 4.4.1
plugin.QuickNotepadPlugin.depend.0=jedit 04.04.99.01

# plugin menu
plugin.QuickNotepadPlugin.menu=quicknotepad \
	- \
	quicknotepad.choose-file \
	quicknotepad.save-file \
	quicknotepad.copy-to-buffer

# action labels for actions supplied by dockables.xml
quicknotepad.label=QuickNotepad

# action labels for actions supplied by actions.xml
quicknotepad.choose-file.label=Choose notepad file
quicknotepad.save-file.label=Save notepad file
quicknotepad.copy-to-buffer.label=Copy notepad to buffer

# plugin option pane
plugin.QuickNotepadPlugin.option-pane=quicknotepad

# Option pane activation BeanShell snippet
options.quicknotepad.code=new QuickNotepadOptionPane();

# Option pane labels
options.quicknotepad.label=QuickNotepad
options.quicknotepad.file=File:
options.quicknotepad.choose-file=Choose
options.quicknotepad.choose-file.title=Choose a notepad file
options.quicknotepad.choose-font=Font:
options.quicknotepad.show-filepath.title=Display notepad file path

# window title
quicknotepad.title=QuickNotepad

# window toolbar buttons
quicknotepad.choose-file.icon=Open.png
quicknotepad.save-file.icon=Save.png
quicknotepad.copy-to-buffer.icon=CopyToBuffer.png

# default settings
options.quicknotepad.show-filepath=true
options.quicknotepad.font=Monospaced
options.quicknotepad.fontstyle=0
options.quicknotepad.fontsize=14

# Setting not defined but supplied for completeness
options.quicknotepad.filepath=
</programlisting>
                </informalexample>
            </listitem>
        </itemizedlist>
    </section>

    <section id="plugin-implement-properties">
        <title>The Property File</title>

        <para>jEdit maintains a list of <quote>properties</quote>, which are
        name/value pairs used to store human-readable strings, user settings,
        and various other forms of meta-data. During startup, jEdit loads the
        default set of properties, followed by plugin properties stored in
        plugin JAR files, finally followed by user properties.</para>

        <para>Some properties are used by the plugin API itself. Others are
        accessed by the plugin using methods in the <ulink
        url="../api/org/gjt/sp/jedit/jEdit.html">
        <classname>jEdit</classname></ulink> class. Others are accessed by the
        scripts used by plugin packagers <footnote>
                <para>See the <guimenuitem>Macros/Properties/Create Plugin
                Announcement</guimenuitem> macro for an example.</para>
            </footnote>.</para>

        <para>Property files contained in plugin JARs must end with the filename
        extension <filename>.props</filename>, and have a very simple syntax,
        which the following example illustrates:</para>

        <informalexample>
            <programlisting># Lines starting with '#' are ignored.
name=value
another.name=another value
long.property=Long property value, split over \
    several lines
escape.property=Newlines and tabs can be inserted \
    using the \t and \n escapes
backslash.property=A backslash can be inserted by writing \\.</programlisting>
        </informalexample>

        <para>Now we look at a fragment from the
        <filename>QuickNotepad.props</filename> file <footnote>
                <para>Examine the actual file for a more complete example</para>
            </footnote> which contains properties for the QuickNotepad plugin.
        The first type of property data is information about the plugin itself;
        these are the only properties that must be specified in order for the
        plugin to load:</para>

        <informalexample>
            <programlisting># general plugin information
plugin.QuickNotepadPlugin.activate=defer
plugin.QuickNotepadPlugin.name=QuickNotepad
plugin.QuickNotepadPlugin.author=John Gellene
plugin.QuickNotepadPlugin.version=4.03
plugin.QuickNotepadPlugin.docs=QuickNotepad.html
# depends on jEdit 4.4.1
plugin.QuickNotepadPlugin.depend.0=jedit 04.04.99.01
plugin.QuickNotepadPlugin.description=A demo jEdit plugin that provides a notepad dockable.
plugin.QuickNotepadPlugin.longdescription=description.html
</programlisting>
        </informalexample>

        <para>These properties are each described in detail in the documentation
        for the <ulink url="../api/org/gjt/sp/jedit/EditPlugin.html">
        <classname>EditPlugin</classname></ulink> class and do not require
        further discussion here.</para>

        <para>Next in the file comes a property that sets the title of the
        plugin's dockable window. Dockable windows are discussed in detail in
        <xref linkend="plugin-implement-dockables" />.</para>

        <informalexample>
            <programlisting># dockable window name
quicknotepad.title=QuickNotepad</programlisting>
        </informalexample>

        <para>Next, we see menu item labels for the plugin's actions. All of
        these but the first are defined in <literal>actions.xml</literal> file,
        and that is because the dockable itself has its own actions. Actions are
        discussed further in <xref linkend="plugin-implement-actions" />.</para>

        <informalexample>
            <programlisting># action labels
# Dockable label
quicknotepad.label=QuickNotepad
# Additional strings extracted from the plugin java source
quicknotepad.choose-file.label=Choose notepad file
quicknotepad.save-file.label=Save notepad file
quicknotepad.copy-to-buffer.label=Copy notepad to buffer
</programlisting>
        </informalexample>

        <para>Next, the plugin's menu is defined. See <xref
        linkend="plugin-implement-quicknotepadplugin" />.</para>

        <informalexample>
            <programlisting># application menu items
quicknotepad.menu.label=QuickNotepad
quicknotepad.menu=quicknotepad - quicknotepad.choose-file \
  quicknotepad.save-file quicknotepad.copy-to-buffer</programlisting>
        </informalexample>

        <para>We have created a small toolbar as a component of QuickNotepad, so
        file names for the button icons follow:</para>

        <informalexample>
            <programlisting># plugin toolbar buttons
quicknotepad.choose-file.icon=Open.png
quicknotepad.save-file.icon=Save.png
quicknotepad.copy-to-buffer.icon=Edit.png</programlisting>
        </informalexample>

        <para>The menu item labels corresponding to these icons will also serve
        as tooltip text.</para>

        <para>Finally, the properties file set forth the labels and settings
        used by the option pane:</para>

        <informalexample>
            <programlisting># Option pane labels
options.quicknotepad.label=QuickNotepad
options.quicknotepad.file=File:
options.quicknotepad.choose-file=Choose
options.quicknotepad.choose-file.title=Choose a notepad file
options.quicknotepad.choose-font=Font:
options.quicknotepad.show-filepath.title=Display notepad file path

# Initial default font settings
options.quicknotepad.show-filepath=true
options.quicknotepad.font=Monospaced
options.quicknotepad.fontstyle=0
options.quicknotepad.fontsize=14

# Setting not defined but supplied for completeness
options.quicknotepad.filepath=</programlisting>
        </informalexample>

        <tip>
            <title>PropertySideKick</title>

            <para>There is a SideKick for Property files, provided in the
            JavaSideKick plugin. This gives you a compact and sorted tree view
            of property files.</para>
        </tip>

    </section>

    <section id="plugin-implement-editbus">
        <title>The EditBus</title>

        <para>jEdit (and some plugins) generate several kinds of messages to
        alert plugins and other components of jedit-specific events. The message
        classes, all derived from <ulink
        url="../api/org/gjt/sp/jedit/EBMessage.html">
        <classname>EBMessage</classname></ulink> cover the opening and closing
        of the application, changes in the status of buffers and views, changes
        in user settings, as well as changes in the state of other program
        features. A full list of messages can be found in the <ulink
        url="../api/org/gjt/sp/jedit/msg/package-summary.html">org.gjt.sp.jedit.msg</ulink>
        package.</para>



        <para>For example, the ViewUpdate messages are all related to the jEdit
        View, or the top-level window. If the user creates multiple Views, a
        plugin may need to know when they are created or destroyed, so it would
        monitor ViewUpdate messages.</para>

        <para>BufferUpdate messages are all related to jEdit buffers. They let
        plugins know when a buffer has become dirty, when it is about to be
        closed, after it is closed, created, loaded, or saved. Each of these
        messages are described in further detail in the API docs.</para>

        <para>As another example, The Navigator plugin monitors a newly added
        (to jEdit 4.3) EBMessage of the kind <ulink
        url="../api/org/gjt/sp/jedit/BufferChanging.html">BufferChanging</ulink>.
        The BufferChanging event provides Navigator enough advance notice to
        save the TextArea's caret just before the current EditPane changes its
        active Buffer. The <literal>BufferChanged</literal> event, another
        <literal>EditPaneUpdate</literal> message, is thrown shortly afterward.
        This is not used by Navigator, but it is used by SideKick to determine
        when it is time to reparse the buffer.</para>

        <para>Plugins register <ulink
        url="../api/org/gjt/sp/jedit/EBComponent.html">
        <function>EBComponent</function></ulink> instances with the <ulink
        url="../api/org/gjt/sp/jedit/EditBus.html">
        <classname>EditBus</classname></ulink> to receive messages reflecting
        changes in jEdit's state.</para>

        <para><ulink url="../api/org/gjt/sp/jedit/EBComponent.html">
        <function>EBComponent</function></ulink>s are added and removed with the
        <ulink
        url="../api/org/gjt/sp/jedit/EditBus.html#addToBus(org.gjt.sp.jedit.EBComponent)">
        <function>EditBus.addToBus()</function></ulink> and <ulink
        url="../api/org/gjt/sp/jedit/EditBus.html#removeFromBus(org.gjt.sp.jedit.EBComponent)">
        <function>EditBus.removeFromBus()</function></ulink> methods.</para>

        <para>Typically, the <ulink
        url="../api/org/gjt/sp/jedit/EBComponent.html#handleMessage(org.gjt.sp.jedit.EBMessage)">
        <function>EBComponent.handleMessage()</function></ulink> method is
        implemented with one or more <function>if</function> blocks that test
        whether the message is an instance of a derived message class in which
        the component has an interest.</para>

        <programlisting>if(msg instanceof BufferUpdate) {
    // a buffer's state has changed!
}
else if(msg instanceof ViewUpdate) {
    // a view's state has changed!
}
// ... and so on</programlisting>

        <para>If a plugin core class will respond to EditBus messages, it can be
        derived from <ulink url="../api/org/gjt/sp/jedit/EBPlugin.html">
        <classname>EBPlugin</classname></ulink>, in which case no explicit
        <function>addToBus()</function> call is necessary. Otherwise, <ulink
        url="../api/org/gjt/sp/jedit/EditPlugin.html">
        <classname>EditPlugin</classname></ulink> will suffice as a plugin base
        class. Note that QuickNotepad uses the latter.</para>

        <tip>
        <title>Using the Activity Log to see the EditBus</title>

        <para> To determine precisely which EditBus messages are being sent by
        jEdit or the plugins, start up jEdit with an additional argument,
        <literal>-log=5</literal>. You can set an even lower log level to see
        further details (the default is 7). With a log level of 5 or lower, the
        Activity Log will include [notice]s, which will show us exactly which
        EditBus message is sent and when. See <xref linkend="activity-log" />
        for more details. </para> </tip>

    </section>

    <section id="plugin-implement-actions">
        <title>The Actions Catalog</title>

        <para>Actions define procedures that can be bound to a menu item, a
        toolbar button or a keyboard shortcut. Most plugin Actions <footnote>
                <para>Some plugins, such as Sidekick, Console, and
                ProjectViewer, create pure Java EditAction-derived Actions,
                based which services are available, or which files are found in
                a certain path. However, this is an advanced topic you can
                explore further in the source and API docs of those
                plugins.</para>
            </footnote> are short scripts written in BeanShell, jEdit's macro
        scripting language. These scripts either direct the action themselves,
        delegate to a method in one of the plugin's classes that encapsulates
        the action, or do a little of both. The scripts are usually short;
        elaborate action protocols are usually contained in compiled code,
        rather than an interpreted macro script, to speed execution.</para>

        <para>Actions are defined by creating an XML file entitled
        <filename>actions.xml</filename> and placing it in the plugin JAR
        file.</para>

        <para>The <filename>actions.xml</filename> file from the
        <application>QuickNotepad</application> plugin looks as follows:</para>

        <informalexample>
            <programlisting>&lt;ACTIONS&gt;
	&lt;ACTION NAME="quicknotepad.choose-file"&gt;
		&lt;CODE&gt;
			wm.addDockableWindow(QuickNotepadPlugin.NAME);
			wm.getDockableWindow(QuickNotepadPlugin.NAME).chooseFile();
		&lt;/CODE&gt;
	&lt;/ACTION&gt;

	&lt;ACTION NAME="quicknotepad.save-file"&gt;
		&lt;CODE&gt;
			wm.addDockableWindow(QuickNotepadPlugin.NAME);
			wm.getDockableWindow(QuickNotepadPlugin.NAME).saveFile();
		&lt;/CODE&gt;
	&lt;/ACTION&gt;

	&lt;ACTION NAME="quicknotepad.copy-to-buffer"&gt;
		&lt;CODE&gt;
			wm.addDockableWindow(QuickNotepadPlugin.NAME);
			wm.getDockableWindow(QuickNotepadPlugin.NAME).copyToBuffer();
		&lt;/CODE&gt;
	&lt;/ACTION&gt;
&lt;/ACTIONS&gt;</programlisting>
        </informalexample>

        <para>This file defines three actions. They each use a built-in variable
        <literal>wm</literal>, which refers to the current view's <ulink
        url="../api/org/gjt/sp/jedit/gui/DockableWindowManager.html">
        <classname>DockableWindowManager</classname></ulink>. Whenever you need
        to obtain a reference to the current dockable, or create a new one, this
        is the class to use. We use the method <filename>addDockable() followed
        by getDockable()</filename> to create if necessary, and then bring up
        the QuickNotepad plugin dockable. This will be docked or floating,
        depending on how it was last used.</para>

        <para>When an action is invoked, the BeanShell scripts address the
        plugin through static methods, or if instance data is needed, the
        current <ulink url="../api/org/gjt/sp/jedit/View.html">
        <classname>View</classname></ulink>, its <ulink
        url="../api/org/gjt/sp/jedit/gui/DockableWindowManager.html">
        <classname>DockableWindowManager</classname></ulink>, and the plugin
        object return by the <filename>getDockable()</filename> method.</para>

        <para>If you are unfamiliar with BeanShell code, you may nevertheless
        notice that the code statements bear a strong resemblance to Java code,
        with one exception: the variable <varname>view</varname> is never
        assigned any value.</para>

        <para>For complete answers to this and other BeanShell mysteries, see
        <xref linkend="writing-macros-part" />; two observations will suffice
        here. First, the variable <varname>view</varname> is predefined by
        jEdit's implementation of BeanShell to refer to the current
        <classname>View</classname> object. Second, the BeanShell scripting
        language is based upon Java syntax, but allows variables to be typed at
        run time, so explicit types for variables need not be declared.</para>

        <para>A formal description of each element of the
        <filename>actions.xml</filename> file can be found in the documentation
        of the <ulink url="../api/org/gjt/sp/jedit/ActionSet.html">
        <classname>ActionSet</classname></ulink> class.</para>
    </section>

    <section id="plugin-implement-dockables">
        <title>The dockables.xml Window Catalog</title>

        <para>A Dockable is a window that can float like a dialog, or dock into
        jEdit's docking area. Each dockable needs a label (for display in menus,
        and on small buttons) and a title (for display in the floating window's
        title bar).</para>

        <para>The jEdit plugin API uses BeanShell to create the top-level
        visible container of a plugin's interface. The BeanShell code is
        contained in a file named <filename>dockables.xml</filename>. It usually
        is quite short, providing only a single BeanShell expression used to
        create a visible plugin window.</para>

        <para>The following example from the QuickNotepad plugin illustrates the
        requirements of the data file:</para>

        <informalexample>
            <programlisting>&lt;?xml version="1.0"?&gt;

&lt;!DOCTYPE DOCKABLES SYSTEM "dockables.dtd"&gt;

&lt;DOCKABLES&gt;
	&lt;DOCKABLE NAME="quicknotepad"&gt;
		new QuickNotepad(view, position);
	&lt;/DOCKABLE&gt;
&lt;/DOCKABLES&gt;</programlisting>
        </informalexample>

        <para>In this example, the <classname>&lt;DOCKABLE&gt;</classname>
        element has a single attribute, the dockable window's identifier. This
        attribute is used to key a property where the window title is stored;
        see <xref linkend="plugin-implement-properties" />.</para>

        <para>For each dockable, jedit defines an action with the same name.
        This means you do not need to define an explicit action to create your
        dockable - in fact, jEdit defines three actions: "toggle", "get" and
        "new floating instance" for each.</para>

        <para>The contents of the <classname>&lt;DOCKABLE&gt;</classname>
        element itself is a BeanShell expression that constructs a new
        <classname>QuickNotepad</classname> object. The <varname>view</varname>
        and <varname>position</varname> are predefined by the plugin API as the
        view in which the plugin window will reside, and the docking position of
        the plugin. You can use <varname>position</varname> to customize the
        layout of your plugin depending on whether it appears on the sides, or
        the top/bottom, or as a floating dockable.</para>

        <para>A formal description of each element of the
        <filename>dockables.xml</filename> file can be found in the
        documentation of the <ulink
        url="../api/org/gjt/sp/jedit/gui/DockableWindowManager.html">
        <classname>DockableWindowManager</classname></ulink> class. This class
        also contains the public interface you should use for getting, showing,
        hiding, and other interactions with the plugin's top-level
        windows.</para>
    </section>

    <section id="plugin-implement-services">
        <title>The services.xml file</title>

        <para>A "service" is a mechanism by which one plugin can work with other
        plugins and avoid a bidirectional build-dependency. For example, the XML
        plugin "depends" on Sidekick, but in fact, it is SideKick which creates
        and operates on an object (a <literal>SideKickParser</literal>, in fact)
        defined in the XML plugin. In a way, the dependency is
        bidirectional.</para>

        <para>Similarly, the AntFarm plugin defines but does not instantiate a
        <literal>Shell</literal> object. It is the Console plugin which creates
        a specific shell for each available service. SideKick and Console use
        the ServiceManager to search for services offered by other
        plugins.</para>

        <para>Here is an example of a service from the XML plugin, which extends
        Sidekick:</para>

        <informalexample>
            <programlisting>
&lt;!DOCTYPE SERVICES SYSTEM "services.dtd"&gt;

&lt;SERVICES&gt;
        &lt;SERVICE CLASS="sidekick.SideKickParser" NAME="xml"&gt;
                new xml.parser.SAXParserImpl();
        &lt;/SERVICE&gt;
&lt;/SERVICES&gt;
</programlisting>
        </informalexample>

        <para>The object it returns tells Sidekick how it can parse files of a
        specific type. The API docs for SideKickParser indicate exactly which
        methods must be implemented in a plugin which offers this service. It
        should be enough information to let Sidekick, which has its own
        dockable, display the tree information in its own view.</para>

        <para>For more information about services, refer to the <ulink
        url="../api/org/gjt/sp/jedit/ServiceManager.html">ServiceManager</ulink>
        class API documentation. There, you can find out what the tags and
        attributes mean, as well as how to register and use services.</para>
    </section>

    <section id="plugin-implement-quicknotepad">
        <title>The QuickNotepad Class</title>

        <para>Here is where most of the features of the plugin will be
        implemented. To work with the dockable window API, the top level window
        will be a <classname>JPanel</classname>. The visible components reflect
        a simple layout. Inside the top-level panel we will place a scroll pane
        with a text area. Above the scroll pane we will place a panel containing
        a small tool bar and a label displaying the path of the current notepad
        file.</para>

        <para>We have identified three user actions that need implementation
        here: <function>chooseFile()</function>,
        <function>saveFile()</function>, and
        <function>copyToBuffer()</function>. As noted earlier, we also want the
        text area to change its appearance in immediate response to a change in
        user options settings. In order to do that, the window class must
        respond to a <classname>PropertiesChanged</classname> message from the
        EditBus.</para>

        <!-- <para>
  We could have the plugin core class receive and delegate
  <classname>PropertiesChanged</classname> messages to the window class.
  However, this would require the plugin core class to hold a reference
  to either the plugin window class or the visible window class and to
  update that reference when the user activates or deactivates the
  plugin.  It is simpler to have the plugin window class subscribe to the
  EditBus directly; many plugins take this approach.  This means that
  <classname>QuickNotepad</classname> must implement the
  <classname>EBComponent</classname> interface.
</para> -->

        <para>Unlike the <classname>EBPlugin</classname> class, the
        <classname>EBComponent</classname> interface does not deal with the
        component's actual subscribing and unsubscribing to the EditBus. To
        accomplish this, we use a pair of methods inherited from the Java
        platform's <classname>JComponent</classname> class that are called when
        the window is made visible, and when it is hidden. These two methods,
        <function>addNotify()</function> and
        <function>removeNotify()</function>, are overridden to add and remove
        the visible window from the list of EditBus subscribers.</para>

        <para>We will provide for two minor features when the notepad is
        displayed in the floating window. First, when a floating plugin window
        is created, we will give the notepad text area input focus. Second, when
        the notepad if floating and has input focus, we will have the
        <keycap>Escape</keycap> key dismiss the notepad window. An
        <classname>AncestorListener</classname> and a
        <classname>KeyListener</classname> will implement these details.</para>

        <para>Here is the listing for the data members, the constructor, and the
        implementation of the <classname>EBComponent</classname>
        interface:</para>

        <informalexample>
            <programlisting>public class QuickNotepad extends JPanel
    implements EBComponent
{
    private String filename;
    private String defaultFilename;
    private View view;
    private boolean floating;

    private QuickNotepadTextArea textArea;
    private QuickNotepadToolPanel toolPanel;

    //
    // Constructor
    //

    public QuickNotepad(View view, String position)
    {
        super(new BorderLayout());

        this.view = view;
        this.floating = position.equals(
            DockableWindowManager.FLOATING);

        this.filename = jEdit.getProperty(
            QuickNotepadPlugin.OPTION_PREFIX
            + "filepath");
        if(this.filename == null || this.filename.length() == 0)
        {
            this.filename = new String(jEdit.getSettingsDirectory()
                + File.separator + "qn.txt");
            jEdit.setProperty(QuickNotepadPlugin.OPTION_PREFIX
                + "filepath",this.filename);
        }
        this.defaultFilename = new String(this.filename);

        this.toolPanel = new QuickNotepadToolPanel(this);
        add(BorderLayout.NORTH, this.toolPanel);

        if(floating)
            this.setPreferredSize(new Dimension(500, 250));

        textArea = new QuickNotepadTextArea();
        textArea.setFont(QuickNotepadOptionPane.makeFont());
        textArea.addKeyListener(new KeyHandler());
        textArea.addAncestorListener(new AncestorHandler());
        JScrollPane pane = new JScrollPane(textArea);
        add(BorderLayout.CENTER, pane);

        readFile();
    }

    //
    // Attribute methods
    //

    // for toolBar display
    public String getFilename()
    {
        return filename;
    }

    //
    // EBComponent implementation
    //

    public void handleMessage(EBMessage message)
    {
        if (message instanceof PropertiesChanged)
        {
            propertiesChanged();
        }
    }


    private void propertiesChanged()
    {
        String propertyFilename = jEdit.getProperty(
            QuickNotepadPlugin.OPTION_PREFIX + "filepath");
        if(!defaultFilename.equals(propertyFilename))
        {
            saveFile();
            toolPanel.propertiesChanged();
            defaultFilename = propertyFilename.clone();
            filename = defaultFilename.clone();
            readFile();
        }
        Font newFont = QuickNotepadOptionPane.makeFont();
        if(!newFont.equals(textArea.getFont()))
        {
            textArea.setFont(newFont);
            textArea.invalidate();
        }
    }

    // These JComponent methods provide the appropriate points
    // to subscribe and unsubscribe this object to the EditBus

    public void addNotify()
    {
        super.addNotify();
        EditBus.addToBus(this);
    }


    public void removeNotify()
    {
        saveFile();
        super.removeNotify();
        EditBus.removeFromBus(this);
    }

    ...

}</programlisting>
        </informalexample>

        <para>This listing refers to a
        <classname>QuickNotebookTextArea</classname> object. It is currently
        implemented as a <classname>JTextArea</classname> with word wrap and tab
        sizes hard-coded. Placing the object in a separate class will simply
        future modifications.</para>
    </section>

    <section id="plugin-implement-quicknotepadtoolbar">
        <title>The QuickNotepadToolBar Class</title>

        <para>There is nothing remarkable about the toolbar panel that is placed
        inside the <classname>QuickNotepad</classname> object. The constructor
        shows the continued use of items from the plugin's properties
        file.</para>

        <informalexample>
            <programlisting>public class QuickNotepadToolPanel extends JPanel
{
    private QuickNotepad pad;
    private JLabel label;

    public QuickNotepadToolPanel(QuickNotepad qnpad)
    {
        pad = qnpad;
        JToolBar toolBar = new JToolBar();
        toolBar.setFloatable(false);

        toolBar.add(makeCustomButton("quicknotepad.choose-file",
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    QuickNotepadToolPanel.this.pad.chooseFile();
                }
            }));
        toolBar.add(makeCustomButton("quicknotepad.save-file",
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    QuickNotepadToolPanel.this.pad.saveFile();
                }
            }));
        toolBar.add(makeCustomButton("quicknotepad.copy-to-buffer",
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    QuickNotepadToolPanel.this.pad.copyToBuffer();
                }
            }));
        label = new JLabel(pad.getFilename(),
            SwingConstants.RIGHT);
        label.setForeground(Color.black);
        label.setVisible(jEdit.getProperty(
            QuickNotepadPlugin.OPTION_PREFIX
            + "show-filepath").equals("true"));
        this.setLayout(new BorderLayout(10, 0));
        this.add(BorderLayout.WEST, toolBar);
        this.add(BorderLayout.CENTER, label);
        this.setBorder(BorderFactory.createEmptyBorder(0, 0, 3, 10));
    }

    ...

}</programlisting>
        </informalexample>

        <para>The method <classname>makeCustomButton()</classname> provides
        uniform attributes for the three toolbar buttons corresponding to three
        of the plugin's use actions. The menu titles for the user actions serve
        double duty as tooltip text for the buttons. There is also a
        <function>propertiesChanged()</function> method for the toolbar that
        sets the text and visibility of the label containing the notepad file
        path.</para>
    </section>

    <section id="plugin-implement-options">
        <title>The QuickNotepadOptionPane Class</title>

        <para>Using the default implementation provided by
        <classname>AbstractOptionPane</classname> reduces the preparation of an
        option pane to two principal tasks: writing a
        <function>_init()</function> method to layout and initialize the pane,
        and writing a <function>_save()</function> method to commit any settings
        changed by user input. If a button on the option pane should trigger
        another dialog, such as a <classname>JFileChooser</classname> or jEdit's
        own enhanced <classname>VFSFileChooserDialog</classname>, the option
        pane will also have to implement the
        <classname>ActionListener</classname> interface to display additional
        components.</para>

        <para>The QuickNotepad plugin has only three options to set: the path
        name of the file that will store the notepad text, the visibility of the
        path name on the tool bar, and the notepad's display font. Using the
        shortcut methods of the plugin API, the implementation of
        <function>_init()</function> looks like this:</para>

        <informalexample>
            <programlisting>public class QuickNotepadOptionPane extends AbstractOptionPane
      implements ActionListener
{
    private JTextField pathName;
    private JButton pickPath;
    private FontSelector font;

    ...

    public void _init()
    {
        showPath = new JCheckBox(jEdit.getProperty(
            QuickNotepadPlugin.OPTION_PREFIX
            + "show-filepath.title"),
        jEdit.getProperty(
            QuickNotepadPlugin.OPTION_PREFIX +  "show-filepath")
            .equals("true"));
        addComponent(showPath);

        pathName = new JTextField(jEdit.getProperty(
            QuickNotepadPlugin.OPTION_PREFIX
            + "filepath"));
        JButton pickPath = new JButton(jEdit.getProperty(
            QuickNotepadPlugin.OPTION_PREFIX
            + "choose-file"));
        pickPath.addActionListener(this);

        JPanel pathPanel = new JPanel(new BorderLayout(0, 0));
        pathPanel.add(pathName, BorderLayout.CENTER);
        pathPanel.add(pickPath, BorderLayout.EAST);

        addComponent(jEdit.getProperty(
            QuickNotepadPlugin.OPTION_PREFIX + "file"),
            pathPanel);

        font = new FontSelector(makeFont());
        addComponent(jEdit.getProperty(
            QuickNotepadPlugin.OPTION_PREFIX + "choose-font"),
            font);
    }

    ...

}</programlisting>
        </informalexample>

        <para>Here we adopt the vertical arrangement offered by use of the
        <function>addComponent()</function> method with one embellishment. We
        want the first <quote>row</quote> of the option pane to contain a text
        field with the current notepad file path and a button that will trigger
        a file chooser dialog when pressed. To place both of them on the same
        line (along with an identifying label for the file option), we create a
        <classname>JPanel</classname> to contain both components and pass the
        configured panel to <function>addComponent()</function>.</para>

        <para>The <function>_init()</function> method uses properties from the
        plugin's property file to provide the names of label for the components
        placed in the option pane. It also uses a property whose name begins
        with <function>PROPERTY_PREFIX</function> as a persistent data item -
        the path of the current notepad file. The elements of the notepad's font
        are also extracted from properties using a static method of the option
        pane class.</para>

        <para>The <function>_save()</function> method extracts data from the
        user input components and assigns them to the plugin's properties. The
        implementation is straightforward:</para>

        <informalexample>
            <programlisting>public void _save()
{
    jEdit.setProperty(QuickNotepadPlugin.OPTION_PREFIX
        + "filepath", pathName.getText());
    Font _font = font.getFont();

    jEdit.setProperty(QuickNotepadPlugin.OPTION_PREFIX
        + "font", _font.getFamily());
    jEdit.setProperty(QuickNotepadPlugin.OPTION_PREFIX
        + "fontsize", String.valueOf(_font.getSize()));
    jEdit.setProperty(QuickNotepadPlugin.OPTION_PREFIX
        + "fontstyle", String.valueOf(_font.getStyle()));
    jEdit.setProperty(QuickNotepadPlugin.OPTION_PREFIX
        + "show-filepath", String.valueOf(showPath.isSelected()));
}</programlisting>
        </informalexample>

        <para>The class has only two other methods, one to display a file
        chooser dialog in response to user action, and the other to construct a
        <classname>Font</classname> object from the plugin's font properties.
        They do not require discussion here.</para>
    </section>

    <section id="plugin-implement-docs">
        <title>Plugin Documentation</title>

        <para>While not required by the plugin API, a help file is an essential
        element of any plugin written for public release. A single web page is
        often all that is required. There are no specific requirements on
        layout, but because of the design of jEdit's help viewer, the use of
        frames should be avoided. Topics that would be useful include the
        following:</para>

        <itemizedlist>
            <listitem>
                <para>a description of the purpose of the plugin;</para>
            </listitem>

            <listitem>
                <para>an explanation of the type of input the user can supply
                through its visible interface (such as mouse action or text
                entry in controls);</para>
            </listitem>

            <listitem>
                <para>a listing of available user actions that can be taken when
                the plugin does not have input focus;</para>
            </listitem>

            <listitem>
                <para>a summary of configuration options;</para>
            </listitem>

            <listitem>
                <para>information on development of the plugin (such as a change
                log, a list of <quote>to do</quote> items, and contact
                information for the plugin's author); and</para>
            </listitem>

            <listitem>
                <para>licensing information, including acknowledgments for any
                library software used by the plugin.</para>
            </listitem>
        </itemizedlist>

        <para>The location of the plugin's help file is stored in the
        <literal>plugin.QuickNotepad.docs</literal> property; see <xref
        linkend="plugin-implement-properties" />.</para>
    </section>

    <section id="plugin-implement-building">
        <title>The build.xml Ant build file</title>

        <para>We have already outlined the contents of the user action catalog,
        the properties file and the documentation file in our earlier
        discussion. The final step is to compile the source file and build the
        archive file that will hold the class files and the plugin's other
        resources.</para>

        <para>Publicly released plugins include with their source a makefile in
        XML format for the <application>Ant</application> utility. The format
        for this file requires few changes from plugin to plugin. Here is a
        version of <filename>build.xml</filename> that could be used by
        QuickNotepad:</para>

        <informalexample>
            <programlisting>
&lt;project name="QuickNotepad"
         default="build"&gt;
    &lt;description&gt;
        This is an ant build.xml file for building the QuickNotepad plugin for jEdit.
    &lt;/description&gt;
    &lt;property name=&quot;user-doc.xml&quot;
          value=&quot;users-guide.xml&quot; /&gt;
    &lt;property file=&quot;build.properties&quot; /&gt;
    &lt;property file=&quot;../build.properties&quot; /&gt;
	&lt;property name=&quot;build.support&quot;
			  value=&quot;../../../build-support&quot; /&gt;
    &lt;import file="${build.support}/plugin-build.xml" /&gt;
&lt;/project&gt;
</programlisting>
        </informalexample>

        <para>This build file imports another modular build file,
        <literal>plugin-build.xml</literal> from the <literal>build-support</literal>
        project. It is available as a package you can check out from subversion, or found online in the <ulink
        url="https://jedit.svn.sourceforge.net/svnroot/jedit/build-support/trunk/">jEdit's
        SVN repository</ulink>. It contains the common build steps used to build the core jEdit plugins, and some example <literal>build.properties.sample</literal> files which you can adapt for use with your development environment.</para>


        <para>Customizing this build file for a different plugin will likely
        only require three changes to build.xml file:</para>

        <itemizedlist>
            <listitem>
                <para>the name of the project</para>
            </listitem>

            <listitem>
                <para>the dependencies of the plugin</para>
            </listitem>

            <listitem>
                <para>The extra files that need to be copied into the
                jar.</para>
            </listitem>
        </itemizedlist>

        <para>Because this build file and the one of most plugins import a
        <literal>build.properties</literal> file from the current and the parent
        directories, it is possible to build most of jEdit's plugins in a
        uniform way by setting the common properties in a single
        <literal>build.properties</literal> file, placed in the plugin source's
        parent directory. </para>

        <tip> <para>For a full discussion of the <filename>Ant</filename> file
        format and command syntax, you should consult the <ulink
        url="http://jakarta.apache.org/ant/manual/index.html">Ant
        documentation</ulink>, also available through jEdit's help system if you
        installed the Ant Plugin. When editing Ant build files, the XML plugin
        gives you completion tips for both elements <emphasis>and</emphasis>
        attributes. The Console plugin provides you with an ANT button which you
        can bind to keyboard actions. In addition, there are the AntFarm and
        Antelope plugins which also proivde you with alternate means to execute
        Ant targets through the Console.</para> </tip> </section>

    <section id="plugin-implement-reloading">
        <title>Reloading the Plugin</title>

        <para>Once you have compiled your plugin, you will need to test its
        behavior when it is reloaded. Follow these steps to reload your plugin
        without restarting jEdit:</para>

        <itemizedlist>
            <listitem>
                <para>From the Plugins menu open the Plugin Manager.</para>
            </listitem>

            <listitem>
                <para>On the Manage tab uncheck Hide libraries. This will allow
                you to see plugins that are not loaded.</para>
            </listitem>

            <listitem>
                <para>Recheck the plugin to reload it.</para>
            </listitem>
        </itemizedlist>

        <tip>
            <para>The Activator plugin provides a very convenient (dockable) way
            to test the activating and reloading behavior of your plugin. Be
            sure to test your plugin's reloading behavior with both the
            Activator and the Reloader tabs.</para>
        </tip>

        <para>If you have reached this point in the text, you are probably
        serious about writing a plugin for jEdit. Good luck with your efforts,
        and thank you for contributing to the jEdit project.</para>
    </section>

    <section id="plugin-debugging" >
    <title> Tips for debugging plugins </title>
      <bridgehead> BeanShell </bridgehead>
      <para> jEdit includes a Beanshell interface into its currently running JVM at all times. You can access it a variety of ways, but one way is from <literal>Plugins - Console - Shells - BeanShell</literal>. From here, you can interactively inspect the values of any object in memory, call any of its member functions, or create new instances of any class that is currently loaded by jEdit or any of its plugins. All this, without setting any breakpoints!
      </para>
      <para> If you're too lazy to type each Beanshell statement interactively, you can also create debugging code snippets as macros and invoke them from <literal>utilities - beanshell - evaluate selection</literal>, or <literal>Macros - Misc - Evaluate Buffer in Beanshell</literal>, or place the file in your own macros directory and bind it to its own keyboard shortcut. </para>
      <bridgehead> Other useful tips </bridgehead>
      <para> This section is new but will be expanded shortly. Please post suggestions to the <literal>jedit-devel</literal> mailing list. </para>
      </section>

</chapter>