/** * 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(); } } }