/**
* Copyright 1999-2009 The Pegadi Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pegadi.storysketch.views;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractCellEditor;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SpinnerDateModel;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jgraph.JGraph;
import org.jgraph.graph.CellMapper;
import org.jgraph.graph.CellView;
import org.jgraph.graph.CellViewRenderer;
import org.jgraph.graph.GraphCellEditor;
import org.jgraph.graph.VertexRenderer;
import org.jgraph.graph.VertexView;
import org.pegadi.storysketch.cells.Appointment;
import org.pegadi.storysketch.cells.AppointmentCell;
public class AppointmentView extends VertexView {
static AppointmentRenderer renderer = new AppointmentRenderer();
static AppointmentEditor editor = null;
// Constructor for Superclass
public AppointmentView(Object cell, JGraph graph,CellMapper cm) {
super(cell, graph, cm);
}
// Returns the Renderer for this Appointment
public CellViewRenderer getRenderer() {
return renderer;
}
public GraphCellEditor getEditor() {
if(editor == null)
editor = new AppointmentEditor();
return editor;
}
}
// Define the Renderer for an AppointmentView
class AppointmentRenderer extends VertexRenderer {
JPanel component = new JPanel();
JLabel whenDate = new JLabel();
JLabel whenTime = new JLabel();
JLabel howLong = new JLabel();
JTextArea info = new JTextArea();
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM);
DateFormat timeFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
Color infoColor = new Color(173, 217, 246);
Color dateColor = new Color(129, 175, 221);
Color infoColorExpired = new Color(246, 136, 140);
Color dateColorExpired = new Color(246, 80, 87);
Color infoColorDone = new Color(163, 207, 173);
Color dateColorDone = new Color(106, 207, 130);
JPanel whenPanel = new JPanel(new BorderLayout());
JPanel howLongPanel = new JPanel(new BorderLayout());
RoundedBorder border;
public AppointmentRenderer() {
border = new RoundedBorder(dateColor);
component.setBorder(border);
whenPanel.setBackground(dateColor);
whenPanel.setBorder(BorderFactory.createEmptyBorder(0,3,0,3));
howLongPanel.setBackground(dateColor);
howLongPanel.setBorder(BorderFactory.createEmptyBorder(0,3,0,3));
info.setBackground(infoColor);
info.setBorder(BorderFactory.createEmptyBorder(0,3,0,3));
whenPanel.add(whenDate, BorderLayout.WEST);
whenPanel.add(whenTime, BorderLayout.EAST);
howLongPanel.add(howLong, BorderLayout.EAST);
component.setLayout(new BorderLayout());
component.add(whenPanel, BorderLayout.NORTH);
component.add(info, BorderLayout.CENTER);
component.add(howLongPanel, BorderLayout.SOUTH);
whenDate.setFont(whenDate.getFont().deriveFont((float)9));
whenDate.setBorder(BorderFactory.createEmptyBorder());
whenTime.setFont(whenTime.getFont().deriveFont((float)9));
whenTime.setBorder(BorderFactory.createEmptyBorder());
howLong.setOpaque(false);
howLong.setFont(howLong.getFont().deriveFont((float)9));
howLong.setBorder(BorderFactory.createEmptyBorder());
info.setFont(info.getFont().deriveFont((float)11));
}
class RoundedBorder implements Border {
int CORNER = 10;
Color col;
public RoundedBorder(Color col) {
this.col = col;
}
public void setColor(Color col) {
this.col = col;
}
public void paintBorder(Component c,
Graphics g,
int x,
int y,
int width,
int height) {
g.setColor(col);
g.fillRoundRect(x, y, width -1, height -1, CORNER, CORNER);
g.setColor(Color.BLACK);
g.drawRoundRect(x, y, width -1, height -1, CORNER, CORNER);
}
public Insets getBorderInsets(Component c) {
return new Insets(CORNER/2, 1, CORNER/2, 1);
}
public boolean isBorderOpaque() {
return false;
}
}
public Component getRendererComponent(JGraph graph,
CellView view,
boolean sel,
boolean focus,
boolean preview) {
AppointmentCell ac = (AppointmentCell) view.getCell();
Appointment a = (Appointment) ac.getUserObject();
Date date = a.getWhen();
whenDate.setText(dateFormat.format(date));
whenTime.setText(timeFormat.format(date));
if(a.getWho().length() > 0 || a.getWhere().length() > 0 ) {
info.setText(a.getWho() + "\n" + a.getWhere());
} else {
info.setText("Avtale");
}
howLong.setText(a.getHowLong());
if(a.getWhen().getTime() < (new Date()).getTime()) {
if(a.getStatus().equals("done")) {
info.setBackground(infoColorDone);
whenPanel.setBackground(dateColorDone);
howLongPanel.setBackground(dateColorDone);
border.setColor(dateColorDone);
} else {
info.setBackground(infoColorExpired);
whenPanel.setBackground(dateColorExpired);
howLongPanel.setBackground(dateColorExpired);
border.setColor(dateColorExpired);
}
} else {
info.setBackground(infoColor);
whenPanel.setBackground(dateColor);
howLongPanel.setBackground(dateColor);
border.setColor(dateColor);
}
return component;
}
}
class AppointmentEditor extends StorySketchCellEditor {
public AppointmentEditor() {
super();
}
protected GraphCellEditor createGraphCellEditor() {
return new AppointmentEditor.RealCellEditor();
}
class RealCellEditor extends AbstractCellEditor implements GraphCellEditor {
JPanel editorComponent = new JPanel();
JTextArea notes;
String notesString;
JTextField whoField, howLongField, whereField;
JSpinner dateSpinner, timeSpinner;
SpinnerDateModel dateModel;
SpinnerDateModel timeModel;
ButtonGroup typeGroup = new ButtonGroup();
JRadioButton interview = new JRadioButton("Intervjuobjekt");
JRadioButton photographer = new JRadioButton("Fotograf");
JRadioButton other = new JRadioButton("Andre");
JTextArea interviewBefore;
JTextArea interviewAfter;
JCheckBox done = new JCheckBox("Ferdig");
JTabbedPane tabs;
JPanel appTab;
public RealCellEditor() {
typeGroup.add(interview);
typeGroup.add(photographer);
typeGroup.add(other);
// Create and add listener to the type buttons
ActionListener typeListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
typeUpdate(e);
}
};
interview.addActionListener(typeListener);
photographer.addActionListener(typeListener);
other.addActionListener(typeListener);
editorComponent.setBorder(UIManager.getBorder("Tree.editorBorder"));
editorComponent.setLayout(new BorderLayout());
JPanel topPanel = new JPanel();
topPanel.setLayout(new BorderLayout());
JLabel label = new JLabel("Avtale");
label.setBorder(BorderFactory.createEmptyBorder(0,3,0,0));
label.setFont(label.getFont().deriveFont((float)16));
topPanel.add(label,BorderLayout.WEST);
Box typeBox = Box.createHorizontalBox();
typeBox.setBorder(new TitledBorder("Avtale med:"));
typeBox.add(interview);
typeBox.add(photographer);
typeBox.add(other);
topPanel.add(typeBox,BorderLayout.EAST);
tabs = new JTabbedPane();
// Appointment tab
appTab = new JPanel();
appTab.setOpaque(false);
BorderLayout bl = new BorderLayout();
bl.setHgap(15);
appTab.setLayout(bl);
JPanel appTabLeft = new JPanel();
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
appTabLeft.setLayout(gridbag);
makeLabel(new JLabel("Hvem:"),appTabLeft,gridbag,c);
whoField = new JTextField(15);
makeField(whoField,appTabLeft,gridbag,c);
makeLabel(new JLabel("Når:"),appTabLeft,gridbag,c);
dateModel = new SpinnerDateModel();
dateSpinner = new JSpinner(dateModel);
dateSpinner.setEditor(new JSpinner.DateEditor(dateSpinner,"E dd. MMM yyyy"));
timeModel = new SpinnerDateModel();
timeSpinner = new JSpinner(timeModel);
timeSpinner.setEditor(new JSpinner.DateEditor(timeSpinner,"HH:mm"));
Box when = Box.createHorizontalBox();
when.add(dateSpinner);
Box.createHorizontalStrut(10);
when.add(timeSpinner);
makeField(when, appTabLeft,gridbag,c);
makeLabel(new JLabel("Hvor:"),appTabLeft,gridbag,c);
whereField = new JTextField(15);
makeField(whereField,appTabLeft,gridbag,c);
makeLabel(new JLabel("Varighet:"),appTabLeft,gridbag,c);
howLongField = new JTextField(15);
makeField(howLongField,appTabLeft,gridbag,c);
makeLabel(new JLabel("Status:"),appTabLeft,gridbag,c);
makeField(done,appTabLeft,gridbag,c);
appTab.add(appTabLeft, BorderLayout.WEST);
notes = new JTextArea(8,15);
// Tab in textareas should give focus to text
Set forward = new HashSet();
forward.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
Set backward = new HashSet();
backward.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,InputEvent.SHIFT_MASK));
notes.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forward);
notes.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, backward);
notesString = "Beskriv avtalen her";
notes.setText(notesString);
notes.setForeground(Color.LIGHT_GRAY);
notes.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent e) {
notes_focusGained(e);
}
public void focusLost(FocusEvent e) {
notes_focusLost(e);
}
});
notes.setLineWrap(true);
notes.setWrapStyleWord(true);
appTab.add(new JScrollPane(notes), BorderLayout.CENTER);
tabs.add(appTab,"Avtale");
// Interview tabs
Box beforeBox = Box.createVerticalBox();
interviewBefore = new JTextArea(10,20);
interviewBefore.setLineWrap(true);
interviewBefore.setWrapStyleWord(true);
interviewBefore.setBackground(Color.decode("#E1FCAE"));
beforeBox.add(new JLabel("Spørsmål:"));
beforeBox.add(new JScrollPane(interviewBefore));
Box afterBox = Box.createVerticalBox();
interviewAfter = new JTextArea(10,20);
interviewAfter.setLineWrap(true);
interviewAfter.setWrapStyleWord(true);
interviewAfter.setBackground(Color.decode("#FFFFAA"));
afterBox.add(new JLabel("Notater:"));
afterBox.add(new JScrollPane(interviewAfter));
interviewBefore.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forward);
interviewBefore.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, backward);
interviewAfter.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forward);
interviewAfter.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, backward);
JSplitPane interviewTab = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, beforeBox, afterBox);
interviewTab.setDividerLocation(0.5);
interviewTab.setResizeWeight(0.5);
tabs.add(interviewTab,"Intervju");
editorComponent.add(topPanel,BorderLayout.NORTH);
editorComponent.add(tabs,BorderLayout.CENTER);
ChangeListener l = new ChangeListener() {
public void stateChanged(ChangeEvent e) {
dateChanged();
}
};
dateSpinner.addChangeListener(l);
timeSpinner.addChangeListener(l);
}
private void typeUpdate(ActionEvent e) {
}
private void dateChanged() {
done.setEnabled(getSpinnerDate().getTime() < (new Date()).getTime());
}
private void notes_focusGained(FocusEvent e) {
if(notes.getForeground()==Color.LIGHT_GRAY) {
notes.setForeground(Color.BLACK);
notes.setText("");
}
}
private void notes_focusLost(FocusEvent e) {
if(notes.getText().length() == 0) {
notes.setForeground(Color.LIGHT_GRAY);
notes.setText(notesString);
}
}
private void makeLabel(Component comp, JPanel p, GridBagLayout gridbag, GridBagConstraints c) {
c.gridwidth = 1;
c.anchor = GridBagConstraints.EAST;
c.insets = new Insets(3,3,3,3);
gridbag.setConstraints(comp,c);
p.add(comp);
}
private void makeField(Component comp, JPanel p, GridBagLayout gridbag, GridBagConstraints c) {
c.gridwidth = GridBagConstraints.REMAINDER;
c.anchor = GridBagConstraints.WEST;
gridbag.setConstraints(comp,c);
p.add(comp);
}
public Component getGraphCellEditorComponent(
JGraph graph,
Object value,
boolean isSelected) {
AppointmentCell ac = (AppointmentCell) editingCell;
Appointment a = (Appointment) ac.getUserObject();
// Update editor with cell values
whoField.setText(a.getWho());
howLongField.setText(a.getHowLong());
whereField.setText(a.getWhere());
dateModel.setValue(a.getWhen());
timeModel.setValue(a.getWhen());
interviewBefore.setText(a.getInterviewBefore());
interviewAfter.setText(a.getInterviewAfter());
notes.setText(a.getNotes());
// Scroll to beginning
notes.setCaretPosition(0);
interviewBefore.setCaretPosition(0);
interviewAfter.setCaretPosition(0);
if(notes.getText().length() == 0) {
notes.setForeground(Color.LIGHT_GRAY);
notes.setText(notesString);
} else {
notes.setForeground(Color.BLACK);
}
int t = a.getType();
interview.setSelected(t == Appointment.TYPE_INTERVIEW);
photographer.setSelected(t == Appointment.TYPE_PHOTOGRAPHER);
other.setSelected(t == Appointment.TYPE_OTHER);
done.setSelected(a.getStatus().equals("done"));
dateChanged();
tabs.setSelectedComponent(appTab);
return editorComponent;
}
public Object getCellEditorValue() {
return editorComponent;
}
public Date getSpinnerDate() {
Date d = dateModel.getDate();
Date t = timeModel.getDate();
Calendar dateCal = new GregorianCalendar();
dateCal.setTime(d);
Calendar timeCal = new GregorianCalendar();
timeCal.setTime(t);
dateCal.set(Calendar.HOUR_OF_DAY,timeCal.get(Calendar.HOUR_OF_DAY));
dateCal.set(Calendar.MINUTE,timeCal.get(Calendar.MINUTE));
return dateCal.getTime();
}
public boolean stopCellEditing() {
AppointmentCell ac = (AppointmentCell) graph.getEditingCell();
Appointment a = (Appointment) ac.getUserObject();
// Update who
a.setWho(whoField.getText());
// Update when
a.setWhen(getSpinnerDate());
// Update how long
a.setHowLong(howLongField.getText());
// Update where
a.setWhere(whereField.getText());
// Update interview notes
a.setInterviewBefore(interviewBefore.getText());
a.setInterviewAfter(interviewAfter.getText());
// Update notes
if(notes.getForeground() == Color.LIGHT_GRAY) {
a.setNotes("");
} else {
a.setNotes(notes.getText());
}
// Update type
int ty = Appointment.TYPE_INTERVIEW;
if(interview.isSelected()) {
ty = Appointment.TYPE_INTERVIEW;
} else if(photographer.isSelected()) {
ty = Appointment.TYPE_PHOTOGRAPHER;
} else if(other.isSelected()) {
ty = Appointment.TYPE_OTHER;
}
a.setType(ty);
if(done.isSelected()) {
a.setStatus("done");
} else {
a.setStatus("none");
}
return super.stopCellEditing();
}
}
}