001: /*
002: * HelpSearchPanel.java - Help search GUI
003: * :tabSize=8:indentSize=8:noTabs=false:
004: * :folding=explicit:collapseFolds=1:
005: *
006: * Copyright (C) 2002 Slava Pestov
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public License
010: * as published by the Free Software Foundation; either version 2
011: * of the License, or any later version.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public License
019: * along with this program; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
021: */
022:
023: package org.gjt.sp.jedit.help;
024:
025: //{{{ Imports
026: import javax.swing.*;
027: import java.awt.event.*;
028: import java.awt.*;
029: import java.util.*;
030: import org.gjt.sp.jedit.gui.*;
031: import org.gjt.sp.jedit.io.VFSManager;
032: import org.gjt.sp.jedit.*;
033: import org.gjt.sp.util.Log;
034:
035: //}}}
036:
037: public class HelpSearchPanel extends JPanel {
038: //{{{ HelpSearchPanel constructor
039: public HelpSearchPanel(HelpViewerInterface helpViewer) {
040: super (new BorderLayout(6, 6));
041:
042: this .helpViewer = helpViewer;
043:
044: Box box = new Box(BoxLayout.X_AXIS);
045: box.add(new JLabel(jEdit
046: .getProperty("helpviewer.search.caption")));
047: box.add(Box.createHorizontalStrut(6));
048: box
049: .add(searchField = new HistoryTextField(
050: "helpviewer.search"));
051: searchField.addActionListener(new ActionHandler());
052:
053: add(BorderLayout.NORTH, box);
054:
055: results = new JList();
056: results.addMouseListener(new MouseHandler());
057: results.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
058: results.setCellRenderer(new ResultRenderer());
059: add(BorderLayout.CENTER, new JScrollPane(results));
060: } //}}}
061:
062: //{{{ Private members
063: private HelpViewerInterface helpViewer;
064: private HistoryTextField searchField;
065: private JList results;
066: private HelpIndex index;
067:
068: private HelpIndex getHelpIndex() {
069: if (index == null) {
070: index = new HelpIndex();
071: try {
072: index.indexEditorHelp();
073: } catch (Exception e) {
074: index = null;
075: Log.log(Log.ERROR, this , e);
076: GUIUtilities.error(helpViewer.getComponent(),
077: "helpviewer.search.error", new String[] { e
078: .toString() });
079: }
080: }
081:
082: return index;
083: } //}}}
084:
085: //{{{ ResultIcon class
086: static class ResultIcon implements Icon {
087: private static RenderingHints renderingHints;
088:
089: static {
090: Map<RenderingHints.Key, Object> hints = new HashMap<RenderingHints.Key, Object>();
091:
092: hints.put(RenderingHints.KEY_RENDERING,
093: RenderingHints.VALUE_RENDER_QUALITY);
094: hints.put(RenderingHints.KEY_ANTIALIASING,
095: RenderingHints.VALUE_ANTIALIAS_ON);
096:
097: renderingHints = new RenderingHints(hints);
098: }
099:
100: private int rank;
101:
102: ResultIcon(int rank) {
103: this .rank = rank;
104: }
105:
106: public int getIconWidth() {
107: return 40;
108: }
109:
110: public int getIconHeight() {
111: return 9;
112: }
113:
114: public void paintIcon(Component c, Graphics g, int x, int y) {
115: Graphics2D g2d = (Graphics2D) g.create();
116: g2d.setRenderingHints(renderingHints);
117:
118: for (int i = 0; i < 4; i++) {
119: if (rank > i)
120: g2d
121: .setColor(UIManager
122: .getColor("Label.foreground"));
123: else
124: g2d.setColor(UIManager
125: .getColor("Label.disabledForeground"));
126: g2d.fillOval(x + i * 10, y, 9, 9);
127: }
128: }
129: } //}}}
130:
131: //{{{ ResultRenderer class
132: static class ResultRenderer extends DefaultListCellRenderer {
133: public Component getListCellRendererComponent(JList list,
134: Object value, int index, boolean isSelected,
135: boolean cellHasFocus) {
136: super .getListCellRendererComponent(list, null, index,
137: isSelected, cellHasFocus);
138:
139: if (value instanceof String) {
140: setIcon(null);
141: setText((String) value);
142: } else {
143: Result result = (Result) value;
144: setIcon(new ResultIcon(result.rank));
145: setText(result.title);
146: }
147:
148: return this ;
149: }
150: } //}}}
151:
152: //{{{ Result class
153: static class Result {
154: String file;
155: String title;
156: int rank;
157:
158: Result(HelpIndex.HelpFile file, int count) {
159: this .file = file.file;
160: this .title = file.title;
161: rank = count;
162: }
163: } //}}}
164:
165: //{{{ ResultCompare class
166: static class ResultCompare implements Comparator<Result> {
167: public int compare(Result r1, Result r2) {
168: if (r1.rank == r2.rank)
169: return r1.title.compareTo(r2.title);
170: else
171: return r2.rank - r1.rank;
172: }
173: } //}}}
174:
175: //{{{ ActionHandler class
176: class ActionHandler implements ActionListener {
177: public void actionPerformed(ActionEvent evt) {
178: final HelpIndex index = getHelpIndex();
179: if (index == null)
180: return;
181:
182: results.setListData(new String[] { jEdit
183: .getProperty("helpviewer.searching") });
184:
185: final String text = searchField.getText();
186: final Vector<Result> resultModel = new Vector<Result>();
187:
188: VFSManager.runInWorkThread(new Runnable() {
189: public void run() {
190: StringTokenizer st = new StringTokenizer(text,
191: ",.;:-? ");
192:
193: // we later use this to compute a relative ranking
194: int maxRank = 0;
195:
196: while (st.hasMoreTokens()) {
197: String word = st.nextToken().toLowerCase();
198: HelpIndex.Word lookup = index.lookupWord(word);
199: if (lookup == null)
200: continue;
201:
202: for (int i = 0; i < lookup.occurCount; i++) {
203: HelpIndex.Word.Occurrence occur = lookup.occurrences[i];
204:
205: boolean ok = false;
206:
207: HelpIndex.HelpFile file = index
208: .getFile(occur.file);
209: for (int j = 0; j < resultModel.size(); j++) {
210: Result result = resultModel
211: .elementAt(j);
212: if (result.file.equals(file.file)) {
213: result.rank += occur.count;
214: result.rank += 20; // multiple files w/ word bonus
215: maxRank = Math.max(result.rank,
216: maxRank);
217: ok = true;
218: break;
219: }
220: }
221:
222: if (!ok) {
223: maxRank = Math
224: .max(occur.count, maxRank);
225: resultModel.addElement(new Result(file,
226: occur.count));
227: }
228: }
229: }
230:
231: if (maxRank != 0) {
232: // turn the rankings into relative rankings, from 1 to 4
233: for (int i = 0; i < resultModel.size(); i++) {
234: Result result = resultModel.elementAt(i);
235: result.rank = (int) Math
236: .ceil((double) result.rank * 4
237: / maxRank);
238: }
239:
240: Collections.sort(resultModel,
241: new ResultCompare());
242: }
243: }
244: });
245:
246: VFSManager.runInAWTThread(new Runnable() {
247: public void run() {
248: if (resultModel.isEmpty()) {
249: results
250: .setListData(new String[] { jEdit
251: .getProperty("helpviewer.no-results") });
252:
253: getToolkit().beep();
254: } else
255: results.setListData(resultModel);
256: }
257: });
258:
259: }
260: } //}}}
261:
262: //{{{ MouseHandler class
263: public class MouseHandler extends MouseAdapter {
264: public void mouseReleased(MouseEvent evt) {
265: int row = results.locationToIndex(evt.getPoint());
266: if (row != -1) {
267: Result result = (Result) results.getModel()
268: .getElementAt(row);
269: helpViewer.gotoURL(result.file, true, 0);
270: }
271: }
272: } //}}}
273: }
|