20
20
package com.eteks.sweethome3d.swing;
22
22
import java.awt.Component;
23
import java.awt.Cursor;
24
import java.awt.Dimension;
25
import java.awt.EventQueue;
23
26
import java.awt.Font;
24
27
import java.awt.Graphics;
25
28
import java.awt.Graphics2D;
29
import java.awt.Point;
30
import java.awt.Rectangle;
26
31
import java.awt.RenderingHints;
27
32
import java.awt.dnd.DnDConstants;
28
import java.awt.event.MouseAdapter;
29
33
import java.awt.event.MouseEvent;
30
34
import java.awt.event.MouseMotionAdapter;
31
35
import java.awt.image.BufferedImage;
32
36
import java.io.IOException;
33
37
import java.lang.ref.WeakReference;
38
import java.net.MalformedURLException;
34
40
import java.util.ArrayList;
35
41
import java.util.Collections;
36
42
import java.util.List;
38
44
import javax.imageio.ImageIO;
39
45
import javax.swing.Icon;
40
import javax.swing.JLabel;
46
import javax.swing.JComponent;
47
import javax.swing.JEditorPane;
41
48
import javax.swing.JTree;
42
49
import javax.swing.SwingUtilities;
43
50
import javax.swing.ToolTipManager;
51
import javax.swing.event.MouseInputAdapter;
44
52
import javax.swing.event.TreeModelEvent;
45
53
import javax.swing.event.TreeModelListener;
46
54
import javax.swing.event.TreeSelectionEvent;
47
55
import javax.swing.event.TreeSelectionListener;
56
import javax.swing.text.AttributeSet;
57
import javax.swing.text.Element;
58
import javax.swing.text.html.HTML;
59
import javax.swing.text.html.HTMLDocument;
48
60
import javax.swing.tree.DefaultTreeCellRenderer;
61
import javax.swing.tree.TreeCellRenderer;
49
62
import javax.swing.tree.TreeModel;
50
63
import javax.swing.tree.TreePath;
194
* Adds a double click mouse listener to modify selected furniture.
207
* Adds mouse listeners to modify selected furniture and manage links in piece information.
196
private void addMouseListener(final FurnitureCatalogController controller) {
197
addMouseListener(new MouseAdapter () {
209
private void addMouseListeners(final FurnitureCatalogController controller) {
210
final Cursor handCursor = new Cursor(Cursor.HAND_CURSOR);
211
MouseInputAdapter mouseListener = new MouseInputAdapter() {
199
213
public void mouseClicked(MouseEvent ev) {
200
if (ev.getClickCount() == 2) {
201
TreePath clickedPath = getPathForLocation(ev.getX(), ev.getY());
202
if (clickedPath != null
203
&& clickedPath.getLastPathComponent() instanceof CatalogPieceOfFurniture) {
204
controller.modifySelectedFurniture();
214
if (SwingUtilities.isLeftMouseButton(ev)) {
215
if (ev.getClickCount() == 2) {
216
TreePath clickedPath = getPathForLocation(ev.getX(), ev.getY());
217
if (clickedPath != null
218
&& clickedPath.getLastPathComponent() instanceof CatalogPieceOfFurniture) {
219
controller.modifySelectedFurniture();
221
} else if (getCellRenderer() instanceof CatalogCellRenderer) {
222
URL url = ((CatalogCellRenderer)getCellRenderer()).getURLAt(ev.getPoint(), (JTree)ev.getSource());
224
SwingTools.showDocumentInBrowser(url);
231
public void mouseMoved(MouseEvent ev) {
232
if (getCellRenderer() instanceof CatalogCellRenderer) {
233
URL url = ((CatalogCellRenderer)getCellRenderer()).getURLAt(ev.getPoint(), (JTree)ev.getSource());
235
EventQueue.invokeLater(new Runnable() {
237
setCursor(handCursor);
242
setCursor(Cursor.getDefaultCursor());
245
addMouseListener(mouseListener);
246
addMouseMotionListener(mouseListener);
249
288
* Cell renderer for this catalog tree.
251
private static class CatalogCellRenderer extends DefaultTreeCellRenderer {
252
private static final int DEFAULT_ICON_HEIGHT = 32;
253
private Font defaultFont;
254
private Font modifiablePieceFont;
290
private class CatalogCellRenderer extends JComponent implements TreeCellRenderer {
291
private static final int DEFAULT_ICON_HEIGHT = 32;
292
private Font defaultFont;
293
private Font modifiablePieceFont;
294
private DefaultTreeCellRenderer nameLabel;
295
private JEditorPane informationPane;
297
public CatalogCellRenderer() {
299
this.nameLabel = new DefaultTreeCellRenderer();
300
this.informationPane = new JEditorPane("text/html", null);
301
this.informationPane.setOpaque(false);
302
this.informationPane.setEditable(false);
304
add(this.informationPane);
257
307
public Component getTreeCellRendererComponent(JTree tree,
258
308
Object value, boolean selected, boolean expanded,
259
309
boolean leaf, int row, boolean hasFocus) {
260
// Get default label with its icon, background and focus colors
261
JLabel label = (JLabel)super.getTreeCellRendererComponent(
310
// Configure name label with its icon, background and focus colors
311
this.nameLabel.getTreeCellRendererComponent(
262
312
tree, value, selected, expanded, leaf, row, hasFocus);
263
313
// Initialize fonts if not done
264
314
if (this.defaultFont == null) {
265
this.defaultFont = label.getFont();
315
this.defaultFont = this.nameLabel.getFont();
316
String bodyRule = "body { font-family: " + this.defaultFont.getFamily() + "; "
317
+ "font-size: " + this.defaultFont.getSize() + "pt; "
318
+ "top-margin: 0; }";
319
((HTMLDocument)this.informationPane.getDocument()).getStyleSheet().addRule(bodyRule);
266
320
this.modifiablePieceFont =
267
new Font(this.defaultFont.getFontName(), Font.ITALIC, this.defaultFont.getSize());
321
new Font(this.defaultFont.getFontName(), Font.ITALIC, this.defaultFont.getSize());
270
323
// If node is a category, change label text
271
324
if (value instanceof FurnitureCategory) {
272
label.setText(((FurnitureCategory)value).getName());
273
label.setFont(this.defaultFont);
325
this.nameLabel.setText(((FurnitureCategory)value).getName());
326
this.nameLabel.setFont(this.defaultFont);
327
this.informationPane.setVisible(false);
275
329
// Else if node is a piece of furniture, change label text and icon
276
330
else if (value instanceof CatalogPieceOfFurniture) {
277
331
CatalogPieceOfFurniture piece = (CatalogPieceOfFurniture)value;
278
label.setText(piece.getName());
279
label.setIcon(getLabelIcon(tree, piece.getIcon()));
280
label.setFont(piece.isModifiable()
332
this.nameLabel.setText(piece.getName());
333
this.nameLabel.setIcon(getLabelIcon(tree, piece.getIcon()));
334
this.nameLabel.setFont(piece.isModifiable()
281
335
? this.modifiablePieceFont : this.defaultFont);
337
String information = piece.getInformation();
338
if (information != null) {
339
this.informationPane.setText(information);
340
this.informationPane.setVisible(true);
342
this.informationPane.setVisible(false);
349
public void doLayout() {
350
Dimension namePreferredSize = this.nameLabel.getPreferredSize();
351
this.nameLabel.setSize(namePreferredSize);
352
if (this.informationPane.isVisible()) {
353
Dimension informationPreferredSize = this.informationPane.getPreferredSize();
354
this.informationPane.setBounds(namePreferredSize.width + 2,
355
(namePreferredSize.height - informationPreferredSize.height) / 2,
356
informationPreferredSize.width, namePreferredSize.height);
361
public Dimension getPreferredSize() {
362
Dimension preferredSize = this.nameLabel.getPreferredSize();
363
if (this.informationPane.isVisible()) {
364
preferredSize.width += 2 + this.informationPane.getPreferredSize().width;
366
return preferredSize;
370
* The following methods are overridden for performance reasons.
373
public void revalidate() {
377
public void repaint(long tm, int x, int y, int width, int height) {
381
public void repaint(Rectangle r) {
385
public void repaint() {
289
391
* @param content the content of an image.
291
393
private Icon getLabelIcon(JTree tree, Content content) {
292
int rowHeight = tree.isFixedRowHeight()
293
? tree.getRowHeight()
294
: DEFAULT_ICON_HEIGHT;
295
return IconManager.getInstance().getIcon(content, rowHeight, tree);
394
return IconManager.getInstance().getIcon(content, getRowHeight(tree), tree);
398
* Returns the height of rows in tree.
400
private int getRowHeight(JTree tree) {
401
return tree.isFixedRowHeight()
402
? tree.getRowHeight()
403
: DEFAULT_ICON_HEIGHT;
299
protected void paintComponent(Graphics g) {
407
protected void paintChildren(Graphics g) {
300
408
// Force text anti aliasing on texts
301
409
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
302
410
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
303
super.paintComponent(g);
411
super.paintChildren(g);
414
public URL getURLAt(Point point, JTree tree) {
415
TreePath path = tree.getPathForLocation(point.x, point.y);
417
&& path.getLastPathComponent() instanceof CatalogPieceOfFurniture) {
418
CatalogPieceOfFurniture piece = (CatalogPieceOfFurniture)path.getLastPathComponent();
419
String information = piece.getInformation();
420
if (information != null) {
421
int row = tree.getRowForPath(path);
422
getTreeCellRendererComponent(tree, piece, false, false, false, row, false).doLayout();
423
Rectangle rowBounds = tree.getRowBounds(row);
424
point.x -= rowBounds.x + this.informationPane.getX();
425
point.y -= rowBounds.y + this.informationPane.getY();
426
if (point.x > 0 && point.y > 0) {
427
// Search in information pane if point is over a HTML link
428
int position = this.informationPane.viewToModel(point);
430
HTMLDocument hdoc = (HTMLDocument)this.informationPane.getDocument();
431
Element element = hdoc.getCharacterElement(position);
432
AttributeSet a = element.getAttributes();
433
AttributeSet anchor = (AttributeSet)a.getAttribute(HTML.Tag.A);
434
if (anchor != null) {
435
String href = (String)anchor.getAttribute(HTML.Attribute.HREF);
438
return new URL(href);
439
} catch (MalformedURLException ex) {
440
// Ignore malformed URL