/*
* Copyright (C) 2012 Jason Gedge <http://www.gedge.ca>
*
* This file is part of the OpGraph project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
*/
package ca.gedge.opgraph.app.extensions;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
import javax.swing.border.EmptyBorder;
import javax.swing.border.MatteBorder;
import ca.gedge.opgraph.app.GraphEditorModel;
import ca.gedge.opgraph.app.components.DoubleClickableTextField;
import ca.gedge.opgraph.app.components.ResizeGrip;
import ca.gedge.opgraph.app.edits.notes.SetNoteTextEdit;
/**
* A component for displaying a {@link Note}.
*/
public class NoteComponent extends JPanel {
/** The default note color */
private static final Color DEFAULT_COLOR = new Color(255, 255, 150);
/** The note this component displaying */
private WeakReference<Note> noteRef;
/** Background color */
private Color background;
/** Border color */
private Color border;
/** Title text field */
private JTextField titleField;
/** Double-click support for the title text field */
private DoubleClickableTextField titleDoubleClickSupport;
/** Body text field */
private JTextArea bodyField;
/** Double-click support for the body text field */
private DoubleClickableTextField bodyDoubleClickSupport;
/** Resize grip */
private ResizeGrip resizeGrip;
/**
* Constructs a component to display a given {@link Note}.
*
* @param note the note
*/
public NoteComponent(Note note) {
this.noteRef = new WeakReference<Note>(note);
// Components
this.titleField = new JTextField(note.getTitle());
this.titleField.setBorder(new EmptyBorder(2, 5, 2, 5));
this.titleDoubleClickSupport = new DoubleClickableTextField(this.titleField);
this.titleDoubleClickSupport.addPropertyChangeListener(DoubleClickableTextField.TEXT_PROPERTY, textListener);
this.bodyField = new JTextArea(note.getBody());
this.bodyField.setLineWrap(true);
this.bodyField.setBorder(new EmptyBorder(2, 5, 2, 5));
this.bodyDoubleClickSupport = new DoubleClickableTextField(this.bodyField);
this.bodyDoubleClickSupport.addPropertyChangeListener(DoubleClickableTextField.TEXT_PROPERTY, textListener);
this.resizeGrip = new ResizeGrip(this);
this.resizeGrip.setBackground(new Color(0, 0, 0, 100));
add(this.resizeGrip);
add(this.titleField);
add(this.bodyField);
// Layout
final SpringLayout layout = new SpringLayout();
layout.putConstraint(SpringLayout.NORTH, this.titleField, 0, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.EAST, this.titleField, 0, SpringLayout.EAST, this);
layout.putConstraint(SpringLayout.WEST, this.titleField, 0, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.EAST, this.bodyField, 0, SpringLayout.EAST, this);
layout.putConstraint(SpringLayout.WEST, this.bodyField, 0, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.SOUTH, this.bodyField, 0, SpringLayout.SOUTH, this);
layout.putConstraint(SpringLayout.EAST, this.resizeGrip, 0, SpringLayout.EAST, this);
layout.putConstraint(SpringLayout.SOUTH, this.resizeGrip, 0, SpringLayout.SOUTH, this);
layout.putConstraint(SpringLayout.NORTH, this.bodyField, 1, SpringLayout.SOUTH, this.titleField);
setLayout(layout);
// Compute initial preferred size
final Dimension titlePref = this.titleField.getPreferredSize();
final Dimension bodyPref = this.bodyField.getPreferredSize();
final Dimension resizePref = this.resizeGrip.getPreferredSize();
final int prefw = Math.max(titlePref.width, bodyPref.width) + resizePref.width;
final int prefh = titlePref.height + 1 + Math.max(bodyPref.height, resizePref.width);
setPreferredSize(new Dimension(prefw, prefh));
setMinimumSize(new Dimension(prefw, prefh));
setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
setBackground(DEFAULT_COLOR);
setOpaque(false);
}
/**
* Gets the note this component is displaying.
*
* @return the note
*/
public Note getNote() {
return noteRef.get();
}
/**
* Gets the resize grip for this component.
*
* @return the resize grip
*/
public ResizeGrip getResizeGrip() {
return resizeGrip;
}
//
// Overrides
//
@Override
public void setBackground(Color bg) {
super.setBackground(bg);
background = new Color(bg.getRed(), bg.getGreen(), bg.getBlue(), 200);
border = new Color(bg.getRed(), bg.getGreen(), bg.getBlue(), 255);
setBorder(new MatteBorder(1, 1, 1, 1, border));
}
@Override
protected void paintComponent(Graphics gfx) {
super.paintComponent(gfx);
final Graphics2D g = (Graphics2D)gfx;
g.setColor(background);
g.fill(bodyField.getBounds());
final Rectangle titleBounds = titleField.getBounds();
++titleBounds.height;
g.setColor(border);
g.fill(titleBounds);
}
//
// DoubleClickableTextField property listener
//
private final PropertyChangeListener textListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent e) {
final Note note = noteRef.get();
String title = note.getTitle();
String body = note.getBody();
if(e.getSource() == bodyDoubleClickSupport) {
body = (String)e.getNewValue();
} else {
title = (String)e.getNewValue();
}
final SetNoteTextEdit edit = new SetNoteTextEdit(note, title, body);
GraphEditorModel.getActiveDocument().getUndoSupport().postEdit(edit);
}
};
}