001    /*
002     * $Id: HighlighterPropertyEditor.java,v 1.1 2006/03/11 01:11:52 rbair Exp $
003     *
004     * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005     * Santa Clara, California 95054, U.S.A. All rights reserved.
006     *
007     * This library is free software; you can redistribute it and/or
008     * modify it under the terms of the GNU Lesser General Public
009     * License as published by the Free Software Foundation; either
010     * version 2.1 of the License, or (at your option) any later version.
011     * 
012     * This library is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015     * Lesser General Public License for more details.
016     * 
017     * You should have received a copy of the GNU Lesser General Public
018     * License along with this library; if not, write to the Free Software
019     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020     */
021    package org.jdesktop.swingx.editors;
022    
023    import java.awt.BorderLayout;
024    import java.awt.Color;
025    import java.awt.Container;
026    import java.awt.GridBagConstraints;
027    import java.awt.GridBagLayout;
028    import java.awt.Insets;
029    import java.awt.event.ActionEvent;
030    import java.beans.PropertyEditorSupport;
031    import java.beans.XMLDecoder;
032    import java.beans.XMLEncoder;
033    import java.io.ByteArrayInputStream;
034    import java.io.ByteArrayOutputStream;
035    import javax.swing.AbstractAction;
036    import javax.swing.AbstractListModel;
037    import javax.swing.BorderFactory;
038    import javax.swing.ButtonGroup;
039    import javax.swing.ImageIcon;
040    import javax.swing.JButton;
041    import javax.swing.JComboBox;
042    import javax.swing.JComponent;
043    import javax.swing.JDialog;
044    import javax.swing.JLabel;
045    import javax.swing.JRadioButton;
046    import javax.swing.JScrollPane;
047    import javax.swing.JSplitPane;
048    import javax.swing.JTextField;
049    import javax.swing.event.ListDataEvent;
050    import javax.swing.event.ListDataListener;
051    import javax.swing.event.ListSelectionEvent;
052    import javax.swing.event.ListSelectionListener;
053    //import org.jdesktop.jdnc.incubator.rlopes.colorcombo.ColorComboBox;
054    import org.jdesktop.swingx.JXList;
055    import org.jdesktop.swingx.JXPanel;
056    import org.jdesktop.swingx.JXTitledPanel;
057    import org.jdesktop.swingx.decorator.AlternateRowHighlighter;
058    import org.jdesktop.swingx.decorator.Highlighter;
059    import org.jdesktop.swingx.decorator.HighlighterPipeline;
060    import org.jdesktop.swingx.decorator.PatternHighlighter;
061    //import org.jdesktop.swingx.expression.ExpressionHighlighter;
062    //import org.netbeans.modules.form.NamedPropertyEditor;
063    //import org.openide.windows.WindowManager;
064    
065    
066    /**
067     *
068     * @author rbair
069     */
070    public class HighlighterPropertyEditor  extends PropertyEditorSupport { //implements NamedPropertyEditor {
071        private HighlighterPipeline pipeline = new HighlighterPipeline();
072        private Editor editor;
073    
074        /** Creates a new instance of HighlighterPropertyEditor */
075        public HighlighterPropertyEditor() {
076            editor = new Editor();
077            editor.highlightersList.setModel(new AbstractListModel() {
078                public Object getElementAt(int index) {
079                    return pipeline.getHighlighters()[index];
080                }
081    
082                public int getSize() {
083                    return pipeline.getHighlighters().length;
084                }
085            });
086            editor.highlightersList.getModel().addListDataListener(new ListDataListener() {
087                public void contentsChanged(ListDataEvent e) {
088                    HighlighterPropertyEditor.this.firePropertyChange();
089                }
090    
091                public void intervalAdded(ListDataEvent e) {
092                    HighlighterPropertyEditor.this.firePropertyChange();
093                }
094    
095                public void intervalRemoved(ListDataEvent e) {
096                    HighlighterPropertyEditor.this.firePropertyChange();
097                }
098            });
099        }
100    
101        public boolean supportsCustomEditor() {
102            return true;
103        }
104    
105        public String getJavaInitializationString() {
106            StringBuffer buffer = new StringBuffer();
107            ByteArrayOutputStream baos = new ByteArrayOutputStream(300);
108            XMLEncoder e = new XMLEncoder(baos);
109            e.writeObject(pipeline.getHighlighters());
110            e.close();
111            Highlighter[] blar = (Highlighter[])new XMLDecoder(new ByteArrayInputStream(baos.toString().getBytes())).readObject();
112            buffer.append("new org.jdesktop.swingx.decorator.HighlighterPipeline(\n");
113            buffer.append("\t(org.jdesktop.swingx.decorator.Highlighter[])new java.beans.XMLDecoder(new java.io.ByteArrayInputStream(\"");
114            buffer.append(escapeString(baos.toString()));
115            buffer.append("\".getBytes())).readObject())");
116            return buffer.toString();
117        }
118        
119        private String escapeString(String s) {
120            return s.replaceAll("\\\\", "\\\\\\\\").replaceAll("\"", "\\\\\"").replaceAll("\n", "");
121        }
122    
123        public String getDisplayName() {
124            return "Highlighter Editor";
125        }
126    
127        public void setAsText(String text) throws IllegalArgumentException {
128        }
129    
130        public void setValue(Object value) {
131            //if the value is a HighlighterPipeline, hold on to this. The
132            //editor is going to need it
133            if (value instanceof HighlighterPipeline) {
134                pipeline = new HighlighterPipeline(((HighlighterPipeline)value).getHighlighters());
135            } else {
136                pipeline = new HighlighterPipeline();
137            }
138            super.setValue(value);
139        }
140    
141        public Object getValue() {
142            return pipeline;
143        }
144    
145        public String getAsText() {
146            return pipeline.toString();
147        }
148    
149        public java.awt.Component getCustomEditor() {
150            return editor;
151        }
152    
153        private class Editor extends JXPanel {
154            private JXList highlightersList;
155            private AlternateRowDetailPanel alternateRowDetailPanel = new AlternateRowDetailPanel();
156            private ExpressionDetailPanel expressionDetailPanel = new ExpressionDetailPanel();
157            private PatternDetailPanel patternDetailPanel = new PatternDetailPanel();
158            
159            public Editor() {
160                setLayout(new BorderLayout());
161    
162                JSplitPane mainsp = new JSplitPane();
163                mainsp.setBorder(BorderFactory.createEmptyBorder());
164                JXTitledPanel tp = new JXTitledPanel("Highlighters");
165                JXPanel buttonPanel = new JXPanel();
166                buttonPanel.setOpaque(false);
167                JButton btn = new JButton(new AddAction());
168                btn.setOpaque(false);
169                btn.setBorder(BorderFactory.createEmptyBorder());
170                buttonPanel.add(btn);
171                btn = new JButton(new DeleteAction());
172                btn.setOpaque(false);
173                btn.setBorder(BorderFactory.createEmptyBorder());
174                buttonPanel.add(btn);
175                tp.addRightDecoration(buttonPanel);
176                highlightersList = new JXList();
177                JScrollPane sp = new JScrollPane(highlightersList);
178                sp.setBorder(BorderFactory.createEmptyBorder());
179                tp.setContentContainer(sp);
180                mainsp.setLeftComponent(tp);
181                final JXTitledPanel details = new JXTitledPanel("Highlighter Details");
182                mainsp.setRightComponent(details);
183                add(mainsp);
184                
185                highlightersList.addListSelectionListener(new ListSelectionListener() {
186                    public void valueChanged(ListSelectionEvent e) {
187                        if (!e.getValueIsAdjusting()) {
188                            //get the first selected value...
189                            Highlighter h = (Highlighter)highlightersList.getSelectedValue();
190                            //load the proper detail panel
191                            Container c = details.getContentContainer();
192                            HighlighterDetailPanel content = null;
193                            if (c instanceof HighlighterDetailPanel) {
194                                content = (HighlighterDetailPanel)c;
195                                content.save();
196                            }
197                            if (h instanceof AlternateRowHighlighter) {
198                                alternateRowDetailPanel.init((AlternateRowHighlighter)h);
199                                content = alternateRowDetailPanel;
200    //                        } else if (h instanceof ExpressionHighlighter) {
201    //                            expressionDetailPanel.init((ExpressionHighlighter)h);
202    //                            content = expressionDetailPanel;
203                            } else if (h instanceof PatternHighlighter) {
204                                patternDetailPanel.init((PatternHighlighter)h);
205                                content = patternDetailPanel;
206                            }
207                            details.setContentContainer(content == null ? new JXPanel() : content);
208                            details.revalidate();
209                            details.repaint();
210                        }
211                    }
212                });
213            }
214            
215            private class DeleteAction extends AbstractAction {
216                public DeleteAction() {
217                    super();
218                    super.putValue(AddAction.SMALL_ICON, new ImageIcon(HighlighterPropertyEditor.class.getResource("deleteHighlighter.gif")));
219                }
220                public void actionPerformed(ActionEvent ae) {
221                    //get the selected items
222                    Object[] values = highlightersList.getSelectedValues();
223                    for (int i=0; i<values.length; i++) {
224                        pipeline.removeHighlighter((Highlighter)values[i]);
225                    }
226                    ListDataListener[] listeners = ((AbstractListModel)highlightersList.getModel()).getListDataListeners();
227                    ListDataEvent evt = new ListDataEvent(highlightersList, ListDataEvent.CONTENTS_CHANGED, 0, pipeline.getHighlighters().length-1);
228                    for (int i=0; i<listeners.length; i++) {
229                        listeners[i].contentsChanged(evt);
230                    }
231                }
232            }
233            
234            private class AddAction extends AbstractAction {
235                public AddAction() {
236                    super();
237                    super.putValue(AddAction.SMALL_ICON, new ImageIcon(HighlighterPropertyEditor.class.getResource("newHighlighter.gif")));
238                }
239                public void actionPerformed(ActionEvent ae) {
240                    //show a true popup
241                    final JDialog dlg = new JDialog(/*WindowManager.getDefault().getMainWindow()*/(JDialog)null, true);
242                    JXPanel cp = new JXPanel(new GridBagLayout());
243                    final JRadioButton newRB = new JRadioButton("New Highlighter");
244                    final JRadioButton formRB = new JRadioButton("From Form");
245                    ButtonGroup bg = new ButtonGroup();
246                    bg.add(newRB);
247                    bg.add(formRB);
248                    newRB.setSelected(true);
249                    cp.add(newRB, new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(12, 12, 5, 11), 0, 0));
250                    JLabel label = new JLabel("Type: ");
251                    final JComboBox typeCB = new JComboBox(new String[]{"Alternate Row", "Expression", "Pattern"});
252                    label.setLabelFor(typeCB);
253                    cp.add(label, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 24, 7, 3), 0, 0));
254                    cp.add(typeCB, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 7, 11), 0, 0));
255                    label = new JLabel("Name: ");
256                    final JTextField nameTF = new JTextField("<auto-generate>");
257                    label.setLabelFor(nameTF);
258                    cp.add(label, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 24, 7, 3), 0, 0));
259                    cp.add(nameTF, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 7, 11), 0, 0));
260                    cp.add(formRB, new GridBagConstraints(0, 3, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 12, 5, 11), 0, 0));
261                    label = new JLabel("Choose Highlighter: ");
262                    final JComboBox highlighterCB = new JComboBox(new Object[0]);
263                    cp.add(label, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 24, 7, 3), 0, 0));
264                    cp.add(highlighterCB, new GridBagConstraints(1, 4, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 17, 11), 0, 0));
265                    JButton okButton = new JButton(new AbstractAction("OK") {
266                        public void actionPerformed(ActionEvent ae) {
267                            if (newRB.isSelected()) {
268                                String type = (String)typeCB.getSelectedItem();
269                                Highlighter h = null;
270                                if (type == null || type == "Alternate Row") {
271                                    h = new AlternateRowHighlighter();
272    //                            } else if (type == "Expression") {
273    //                                h = new ExpressionHighlighter();
274                                } else if (type == "Pattern") {
275                                    h = new PatternHighlighter();
276                                }
277                                //TODO deal with the name
278                                pipeline.addHighlighter(h);
279                                ListDataListener[] listeners = ((AbstractListModel)highlightersList.getModel()).getListDataListeners();
280                                int size = pipeline.getHighlighters().length;
281                                ListDataEvent evt = new ListDataEvent(highlightersList, ListDataEvent.CONTENTS_CHANGED, size -1, size -1);
282                                for (int i=0; i<listeners.length; i++) {
283                                    listeners[i].contentsChanged(evt);
284                                }
285                            }
286                            dlg.setVisible(false);
287                        }
288                    });
289                    JXPanel buttonPanel = new JXPanel(new GridBagLayout());
290                    buttonPanel.add(okButton, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.SOUTHEAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
291                    cp.add(buttonPanel, new GridBagConstraints(0, 5, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 12, 11, 11), 0, 0));
292                    dlg.setContentPane(cp);
293                    dlg.pack();
294                    //TODO need to to center...
295                    dlg.setVisible(true);
296                }
297            }
298            
299            private JComboBox createColorComboBox() {
300    //            try {
301    //                return new ColorComboBox();
302    //            } catch (Exception e) {
303                    return new JComboBox(new Color[]{Color.BLACK, Color.BLUE, 
304                            Color.CYAN, Color.DARK_GRAY, Color.GRAY,
305                            Color.GREEN, Color.LIGHT_GRAY, Color.MAGENTA,
306                            Color.ORANGE, Color.PINK, Color.RED, Color.WHITE,
307                            Color.YELLOW});
308    //            }
309            }
310    
311            private class HighlighterDetailPanel extends JXPanel {
312                private int rowCounter = 0;
313                protected JComboBox backgroundCB;
314                protected JComboBox selectedBackgroundCB;
315                protected JComboBox foregroundCB;
316                protected JComboBox selectedForegroundCB;
317                private Highlighter h;
318                
319                public HighlighterDetailPanel() {
320                    setLayout(new GridBagLayout());
321                    backgroundCB = createColorComboBox();
322                    add("Background: ", backgroundCB, false);
323                    selectedBackgroundCB = createColorComboBox();
324                    add("Selected Background: ", selectedBackgroundCB, false);
325                    foregroundCB = createColorComboBox();
326                    add("Foreground: ", foregroundCB, false);
327                    selectedForegroundCB = createColorComboBox();
328                    add("Selected Foreground: ", selectedForegroundCB, false);
329                }
330                
331                protected void add(String labelText, JComponent component, boolean isLast) {
332                    JLabel label = new JLabel(labelText);
333                    label.setLabelFor(component);
334                    Insets insets = rowCounter == 0 ? new Insets(12, 12, 5, 5) : new Insets(0, 12, 5, 5);
335                    add(label, new GridBagConstraints(0, rowCounter, 1, 1, 0.0, 0.0, isLast ? GridBagConstraints.NORTHWEST : GridBagConstraints.WEST, GridBagConstraints.NONE, insets, 0, 0));
336                    insets = rowCounter == 0 ? new Insets(12, 0, 5, 11) : new Insets(0, 0, isLast ? 11 : 5, 11);
337                    add(component, new GridBagConstraints(1, rowCounter, 1, 1, 1.0, isLast ? 1.0 : 0.0, isLast ? GridBagConstraints.NORTHWEST : GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insets, 0, 0));
338                    rowCounter++;
339                }
340                
341                protected void init(Highlighter h) {
342                    this.h = h;
343                    backgroundCB.setSelectedItem(h.getBackground());
344                    selectedBackgroundCB.setSelectedItem(h.getSelectedBackground());
345                    foregroundCB.setSelectedItem(h.getForeground());
346                    selectedForegroundCB.setSelectedItem(h.getSelectedForeground());
347                }
348                
349                public void save() {
350                    this.h.setBackground((Color)backgroundCB.getSelectedItem());
351                    this.h.setSelectedBackground((Color)selectedBackgroundCB.getSelectedItem());
352                    this.h.setForeground((Color)foregroundCB.getSelectedItem());
353                    this.h.setSelectedForeground((Color)selectedForegroundCB.getSelectedItem());
354                    ListDataListener[] listeners = ((AbstractListModel)highlightersList.getModel()).getListDataListeners();
355                    int size = pipeline.getHighlighters().length;
356                    ListDataEvent evt = new ListDataEvent(highlightersList, ListDataEvent.CONTENTS_CHANGED, size -1, size-1);
357                    for (int i=0; i<listeners.length; i++) {
358                        listeners[i].contentsChanged(evt);
359                    }
360                }
361            }
362            
363            private class AlternateRowDetailPanel extends HighlighterDetailPanel {
364                private JComboBox evenRowCB;
365                private JComboBox oddRowCB;
366                private AlternateRowHighlighter h;
367                
368                public AlternateRowDetailPanel() {
369                    evenRowCB = createColorComboBox();
370                    add("Even Row Background: ", evenRowCB, false);
371                    oddRowCB = createColorComboBox();
372                    add("Odd Row Background: ", oddRowCB, true);
373                }
374                
375                public void init(AlternateRowHighlighter h) {
376                    super.init(h);
377                    this.h = h;
378                    evenRowCB.setSelectedItem(h.getEvenRowBackground());
379                    oddRowCB.setSelectedItem(h.getOddRowBackground());
380                }
381                
382                public void save() {
383                    this.h.setEvenRowBackground((Color)evenRowCB.getSelectedItem());
384                    this.h.setOddRowBackground((Color)oddRowCB.getSelectedItem());
385                    super.save();
386                }
387            }
388            
389            private class ExpressionDetailPanel extends HighlighterDetailPanel {
390                private JTextField bgExpressionTF;
391                private JTextField fgExpressionTF;
392    //            private ExpressionHighlighter h;
393                
394                public ExpressionDetailPanel() {
395                    bgExpressionTF = new JTextField();
396                    add("Background Expression: ", bgExpressionTF, false);
397                    fgExpressionTF = new JTextField();
398                    add("Foreground Expression: ", fgExpressionTF, true);
399                }
400                
401                public void init(/*Expression*/Highlighter h) {
402                    super.init(h);
403    //                this.h = h;
404    //                bgExpressionTF.setText(h.getBackgroundExpression());
405    //                fgExpressionTF.setText(h.getForegroundExpression());
406                }
407                
408                public void save() {
409    //                this.h.setBackgroundExpression(bgExpressionTF.getText());
410    //                this.h.setForegroundExpression(fgExpressionTF.getText());
411                    super.save();
412                }
413            }
414            
415            private class PatternDetailPanel extends HighlighterDetailPanel {
416                private JTextField patternTF;
417    //            private JCheckBox matchFlagsCB;
418                private PatternHighlighter h;
419                
420                public PatternDetailPanel() {
421                    patternTF = new JTextField();
422                    add("Pattern: ", patternTF, true);
423    //                matchFlagsCB = new JCheckBox("Match Flags?");
424    //                add("", matchFlagsCB, true);
425                }
426                
427                public void init(PatternHighlighter h) {
428                    super.init(h);
429                    this.h = h;
430                    patternTF.setText(h.getPattern().pattern());
431    //                matchFlagsCB.setSelected(...);
432                }
433                
434                public void save() {
435                    this.h.setPattern(patternTF.getText(), 0); //TODO
436                    super.save();
437                }
438            }
439            
440        }
441    }