1
22
23 package org.crosswire.bibledesktop.display.basic;
24
25 import java.awt.Color;
26 import java.awt.Component;
27 import java.awt.Dimension;
28 import java.awt.Point;
29 import java.awt.Toolkit;
30 import java.awt.event.ActionEvent;
31 import java.awt.event.ActionListener;
32 import java.awt.event.MouseAdapter;
33 import java.awt.event.MouseEvent;
34 import java.net.URI;
35 import java.util.Locale;
36
37 import javax.swing.JScrollPane;
38 import javax.swing.JTextPane;
39 import javax.swing.Popup;
40 import javax.swing.PopupFactory;
41 import javax.swing.Timer;
42 import javax.swing.border.TitledBorder;
43 import javax.swing.text.html.HTMLEditorKit;
44 import javax.xml.transform.TransformerException;
45
46 import org.crosswire.bibledesktop.book.install.BookFont;
47 import org.crosswire.bibledesktop.desktop.Desktop;
48 import org.crosswire.bibledesktop.desktop.XSLTProperty;
49 import org.crosswire.bibledesktop.display.URIEvent;
50 import org.crosswire.bibledesktop.display.URIEventListener;
51 import org.crosswire.common.swing.AntiAliasedTextPane;
52 import org.crosswire.common.swing.GuiConvert;
53 import org.crosswire.common.swing.GuiUtil;
54 import org.crosswire.common.util.Reporter;
55 import org.crosswire.common.xml.Converter;
56 import org.crosswire.common.xml.SAXEventProvider;
57 import org.crosswire.common.xml.TransformingSAXEventProvider;
58 import org.crosswire.common.xml.XMLUtil;
59 import org.crosswire.jsword.book.Book;
60 import org.crosswire.jsword.book.BookCategory;
61 import org.crosswire.jsword.book.BookData;
62 import org.crosswire.jsword.book.BookException;
63 import org.crosswire.jsword.book.BookMetaData;
64 import org.crosswire.jsword.book.Books;
65 import org.crosswire.jsword.book.Defaults;
66 import org.crosswire.jsword.passage.NoSuchKeyException;
67 import org.crosswire.jsword.util.ConverterFactory;
68 import org.xml.sax.SAXException;
69
70
84 public class URITipMgr extends MouseAdapter implements ActionListener, URIEventListener {
85
86 private Component owner;
87 private JTextPane txtView;
88 private JScrollPane scrView;
89 private TitledBorder title;
90 private Popup popup;
91 private boolean sticky;
92
93 private int lastx;
94 private int lasty;
95 private URIEvent event;
96 private Timer timer;
97
98 private Converter converter;
99
100 public URITipMgr(Component own, Dimension dim) {
101 converter = ConverterFactory.getConverter();
102 owner = own;
103 txtView = new AntiAliasedTextPane();
104 txtView.setEditable(false);
105 txtView.setEditorKit(new HTMLEditorKit());
106 title = new TitledBorder((String) null);
107 scrView = new JScrollPane(txtView);
108 scrView.setBackground(Color.yellow);
109 scrView.setBorder(title);
110 scrView.getViewport().setPreferredSize(dim);
111 own.addMouseMotionListener(this);
113 own.addMouseListener(this);
114 txtView.addMouseListener(this);
116 setDelay(1500);
117 }
118
119 public void setDelay(int delay) {
120 if (timer != null) {
121 timer.stop();
122 }
123 timer = new Timer(delay, this);
124 }
125
126 public void updateText() {
127 if (event == null) {
128 return;
129 }
130 String txt = null;
131 String protocol = event.getScheme();
132 Book book = null;
133 if (protocol.equals(Desktop.GREEK_DEF_PROTOCOL)) {
134 book = Defaults.getGreekDefinitions();
135 title.setTitle("Greek Definition");
136 } else if (protocol.equals(Desktop.HEBREW_DEF_PROTOCOL)) {
137 book = Defaults.getHebrewDefinitions();
138 title.setTitle("Hebrew Definition");
139 } else if (protocol.equals(Desktop.GREEK_MORPH_PROTOCOL)) {
140 book = Defaults.getGreekParse();
141 title.setTitle("Greek Morphology");
142 } else if (protocol.equals(Desktop.HEBREW_MORPH_PROTOCOL)) {
143 book = Defaults.getHebrewParse();
144 title.setTitle("Hebrew Morphology");
145 }
146
147 if (book == null || Books.installed().getBook(book.getName()) == null) {
148 txtView.setText("Book Unavailable!");
149 title.setTitle("Exception");
150 return;
151 }
152
153 BookData bdata = null;
154
155 try {
156 bdata = new BookData(book, book.getKey(event.getURI()));
157 } catch (NoSuchKeyException ex) {
158 txtView.setText(ex.getDetailedMessage());
159 title.setTitle("Exception");
160 return;
161 }
162
163 assert book == bdata.getFirstBook();
164
165 BookMetaData bmd = book.getBookMetaData();
166 if (bmd == null) {
167 txtView.setText("Book Meta Data Unavailable!");
168 title.setTitle("Exception");
169 return;
170 }
171
172 boolean direction = bmd.isLeftToRight();
174 String fontSpec = GuiConvert.font2String(BookFont.instance().getFont(book));
175 try {
176 SAXEventProvider osissep = bdata.getSAXEventProvider();
177 TransformingSAXEventProvider htmlsep = (TransformingSAXEventProvider) converter.convert(osissep);
178 XSLTProperty.DIRECTION.setState(direction ? "ltr" : "rtl");
179
180 URI loc = bmd.getLocation();
181 XSLTProperty.BASE_URL.setState(loc == null ? "" : loc.getPath());
182
183 if (bmd.getBookCategory() == BookCategory.BIBLE) {
184 XSLTProperty.setProperties(htmlsep);
185 } else {
186 XSLTProperty.CSS.setProperty(htmlsep);
187 XSLTProperty.BASE_URL.setProperty(htmlsep);
188 XSLTProperty.DIRECTION.setProperty(htmlsep);
189 }
190
191 htmlsep.setParameter(XSLTProperty.FONT.getName(), fontSpec);
193
194 txt = XMLUtil.writeToString(htmlsep);
195 } catch (SAXException e) {
196 Reporter.informUser(this, e);
197 e.printStackTrace();
198 txtView.setText(e.getMessage());
199 title.setTitle("Exception");
200 } catch (TransformerException e) {
201 Reporter.informUser(this, e);
202 e.printStackTrace();
203 txtView.setText(e.getMessage());
204 title.setTitle("Exception");
205 } catch (BookException e) {
206 Reporter.informUser(this, e);
207 e.printStackTrace();
208 txtView.setText(e.getMessage());
209 title.setTitle("Exception");
210 }
211
212 GuiUtil.applyOrientation(txtView, direction);
214
215 txtView.setLocale(new Locale(bmd.getLanguage().getCode()));
219 txtView.setText(txt);
220 txtView.setCaretPosition(0);
221 }
222
223 void showTip() {
224 updateText();
226 Point p = owner.getLocationOnScreen();
227 Dimension d = scrView.getPreferredSize();
228 Dimension s = Toolkit.getDefaultToolkit().getScreenSize();
229 int x = p.x + lastx;
230 int y = p.y + lasty;
231 int horizDist = 30; int vertiDist = 10; if (x + x > s.width) {
235 x -= horizDist + d.width;
236 } else {
237 x += horizDist;
238 }
239 if (y + y > s.height) {
240 y -= vertiDist + d.height;
241 } else {
242 y += vertiDist;
243 }
244
245 popup = PopupFactory.getSharedInstance().getPopup(owner, scrView, x, y);
246 popup.show();
247 }
248
249 void hideTip(boolean stick) {
250 if (popup != null) {
251 popup.hide();
252 }
253 popup = null;
254 sticky = stick;
255 }
256
257
260 boolean interested(URIEvent ev) {
261 String protocol = ev.getScheme();
263 if (protocol.equals(Desktop.GREEK_DEF_PROTOCOL)) {
264 return true;
265 }
266 if (protocol.equals(Desktop.HEBREW_DEF_PROTOCOL)) {
267 return true;
268 }
269 if (protocol.equals(Desktop.GREEK_MORPH_PROTOCOL)) {
270 return true;
271 }
272 if (protocol.equals(Desktop.HEBREW_MORPH_PROTOCOL)) {
273 return true;
274 }
275 return false;
276 }
277
278
281 public void activateURI(URIEvent ev) {
282 }
283
284
287 public void enterURI(URIEvent ev) {
288 if (!interested(ev)) {
289 return;
290 }
291 System.out.println("entering" + ev.getURI());
292 event = ev;
293 if (sticky) {
294 hideTip(true); showTip(); } else {
297 timer.start();
298 }
299 }
300
301
304 public void leaveURI(URIEvent ev) {
305 if (!interested(ev)) {
306 return;
307 }
308 System.out.println("leaving" + ev.getURI());
309 timer.stop();
310 }
311
312
315 public void actionPerformed(ActionEvent e) {
316 hideTip(false); showTip();
320 timer.stop();
321 }
322
323
326 @Override
327 public void mouseDragged(MouseEvent e) {
328 }
329
330
333 @Override
334 public void mouseMoved(MouseEvent e) {
335 lastx = e.getX();
336 lasty = e.getY();
337 }
338
339 @Override
340 public void mouseClicked(MouseEvent e) {
341 if (e.getSource() == txtView && e.getClickCount() == 1) {
343 sticky = !sticky;
344 } else {
345 hideTip(false); }
347 }
348
349 @Override
350 public void mouseExited(MouseEvent e) {
351 if (e.getSource() == owner) {
355 timer.stop();
356 }
357 }
358 }
359