001: package org.columba.calendar.ui.search;
002:
003: import java.awt.BorderLayout;
004: import java.awt.Color;
005: import java.awt.Component;
006: import java.awt.Font;
007: import java.awt.Graphics;
008: import java.awt.Insets;
009: import java.awt.Point;
010: import java.awt.event.ActionEvent;
011: import java.awt.event.ActionListener;
012: import java.awt.event.MouseAdapter;
013: import java.awt.event.MouseEvent;
014: import java.net.URI;
015: import java.text.DateFormat;
016: import java.util.Calendar;
017: import java.util.Iterator;
018: import java.util.List;
019:
020: import javax.swing.BorderFactory;
021: import javax.swing.DefaultListModel;
022: import javax.swing.JLabel;
023: import javax.swing.JList;
024: import javax.swing.JMenuItem;
025: import javax.swing.JPanel;
026: import javax.swing.JPopupMenu;
027: import javax.swing.ListCellRenderer;
028: import javax.swing.border.AbstractBorder;
029: import javax.swing.border.Border;
030:
031: import org.columba.calendar.facade.DialogFacade;
032: import org.columba.calendar.model.api.IComponent;
033: import org.columba.calendar.model.api.IEvent;
034: import org.columba.calendar.model.api.ITodo;
035: import org.columba.calendar.resourceloader.IconKeys;
036: import org.columba.calendar.resourceloader.ResourceLoader;
037: import org.columba.calendar.search.CalendarSearchResult;
038: import org.columba.core.gui.base.DoubleClickListener;
039: import org.columba.core.search.api.ISearchResult;
040: import org.jdesktop.swingx.JXList;
041: import org.jdesktop.swingx.decorator.Highlighter;
042: import org.jdesktop.swingx.decorator.HighlighterPipeline;
043: import org.jdesktop.swingx.decorator.RolloverHighlighter;
044:
045: public class SearchResultList extends JXList {
046:
047: private DefaultListModel listModel;
048:
049: private JPopupMenu contextMenu;
050:
051: public SearchResultList() {
052: super ();
053:
054: listModel = new DefaultListModel();
055: setModel(listModel);
056: setCellRenderer(new MyListCellRenderer());
057:
058: setBorder(null);
059: setHighlighters(new HighlighterPipeline(
060: new Highlighter[] { new RolloverHighlighter(new Color(
061: 248, 248, 248), Color.white) }));
062: setRolloverEnabled(true);
063:
064: addMouseListener(new DoubleClickListener() {
065: @Override
066: public void doubleClick(MouseEvent event) {
067: ISearchResult result = (ISearchResult) getSelectedValue();
068: URI uri = result.getLocation();
069: new DialogFacade().openEventEditorDialog(uri);
070: }
071: });
072:
073: add(getPopupMenu());
074: addMouseListener(new MyMouseListener());
075: }
076:
077: private JPopupMenu getPopupMenu() {
078: if (contextMenu != null)
079: return contextMenu;
080:
081: contextMenu = new JPopupMenu();
082:
083: JMenuItem item = new JMenuItem("Open..");
084: item.addActionListener(new ActionListener() {
085: public void actionPerformed(ActionEvent event) {
086: ISearchResult result = (ISearchResult) getSelectedValue();
087: URI uri = result.getLocation();
088: new DialogFacade().openEventEditorDialog(uri);
089: }
090: });
091:
092: contextMenu.add(item);
093: return contextMenu;
094: }
095:
096: public void addAll(List<ISearchResult> result) {
097: Iterator<ISearchResult> it = result.iterator();
098: while (it.hasNext()) {
099: listModel.addElement(it.next());
100: }
101: }
102:
103: public void add(ISearchResult result) {
104: listModel.addElement(result);
105: }
106:
107: public void clear() {
108: listModel.clear();
109: }
110:
111: class MyListCellRenderer extends JPanel implements ListCellRenderer {
112:
113: private JLabel iconLabel = new JLabel();
114:
115: private JLabel titleLabel = new JLabel();
116:
117: private JLabel startDateLabel = new JLabel();
118:
119: private JLabel descriptionLabel = new JLabel();
120:
121: private JPanel centerPanel;
122:
123: private Border lineBorder = new HeaderSeparatorBorder(
124: new Color(230, 230, 230));
125:
126: private DateFormat df = DateFormat.getDateTimeInstance();
127:
128: MyListCellRenderer() {
129: setLayout(new BorderLayout());
130:
131: centerPanel = new JPanel();
132: centerPanel.setLayout(new BorderLayout());
133:
134: JPanel titlePanel = new JPanel();
135: titlePanel.setLayout(new BorderLayout());
136: titlePanel.add(titleLabel, BorderLayout.WEST);
137: titlePanel.add(startDateLabel, BorderLayout.EAST);
138:
139: centerPanel.add(titlePanel, BorderLayout.NORTH);
140: centerPanel.add(descriptionLabel, BorderLayout.CENTER);
141: centerPanel.setBorder(BorderFactory.createEmptyBorder(0, 0,
142: 0, 2));
143: add(iconLabel, BorderLayout.WEST);
144: add(centerPanel, BorderLayout.CENTER);
145:
146: descriptionLabel.setFont(descriptionLabel.getFont()
147: .deriveFont(Font.ITALIC));
148:
149: setBorder(BorderFactory.createCompoundBorder(lineBorder,
150: BorderFactory.createEmptyBorder(2, 2, 2, 2)));
151: iconLabel.setBorder(BorderFactory.createEmptyBorder(2, 4,
152: 2, 8));
153:
154: titlePanel.setOpaque(false);
155: centerPanel.setOpaque(false);
156: setOpaque(true);
157:
158: }
159:
160: public Component getListCellRendererComponent(JList list,
161: Object value, int index, boolean isSelected,
162: boolean cellHasFocus) {
163:
164: if (isSelected) {
165: setBackground(list.getSelectionBackground());
166: setForeground(list.getSelectionForeground());
167:
168: } else {
169: setBackground(list.getBackground());
170: setForeground(list.getForeground());
171:
172: }
173:
174: CalendarSearchResult result = (CalendarSearchResult) value;
175:
176: titleLabel.setText(result.getTitle());
177: iconLabel.setIcon(ResourceLoader
178: .getSmallIcon(IconKeys.NEW_APPOINTMENT));
179: if (result.getDescription() != null
180: && result.getDescription().length() > 0)
181: descriptionLabel.setText(result.getDescription());
182: else
183: descriptionLabel.setText("no Description specified");
184:
185: IComponent c = result.getModel();
186: if (c.getType().equals(IComponent.TYPE.EVENT)) {
187: IEvent event = (IEvent) c;
188: Calendar startDate = event.getDtStart();
189:
190: startDateLabel.setText(df.format(startDate.getTime()));
191: } else if (c.getType().equals(IComponent.TYPE.TODO)) {
192: ITodo todo = (ITodo) c;
193: Calendar startDate = todo.getDtStart();
194: startDateLabel.setText(df.format(startDate.getTime()));
195: } else
196: throw new IllegalArgumentException(
197: "unsupported component type " + c.getType());
198:
199: return this ;
200: }
201:
202: }
203:
204: class MyMouseListener extends MouseAdapter {
205:
206: @Override
207: public void mouseClicked(MouseEvent e) {
208: handleEvent(e);
209: }
210:
211: @Override
212: public void mousePressed(MouseEvent e) {
213: handlePopupEvent(e);
214: }
215:
216: @Override
217: public void mouseReleased(MouseEvent e) {
218: handlePopupEvent(e);
219: }
220:
221: /**
222: * @param e
223: */
224: private void handlePopupEvent(MouseEvent e) {
225: Point p = e.getPoint();
226: if (e.isPopupTrigger()) {
227: // check if a single entry is selected
228: if (getSelectedIndices().length <= 1) {
229: // select new item
230: int index = locationToIndex(p);
231: setSelectedIndex(index);
232: }
233: // show context menu
234: getPopupMenu().show(e.getComponent(), p.x, p.y);
235: }
236: }
237:
238: /**
239: * @param e
240: */
241: private void handleEvent(MouseEvent e) {
242: }
243: }
244:
245: class HeaderSeparatorBorder extends AbstractBorder {
246:
247: protected Color color;
248:
249: public HeaderSeparatorBorder(Color color) {
250: super ();
251:
252: this .color = color;
253: }
254:
255: /**
256: * Paints the border for the specified component with the specified
257: * position and size.
258: *
259: * @param c
260: * the component for which this border is being painted
261: * @param g
262: * the paint graphics
263: * @param x
264: * the x position of the painted border
265: * @param y
266: * the y position of the painted border
267: * @param width
268: * the width of the painted border
269: * @param height
270: * the height of the painted border
271: */
272: public void paintBorder(Component c, Graphics g, int x, int y,
273: int width, int height) {
274: Color oldColor = g.getColor();
275: g.setColor(color);
276: g
277: .drawLine(x, y + height - 1, x + width - 1, y
278: + height - 1);
279:
280: g.setColor(oldColor);
281: }
282:
283: /**
284: * Returns the insets of the border.
285: *
286: * @param c
287: * the component for which this border insets value applies
288: */
289: public Insets getBorderInsets(Component c) {
290: return new Insets(0, 0, 1, 0);
291: }
292:
293: /**
294: * Reinitialize the insets parameter with this Border's current Insets.
295: *
296: * @param c
297: * the component for which this border insets value applies
298: * @param insets
299: * the object to be reinitialized
300: */
301: public Insets getBorderInsets(Component c, Insets insets) {
302: insets.left = insets.top = insets.right = insets.bottom = 1;
303: return insets;
304: }
305:
306: }
307: }
|