1/*
2 * Display_abbreviations.bsh - a BeanShell macro script for the
3 * jEdit text editor - displays all defined abbreviations
4 * Copyright (C) 2001 John Gellene
5 * email: jgellene@nyc.rr.com
6 * http://community.jedit.org
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 *
22 * $Id: Display_Abbreviations.bsh 23920 2015-05-22 08:03:45Z ezust $
23 *
24 * requires JDK 1.2, jEdit3.0
25 *
26 * Notes on use:
27 *
28 * This macro will display a sorted list of all defined abbreviations
29 * in a dialog.  A combo box lists all eidting modes for which abbreviations
30 * are currently defined, as well as the "global" abbreviation set.
31 *
32 * Pressing a letter key will cause the table to scroll to the first row
33 * with a label beginning with the letter (or the imeediately preceding row if
34 * no item begins with that letter).  The table is read-only; the dialog is
35 * dismissed by clicking "OK" or pressing Esc or Enter.
36 *
37 * The macro has two global constants defined to permit customization of the
38 * script's behavior.  STARTING_SET contains the name of the abbreviation set
39 * that will be first displayed.  If the other variable, EXCLUDE_EMPTY_SETS,
40 * is set to true, the drop-down menu and the results of clicking the
41 * "Write All" button will only include abbreviations sets containing
42 * entries.
43 *
44 * The table being displayed at any time is not updated if changes are made to
45 * the abbreviation set in the "Global Options" dialog.  If EXCLUDE_EMPTY_SETS
46 * is set to true, the drop-down list will not by updated.  Clsoing the dialog
47 * and running the macro again will obtain current data.
48 *
49 *
50 * Checked for jEdit 4.0 API
51 *
52 */
53
54import javax.swing.table.*;
55
56//Localization
57final static String AbbreviationLabel = jEdit.getProperty("macro.rs.DisplayAbbreviations.Abbreviation.label", "Abbreviation");
58final static String ExpansionLabel = jEdit.getProperty("macro.rs.DisplayAbbreviations.Expansion.label", "Expansion");
59final static String AbbreviationSetLabel = jEdit.getProperty("macro.rs.DisplayAbbreviations.AbbreviationSet.label", "Abbreviation set:");
60final static String CloseLabel = jEdit.getProperty("macro.rs.DisplayAbbreviations.Close.label", "Close");
61final static String WriteSetLabel = jEdit.getProperty("macro.rs.DisplayAbbreviations.WriteSet.label", "Write set");
62final static String WriteAllLabel = jEdit.getProperty("macro.rs.DisplayAbbreviations.WriteAll.label", "Write all");
63final static String AbbreviationListLabel = jEdit.getProperty("macro.rs.DisplayAbbreviations.AbbreviationList.label", "Abbreviation list");
64final static String CallingWTTNBLabel = jEdit.getProperty("macro.rs.DisplayAbbreviations.CallingWTTNB.label", "calling writeTableToNewBuffer for");
65final static String SizeVectorLabel = jEdit.getProperty("macro.rs.DisplayAbbreviations.SizeVector.label", "size of vector =");
66final static String jEditAbbreviationTableLabel = jEdit.getProperty("macro.rs.DisplayAbbreviations.jEditAbbreviationTable.label", "jEdit Abbreviation Table");
67final static String AbbreviationExpansionLabel = jEdit.getProperty("macro.rs.DisplayAbbreviations.AbbreviationExpansion.label", "Abbreviation    Expansion");
68final static String NoAbbreviationsLabel = jEdit.getProperty("macro.rs.DisplayAbbreviations.NoAbbreviations.label", "<< No abbreviations >>");
69
70/*
71 * getActiveSets()
72 * This returns an array with the names of the abbreviation sets
73 * (beginning with "global").  If EXCLUDE_EMPTY_SETS is set to true, only sets
74 * with abbreviations are included.
75 */
76Object[] getActiveSets()
77{
78	Mode[] modes = jEdit.getModes();
79	Vector setVector = new Vector(modes.length + 1);
80	setVector.addElement("global");
81	for(int i = 0; i < modes.length; i++)
82	{
83		String name = modes[i].getName();
84		if(EXCLUDE_EMPTY_SETS)
85		{
86			Hashtable ht = Abbrevs.getModeAbbrevs().get(name);
87			if( ht == null || ht.isEmpty())
88				continue;
89		}
90		setVector.addElement(name);
91	}
92	Object[] sets = new Object[setVector.size()];
93	setVector.copyInto(sets);
94	return sets;
95}
96
97/*
98 * makeTableDataForMode()
99 * This extracts the abbreviations from the named set.  If extraction is
100 * successful, the vector named by the first parameter will have its
101 * elements removed before the variable is set to the newly created vector.
102 */
103Vector makeTableDataForMode(Vector v, String name)
104{
105	if(name.equals(currentSet))
106		return v;
107	Hashtable htable = null;
108	if(name.equals("global"))
109	{
110		htable = Abbrevs.getGlobalAbbrevs();
111	}
112	else
113	{
114		Hashtable modeAbbrevs = Abbrevs.getModeAbbrevs();
115		htable = modeAbbrevs.get(name);
116	}
117	if(htable != null)
118	{
119		Enumeration abbrevEnum = htable.keys();
120		Enumeration expandEnum = htable.elements();
121		Vector newData = new Vector(20, 5);
122		while(abbrevEnum.hasMoreElements())
123		{
124			Vector row = new Vector(2);
125			row.addElement(abbrevEnum.nextElement());
126			row.addElement(expandEnum.nextElement());
127			newData.addElement(row);
128		}
129		Collections.sort(newData,
130			new StandardUtilities.StringCompare(true));
131		currentSet = name;
132		if( v != null)
133			v.removeAllElements();
134		v = newData;
135	}
136	return v;
137}
138
139/*
140 * showAbbrevs()
141 * This is the macro's principal method.
142 */
143void showAbbrevs()
144{
145	currentSet = null;
146	data = makeTableDataForMode(data, STARTING_SET);
147	if(data.size() == 0)
148	{
149		STARTING_SET = "global";
150		data = makeTableDataForMode(data, STARTING_SET);
151	}
152	Vector columnNames = new Vector(2);
153	columnNames.addElement(new String(AbbreviationLabel));
154	columnNames.addElement(new String(ExpansionLabel));
155	table = new JTable();
156	table.setRowHeight(GUIUtilities.defaultRowHeight());
157	table.setModel(new DefaultTableModel(data, columnNames));
158	table.setRowSelectionAllowed(true);
159	/* 	The next line prevents the table from being edited.
160	 * 	The normal approach in Java would be to subclass the TableModel
161	 * 	associated with the JTable and define TableModel.isCellEditable()
162	 * 	to return false.  However, BeanShell does not allow conventional
163	 *  class creation, and the desired behavior cannot be achieved using
164	 *  its scripted object feature.
165	 */
166	table.setDefaultEditor(Object.class, null);
167	if(table.getRowCount() != 0)
168		table.setRowSelectionInterval(0,0);
169	tablePane = new JScrollPane(table);
170	tablePane.setPreferredSize(new Dimension(450, 300));
171
172	combo = new JComboBox(abbrevSets);
173	Dimension dim = combo.getPreferredSize();
174	dim.width = Math.max(dim.width, 120);
175	combo.setPreferredSize(dim);
176	combo.setSelectedItem(STARTING_SET);
177	comboPanel = new JPanel(new FlowLayout());
178	comboPanel.add(new JLabel(AbbreviationSetLabel));
179	comboPanel.add(combo);
180
181	close = new JButton(CloseLabel);
182	write_set = new JButton(WriteSetLabel);
183	write_all = new JButton(WriteAllLabel);
184	buttonPanel = new JPanel(new FlowLayout());
185	buttonPanel.add(write_set);
186	buttonPanel.add(write_all);
187	buttonPanel.add(close);
188
189	close.addActionListener(this);
190	write_set.addActionListener(this);
191	write_all.addActionListener(this);
192	combo.addActionListener(this);
193	void actionPerformed(e)
194	{
195		Component source = e.getSource();
196		if(source == close)
197			dialog.hide();
198		else if(source == write_set)
199			writeTableToNewBuffer(super.data, (String)combo.getSelectedItem());
200		else if(source == write_all)
201			writeAllToNewBuffer();
202		else if(source == combo)
203		{
204			super.data = makeTableDataForMode(super.data, (String)combo.getSelectedItem());
205			if( data != null)
206			{
207				DefaultTableModel model = (DefaultTableModel)table.getModel();
208				model.setDataVector(super.data, columnNames);
209			}
210		}
211	}
212
213	// workaround required by Swing bug; scheduled to be fixed in JDK 1.4
214	combo.getComponent(0).addKeyListener(this);
215	table.addKeyListener(this);
216	write_set.addKeyListener(this);
217	write_all.addKeyListener(this);
218	close.addKeyListener(this);
219	void keyPressed(e)
220	{
221		if(combo.isPopupVisible()) return;
222		if(e.getKeyCode() == KeyEvent.VK_ESCAPE ||
223			e.getKeyCode() == KeyEvent.VK_ENTER)
224		{
225			dialog.hide();
226		}
227		else if(e.getSource() != combo)
228		{
229			char ch = e.getKeyChar();
230			if(Character.isLetter(ch))
231			{
232				e.consume();
233				row = findFirstItem(ch);
234				/* The next few lines set the last visible row
235				 * of the table so that you can look ahead of
236				 * the selected row.
237				 */
238				visibleRows =
239					table.getVisibleRect().height / table.getRowHeight();
240				oldRow = table.getSelectedRow();
241				table.setRowSelectionInterval(row,row);
242				if (visibleRows > 5 && row - oldRow > visibleRows - 3)
243				{
244					row = Math.min( super.data.size() - 1, row + 3);
245				}
246				table.scrollRectToVisible(table.getCellRect(row,0,true));
247			}
248		}
249	}
250	/*
251	 * Having these members of KeyListener implemented as no-ops
252	 * will speedup execution.  Otherwise BeanShell throws an
253	 * exception that jEdit handles internally.
254	 * Under BeanShell 1.2, implementation of these methods is
255	 * required.
256	 */
257	void keyReleased(e) {}
258	void keyTyped(e) {}
259
260	/*
261	 * findFirstItem()
262	 * A simple linear search for the table entry that begins with the
263	 * given letter.  It returns the first row with an entry beginning with
264	 * the letter, or the immdediately preceding row if there is no match
265	 * on the letter.
266	 *
267	 */
268	int findFirstItem(char ch)
269	{
270		ch = Character.toUpperCase(ch);
271		int row = 0;
272		for(int i = 0; i < data.size(); ++i)
273		{
274			String name = ((Vector)data.elementAt(i)).elementAt(0);
275			char ch_test = Character.toUpperCase(name.charAt(0));
276			if( ch_test > ch) break;
277			else
278			{
279				row = i;
280				if( ch_test == ch) break;
281			}
282		}
283		return row;
284	}
285
286	title = AbbreviationListLabel;
287	dialog = new JDialog(view, title, false);
288	c = dialog.getContentPane();
289	c.add(tablePane, "Center");
290	c.add(comboPanel, "North");
291	c.add(buttonPanel, "South");
292	dialog.getRootPane().setDefaultButton(close);
293	dialog.pack();
294	dialog.setLocationRelativeTo(view);
295	dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
296	dialog.show();
297}
298
299/*
300 * The next four methods deal with writing the abbreviation sets to a new
301 * text buffer.
302 */
303void writeTableToNewBuffer(Vector v, String setName)
304{
305	Log.log(Log.DEBUG, BeanShell.class,
306		CallingWTTNBLabel + " " + setName);
307	writeHeader();
308	Log.log(Log.DEBUG, BeanShell.class, SizeVectorLabel + " "
309	 + String.valueOf(v.size()));
310	writeSet(v, setName);
311}
312
313// saved the currentSet and deleted it for makeTableDataForMode()-invocation
314// because otherwise the currently in the Dialog displayed set has no abbrevs
315// in the output written to the buffer.
316void writeAllToNewBuffer()
317{
318	writeHeader();
319	Vector vOut = new Vector();
320	savedCurrentSet = currentSet;
321	for( int i = 0; i < abbrevSets.length; ++i)
322	{
323		currentSet = null;
324		String setName = (String)abbrevSets[i];
325		vOut = makeTableDataForMode(vOut, setName);
326		writeSet(vOut, setName);
327		textArea.setSelectedText("\n\n");
328	}
329	currentSet = savedCurrentSet;
330}
331
332void writeHeader()
333{
334	jEdit.newFile(view);
335	textArea.setSelectedText(jEditAbbreviationTableLabel + "\n\n");
336}
337
338/*
339 * This truncates the definition text at 17 characters and the expansion text
340 * at 58.
341 */
342void writeSet(Vector v, String setName)
343{
344	textArea.setSelectedText(AbbreviationSetLabel + " " + setName + "\n");
345	textArea.setSelectedText(AbbreviationExpansionLabel + "\n\n");
346	if(v.size() == 0)
347		textArea.setSelectedText(NoAbbreviationsLabel + "\n");
348	else for( int i = 0; i < v.size(); ++i)
349	{
350		StringBuffer sb = new StringBuffer(85);
351		spaceString = "                    ";
352		char[] space = spaceString.toCharArray();
353		Vector row = (Vector)v.elementAt(i);
354		abbrevName = (String)row.elementAt(0);
355		if(abbrevName == null) continue;
356		if(abbrevName.length() > 17)
357			abbrevName = abbrevName.substring(0, 14) + "...";
358		sb.append(abbrevName);
359		sb.append(space, 0, 18 - (abbrevName.length()));
360		expansion = row.elementAt(1);
361		if(shortcut1 != null)
362		{
363			if(expansion.length() > 58)
364				expansion = expansion.substring(0, 55) + "...";
365			sb.append(expansion);
366		}
367		sb.append('\n');
368		textArea.setSelectedText(sb.toString());
369	}
370}
371
372
373/*
374 * main routine, including definition of global variables
375 */
376STARTING_SET = "global";
377EXCLUDE_EMPTY_SETS = true;
378abbrevSets = getActiveSets();
379currentSet = null;
380Vector data = new Vector(20, 5);
381showAbbrevs();
382
383/*
384	Macro index data (in DocBook format)
385
386<listitem>
387    <para><filename>Display_Abbreviations.bsh</filename></para>
388    <abstract><para>
389        Displays the abbreviations registered for each of jEdit's
390        editing modes.
391    </para></abstract>
392    <para>
393        The macro provides a read-only view of the abbreviations
394        contained in the <quote>Abbreviations</quote> option pane.  Pressing
395        a letter key will scroll the table to the first entry beginning with
396        that letter.  A further option is provided to write a selected mode's
397        abbreviations or all abbreviations in a text buffer for printing as a
398        reference. Notes in the source code listing point out some display options
399        that are configured by modifying global variables.
400    </para>
401</listitem>
402
403*/
404
405// end Display_Abbreviations.bsh
406
407