1 /* Copyright (C) 2005-2011 Fabio Riccardi */
2 
3 package com.lightcrafts.ui.operation;
4 
5 import com.lightcrafts.model.Operation;
6 import static com.lightcrafts.ui.operation.Locale.LOCALE;
7 import com.lightcrafts.ui.toolkit.ImageOnlyButton;
8 import com.lightcrafts.utils.xml.XMLException;
9 import com.lightcrafts.utils.xml.XmlDocument;
10 
11 import javax.swing.*;
12 import java.awt.event.ActionEvent;
13 import java.awt.event.ActionListener;
14 import java.awt.image.BufferedImage;
15 import java.io.ByteArrayInputStream;
16 import java.io.ByteArrayOutputStream;
17 import java.util.prefs.Preferences;
18 
19 /**
20  * A title bar for OpControls, including a label for the Operation and
21  * standard controls like show/hide, enable/disable, and remove.
22  */
23 
24 class OpTitle extends SelectableTitle {
25 
26     // Preferences are used to remember OpControl presets:
27     private final static Preferences Prefs =
28         Preferences.userNodeForPackage(OpTitle.class);
29     private final static String PresetsKey = "Presets";
30 
31     private OpControl control;
32     private JToggleButton activeButton;
33     private JButton removeButton;
34     private OpTitleEditor editor;
35 
OpTitle(final OpControl control, final OpStack stack)36     OpTitle(final OpControl control, final OpStack stack) {
37         super(control);
38         this.control = control;
39 
40         editor = new OpTitleEditor(this, control.undoSupport);
41         editor.setLabel(label);
42 
43         Operation op = control.getOperation();
44         BufferedImage image = OpActions.getIcon(op);
45         setIcon(image);
46 
47         activeButton = createActiveButton();
48         activeButton.setToolTipText(LOCALE.get("DisableToolTip"));
49         activeButton.setSelected(true);
50         activeButton.addActionListener(
51             new ActionListener() {
52                 public void actionPerformed(ActionEvent event) {
53                     boolean active = activeButton.isSelected();
54                     String tip;
55                     if (active) {
56                         tip = LOCALE.get("DisableToolTip");
57                     }
58                     else {
59                         tip = LOCALE.get("EnableToolTip");
60                     }
61                     activeButton.setToolTipText(tip);
62                     control.setActivated(activeButton.isSelected());
63                 }
64             }
65         );
66         removeButton = createGoAwayButton();
67         removeButton.setToolTipText(LOCALE.get("RemoveToolTip"));
68         removeButton.addActionListener(
69             new ActionListener() {
70                 public void actionPerformed(ActionEvent event) {
71                     stack.removeControl(control);
72                 }
73             }
74         );
75         if (! control.isSingleton()) {
76             buttonBox.add(activeButton);
77             // buttonBox.add(Box.createHorizontalStrut(ButtonSpace));
78             buttonBox.add(removeButton);
79             // buttonBox.add(Box.createHorizontalStrut(ButtonSpace));
80         }
81     }
82 
getControl()83     OpControl getControl() {
84         return control;
85     }
86 
setActive(boolean active)87     void setActive(boolean active) {
88         // Won't generate an ActionEvent, so no risk of recursion with the
89         // activeButton ActionListener:
90         activeButton.setSelected(active);
91     }
92 
resetTitle(String title)93     void resetTitle(String title) {
94         super.resetTitle(title);
95         if (editor != null) {
96             // (Called from base class constructor, when editor may be null)
97             editor.setLabel(label);
98         }
99     }
100 
createGoAwayButton()101     private static JButton createGoAwayButton() {
102         Icon normalIcon = getTitleIcon("x");
103         Icon highlightIcon = getTitleIcon("x_H");
104         Icon pressedIcon = getTitleIcon("x_S");
105         JButton button = new ImageOnlyButton(
106             normalIcon, highlightIcon, pressedIcon, null
107         );
108 //        button.putClientProperty(SubstanceLookAndFeel.BUTTON_NO_MIN_SIZE_PROPERTY, Boolean.TRUE);
109 //        button.putClientProperty(SubstanceLookAndFeel.BUTTON_PAINT_NEVER_PROPERTY, Boolean.TRUE);
110 //        ImageOnlyButton.setStyle(button);
111         return button;
112     }
113 
createActiveButton()114     private static JToggleButton createActiveButton() {
115         JToggleButton button = new JToggleButton();
116         Icon normalIcon = getTitleIcon("nocheck");
117         Icon selectedIcon = getTitleIcon("check");
118         Icon normalHighlightIcon = getTitleIcon("nocheck_H");
119         Icon selectedHighlightIcon = getTitleIcon("check_H");
120         button.setIcon(normalIcon);
121         button.setSelectedIcon(selectedIcon);
122         button.setRolloverIcon(normalHighlightIcon);
123         button.setRolloverSelectedIcon(selectedHighlightIcon);
124         button.setRolloverEnabled(true);
125 //        button.putClientProperty(SubstanceLookAndFeel.BUTTON_NO_MIN_SIZE_PROPERTY, Boolean.TRUE);
126 //        button.putClientProperty(SubstanceLookAndFeel.BUTTON_PAINT_NEVER_PROPERTY, Boolean.TRUE);
127         ImageOnlyButton.setStyle(button);
128         return button;
129     }
130 
getPopupMenu()131     JPopupMenu getPopupMenu() {
132         JPopupMenu menu = super.getPopupMenu();
133 
134         final OpStack stack = findOpStack();
135 
136         boolean isLocked = control.isLocked();
137 
138         if (! control.isSingleton()) {
139             if (! control.isActivated()) {
140                 JMenuItem enableItem = new JMenuItem(
141                     LOCALE.get("EnableMenuItem")
142                 );
143                 enableItem.addActionListener(
144                     new ActionListener() {
145                         public void actionPerformed(ActionEvent event) {
146                             control.setActivated(true);
147                         }
148                     }
149                 );
150                 enableItem.setEnabled(! isLocked);
151                 menu.add(enableItem, 0);
152             }
153             else {
154                 JMenuItem disableItem = new JMenuItem(
155                     LOCALE.get("DisableMenuItem")
156                 );
157                 disableItem.addActionListener(
158                     new ActionListener() {
159                         public void actionPerformed(ActionEvent event) {
160                             control.setActivated(false);
161                         }
162                     }
163                 );
164                 disableItem.setEnabled(! isLocked);
165                 menu.add(disableItem, 0);
166             }
167             menu.add(new JSeparator(), 1);
168         }
169         if (! isLocked) {
170             JMenuItem lockItem = new JMenuItem(
171                 LOCALE.get("LockMenuItem")
172             );
173             lockItem.addActionListener(
174                 new ActionListener() {
175                     public void actionPerformed(ActionEvent event) {
176                         control.setLocked(true);
177                     }
178                 }
179             );
180             menu.add(lockItem, 2);
181         }
182         else {
183             JMenuItem unlockItem = new JMenuItem(
184                 LOCALE.get("UnlockMenuItem")
185             );
186             unlockItem.addActionListener(
187                 new ActionListener() {
188                     public void actionPerformed(ActionEvent event) {
189                         control.setLocked(false);
190                     }
191                 }
192             );
193             menu.add(unlockItem, 2);
194         }
195         menu.add(new JSeparator(), 3);
196 
197         JMenuItem savePreset = new JMenuItem(
198             LOCALE.get("RememberPresetMenuItem")
199         );
200         savePreset.addActionListener(
201             new ActionListener() {
202                 public void actionPerformed(ActionEvent event) {
203                     XmlDocument preset = new XmlDocument("Preset");
204                     control.save(preset.getRoot());
205                     writePreset(preset);
206                 }
207             }
208         );
209         menu.add(savePreset, 4);
210 
211         JMenuItem applyPreset = new JMenuItem(
212             LOCALE.get("ApplyPresetMenuItem")
213         );
214         final XmlDocument preset = readPreset();
215         applyPreset.addActionListener(
216             new ActionListener() {
217                 public void actionPerformed(ActionEvent event) {
218                     try {
219                         // Like control.restore(), but with undo:
220                         control.restorePresets(preset.getRoot());
221                     }
222                     catch (XMLException e) {
223                         // No way to back out of this, so leave things as
224                         // they are and hope the user can recover.
225                         System.err.println(
226                             "Error in preset restore: " + e.getMessage()
227                         );
228                     }
229                 }
230             }
231         );
232         if ((preset == null) || isLocked) {
233             applyPreset.setEnabled(false);
234         }
235         menu.add(applyPreset, 5);
236 
237         if (! control.isSingleton()) {
238             JMenuItem deleteItem = new JMenuItem(LOCALE.get("DeleteMenuItem"));
239             deleteItem.addActionListener(
240                 new ActionListener() {
241                     public void actionPerformed(ActionEvent event) {
242                         stack.removeControl(control);
243                     }
244                 }
245             );
246             deleteItem.setEnabled(! isLocked);
247 
248             menu.add(new JSeparator());
249 
250             menu.add(deleteItem);
251         }
252         return menu;
253     }
254 
255     // Read in the preset for the current OpControl type from Preferences,
256     // or null if no such preset exists.
readPreset()257     private XmlDocument readPreset() {
258         String key = getPresetsKey();
259         String text = Prefs.get(key, "");
260         try {
261             ByteArrayInputStream in =
262                 new ByteArrayInputStream(text.getBytes("UTF-8"));
263             return new XmlDocument(in);
264         }
265         catch (Exception e) {   // IOException or XMLException
266             return null;
267         }
268     }
269 
270     // Save the given preset in Preferences for the current OpControl type.
writePreset(XmlDocument preset)271     private void writePreset(XmlDocument preset) {
272         String key = getPresetsKey();
273         try {
274             ByteArrayOutputStream out = new ByteArrayOutputStream();
275             preset.write(out);
276             String text = out.toString("UTF-8");
277             Prefs.put(key, text);
278             Prefs.sync();
279         }
280         catch (Exception e) {   // IOException or BackingStoreException
281             // Make sure the "Apply Preset" item doesn't get enabled:
282             Prefs.remove(key);
283         }
284     }
285 
getPresetsKey()286     private String getPresetsKey() {
287         String name = control.getOperation().getType().getName();
288         return PresetsKey + name;
289     }
290 }
291