Mercurial > cgi-bin > hgweb.cgi > JpegWasher
comparison src/name/blackcap/exifwasher/SettingsDialog.kt @ 5:dc1f4359659d
Got it compiling.
author | David Barts <n5jrn@me.com> |
---|---|
date | Thu, 09 Apr 2020 18:20:34 -0700 |
parents | 19c381c536ec |
children | aafc9c127c7b |
comparison
equal
deleted
inserted
replaced
4:ba5dc14652da | 5:dc1f4359659d |
---|---|
4 package name.blackcap.exifwasher | 4 package name.blackcap.exifwasher |
5 | 5 |
6 import java.awt.Toolkit | 6 import java.awt.Toolkit |
7 import java.awt.event.ActionEvent | 7 import java.awt.event.ActionEvent |
8 import java.awt.event.ActionListener | 8 import java.awt.event.ActionListener |
9 import java.io.BufferedWriter | |
9 import java.io.File | 10 import java.io.File |
11 import java.io.FileOutputStream | |
10 import java.io.IOException | 12 import java.io.IOException |
13 import java.io.OutputStreamWriter | |
14 import java.util.Properties | |
11 import java.util.logging.Level | 15 import java.util.logging.Level |
12 import java.util.logging.Logger | 16 import java.util.logging.Logger |
13 import javax.swing.* | 17 import javax.swing.* |
14 import javax.swing.event.ListDataEvent | 18 import javax.swing.event.ListDataEvent |
15 import javax.swing.event.ListDataListener | 19 import javax.swing.event.ListDataListener |
20 import javax.swing.event.ListSelectionListener | |
16 import kotlin.text.toBoolean | 21 import kotlin.text.toBoolean |
17 | 22 |
18 import name.blackcap.exifwasher.exiv2.* | 23 import name.blackcap.exifwasher.exiv2.* |
19 | 24 |
25 /* work around name shadowing */ | |
26 private val _PROPS = PROPERTIES | |
27 | |
20 class SettingsDialog : JDialog(Application.mainFrame) { | 28 class SettingsDialog : JDialog(Application.mainFrame) { |
21 private val BW = 9 | 29 protected val BW = 9 |
22 private val BW2 = BW * 2 | 30 protected val BW2 = BW * 2 |
23 | 31 |
24 /* where to send output, if not outputToInputDir */ | 32 /* where to send output, if not outputToInputDir */ |
25 private var _outputTo = PROPERTIES.getProperty("outputTo") | 33 protected var _outputTo = _PROPS.getProperty("outputTo") |
26 private var _dOutputTo = DPROPERTIES.getProperty("outputTo") | 34 protected var _dOutputTo = DPROPERTIES.getProperty("outputTo") |
27 val outputTo: String | 35 val outputTo: String |
28 get() = _outputTo | 36 get() = _outputTo |
29 | 37 |
30 /* make output where input was found */ | 38 /* make output where input was found */ |
31 private var _outputToInputDir = (PROPERTIES.getProperty("outputToInputDir") ?: "false").toBoolean() | 39 protected var _outputToInputDir = _PROPS.getProperty("outputToInputDir", "false").toBoolean() |
32 private var _dOutputToInputDir = (DPROPERTIES.getProperty("outputToInputDir") ?: "false").toBoolean() | 40 protected var _dOutputToInputDir = DPROPERTIES.getProperty("outputToInputDir", "false").toBoolean() |
33 val outputToInputDir: Boolean | 41 val outputToInputDir: Boolean |
34 get() = _outputToInputDir | 42 get() = _outputToInputDir |
35 | 43 |
36 /* the whitelist of allowed Exif tags */ | 44 /* the whitelist of allowed Exif tags */ |
37 private var _whitelist = Whitelist.parse(PROPERTIES.getProperty("whitelist") :? "") | 45 protected var _whitelist = Whitelist.parse(_PROPS.getProperty("whitelist", "")) |
38 val whitelist: Whitelist | 46 val whitelist: Whitelist |
39 get() = _whitelist | 47 get() = _whitelist |
40 | 48 |
41 /* the default whitelist, for factory resets */ | 49 /* the default whitelist, for factory resets */ |
42 private val _oWhitelist = _whitelist.clone() | 50 protected val _oWhitelist = _whitelist.clone() |
43 private val _dWhitelist = Whitelist.parse(DPROPERTIES.getProperty("whitelist") :? "") | 51 protected val _dWhitelist = Whitelist.parse(DPROPERTIES.getProperty("whitelist", "")) |
44 | 52 |
45 /* radio buttons to choose output directory policy */ | 53 /* radio buttons to choose output directory policy */ |
46 private val outputToButton = JRadioButton("Output to:", !outputToInputDir).apply { | 54 protected val outputToButton = JRadioButton("Output to:", !outputToInputDir).apply { |
47 addActionListener(ActionListener { setOutputOpts(isSelected()) }) | 55 addActionListener(ActionListener { setOutputOpts(isSelected()) }) |
48 } | 56 } |
49 private val outputToInputButton = JRadioButton( | 57 protected val outputToInputButton = JRadioButton( |
50 "Output to directory containing input file.", outputToInputDir).apply { | 58 "Output to directory containing input file.", outputToInputDir).apply { |
51 addActionListener(ActionListener { setOutputOpts(!isSelected()) }) | 59 addActionListener(ActionListener { setOutputOpts(!isSelected()) }) |
52 } | 60 } |
53 private val buttonGroup = ButtonGroup().apply { | 61 protected val buttonGroup = ButtonGroup().apply { |
54 add(outputToButton) | 62 add(outputToButton) |
55 add(outputToInputButton) | 63 add(outputToInputButton) |
56 } | 64 } |
57 private fun setOutputOpts(toSpecific: Boolean) { | 65 protected fun setOutputOpts(toSpecific: Boolean) { |
58 _outputToInputDir = !toSpecific | 66 _outputToInputDir = !toSpecific |
59 changeOutputTo.setEnabled(toSpecific) | 67 changeOutputTo.setEnabled(toSpecific) |
60 } | 68 } |
61 | 69 |
62 /* displays the OutputTo directory */ | 70 /* displays the OutputTo directory */ |
63 private val outputToText = JTextField(outputTo, 50).apply { | 71 protected val outputToText = JTextField(outputTo, 50).apply { |
64 setEditable(false) | 72 setEditable(false) |
65 } | 73 } |
66 | 74 |
67 /* pops up to change the above directory */ | 75 /* pops up to change the above directory */ |
68 private val outputToChooser = JFileChooser(outputToText.text).apply { | 76 protected val outputToChooser = JFileChooser(outputToText.text).apply { |
69 fileSelectionMode = DIRECTORIES_ONLY | 77 fileSelectionMode = JFileChooser.DIRECTORIES_ONLY |
70 } | 78 } |
71 | 79 |
72 /* requests the OutputTo directory be changed */ | 80 /* requests the OutputTo directory be changed */ |
73 private val changeOutputTo = JButton("Change").also { | 81 protected val changeOutputTo = JButton("Change").also { |
74 it.addActionListener(ActionListener { | 82 it.addActionListener(ActionListener { |
75 val status = outputToChooser.showOpenDialog(this) | 83 val status = outputToChooser.showOpenDialog(this) |
76 if (status == JFileChooser.APPROVE_OPTION) { | 84 if (status == JFileChooser.APPROVE_OPTION) { |
77 _outputTo = outputToChooser.selectedFile.canonicalPath | 85 _outputTo = outputToChooser.selectedFile.canonicalPath |
78 outputToText.text = _outputTo | 86 outputToText.text = _outputTo |
80 }) | 88 }) |
81 it.setEnabled(!outputToInputDir) | 89 it.setEnabled(!outputToInputDir) |
82 } | 90 } |
83 | 91 |
84 /* bottom buttons to restore defaults, cancel, save */ | 92 /* bottom buttons to restore defaults, cancel, save */ |
85 private val restoreButton = JButton("Restore All Defaults").also { | 93 protected val restoreButton = JButton("Restore All Defaults").apply { |
86 addActionListener(ActionListener { | 94 addActionListener(ActionListener { |
87 restore(_dOutputToInputDir, _dOutputTo, _dWhitelist) | 95 restore(_dOutputToInputDir, _dOutputTo, _dWhitelist) |
88 } | 96 }) |
89 } | 97 } |
90 private val cancelButton = JButton("Cancel").also { | 98 protected val cancelButton = JButton("Cancel").apply { |
91 addActionListener(ActionListener { | 99 addActionListener(ActionListener { |
92 setVisible(false) | 100 setVisible(false) |
93 restore(outputToInputDir, outputTo, whitelist) | 101 restore(outputToInputDir, outputTo, whitelist) |
94 }) | 102 }) |
95 } | 103 } |
96 private val saveButton = JButton("Save").also { | 104 protected val saveButton = JButton("Save").apply { |
97 addActionListener(ActionListener { | 105 addActionListener(ActionListener { |
98 setVisible(false) | 106 setVisible(false) |
99 writeProperties() | 107 writeProperties() |
100 }) | 108 }) |
101 } | 109 } |
102 | 110 |
103 private fun writeProperties() { | 111 protected fun writeProperties() { |
104 PROPERTIES.run { | 112 _PROPS.run { |
105 setProperty("outputTo", outputTo) | 113 setProperty("outputTo", outputTo) |
106 setProperty("outputToInputDir", outputToInputDir.toString()) | 114 setProperty("outputToInputDir", outputToInputDir.toString()) |
107 setProperty("whitelist", whitelist.toString()) | 115 setProperty("whitelist", whitelist.toString()) |
108 } | 116 } |
109 try { | 117 try { |
110 BufferedWriter(OutputStreamWriter(FileOutputStream(PROP_FILE), CHARSET)).use { | 118 BufferedWriter(OutputStreamWriter(FileOutputStream(PROP_FILE), CHARSET)).use { |
111 PROPERTIES.store(it, null) | 119 _PROPS.store(it, null) |
112 } | 120 } |
113 } catch (e: IOException) { | 121 } catch (e: IOException) { |
114 LOGGER.log(Level.SEVERE, "unable to write settings", e) | 122 LOGGER.log(Level.SEVERE, "unable to write settings", e) |
115 JOptionPane.showMessageDialog(Application.mainFrame, | 123 JOptionPane.showMessageDialog(Application.mainFrame, |
116 "Unable to write settings.", | 124 "Unable to write settings.", |
117 "Error", | 125 "Error", |
118 JOptionPane.ERROR_MESSAGE) | 126 JOptionPane.ERROR_MESSAGE) |
119 } | 127 } |
120 } | 128 } |
121 | 129 |
122 private fun restore(outputToInput: Boolean, output: String, wl: Whitelist) { | 130 protected fun restore(outputToInput: Boolean, output: String, wl: Whitelist) { |
123 outputToButton.setSelected(!outputToInput) | 131 outputToButton.setSelected(!outputToInput) |
124 changeOutputTo.setEnabled(!outputToInput) | 132 changeOutputTo.setEnabled(!outputToInput) |
125 outputToText.text = output | 133 outputToText.text = output |
126 outputToInputButton.setSelected(outputToInput) | 134 outputToInputButton.setSelected(outputToInput) |
127 wlSelectorModel.reset(wl.toList()) | 135 wlSelectorModel.reset(wl.toList()) |
128 } | 136 } |
129 | 137 |
130 /* so we can present a list of strings that is always sorted */ | 138 /* so we can present a list of strings that is always sorted */ |
131 private class WhiteListModel(basedOn: Collection<String>): ListModel<String> { | 139 protected class WhiteListModel(basedOn: Collection<String>): ListModel<String> { |
132 private val storage = ArrayList<String>(basedOn).apply { sort() } | 140 private val storage = ArrayList<String>(basedOn).apply { sort() } |
133 private val listeners = mutableListOf<ListDataListener>() | 141 private val listeners = mutableListOf<ListDataListener>() |
134 | 142 |
135 /* so we can mutate the list */ | 143 /* so we can mutate the list */ |
136 | 144 |
138 var index = storage.binarySearch(newItem) | 146 var index = storage.binarySearch(newItem) |
139 if (index < 0) { | 147 if (index < 0) { |
140 index = -(index + 1) | 148 index = -(index + 1) |
141 } | 149 } |
142 storage.add(index, newItem) | 150 storage.add(index, newItem) |
143 val event = ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, index, index) | 151 notifyAll(ListDataEvent.INTERVAL_ADDED, index, index) |
144 listeners.forEach { it.intervalAdded(event) } | |
145 } | 152 } |
146 | 153 |
147 fun removeAt(index: Int): Unit { | 154 fun removeAt(index: Int): Unit { |
148 if (storage.removeAt(index)) { | 155 storage.removeAt(index) |
149 val event = ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, index, index) | 156 notifyAll(ListDataEvent.INTERVAL_REMOVED, index, index) |
150 listeners.forEach { it.intervalRemoved(event) } | |
151 } | |
152 } | 157 } |
153 | 158 |
154 fun remove(oldItem: String): Unit { | 159 fun remove(oldItem: String): Unit { |
155 val index = basedOn.binarySearch(oldItem) | 160 val index: Int = storage.binarySearch(oldItem) |
156 if (index < 0) { | 161 if (index < 0) { |
157 return | 162 return |
158 } | 163 } |
159 var start = index | 164 storage.removeAt(index) |
160 while (start > 0 && storage[start] == oldItem) { | 165 notifyAll(ListDataEvent.INTERVAL_REMOVED, index, index) |
161 start -= 1 | |
162 } | |
163 var end = index | |
164 var max = storage.size - 1 | |
165 while (end < max && storage[end] == oldItem) { | |
166 end += 1 | |
167 } | |
168 storage.removeRange(start, end+1) | |
169 val event = ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, start, end) | |
170 listeners.forEach { it.intervalRemoved(event) } | |
171 } | 166 } |
172 | 167 |
173 fun reset(basedOn: Collection<String>): Unit { | 168 fun reset(basedOn: Collection<String>): Unit { |
174 val removeEvent = ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, 0, storage.size) | 169 val oldSize = storage.size |
175 storage.clear() | 170 storage.clear() |
171 notifyAll(ListDataEvent.INTERVAL_REMOVED, 0, oldSize) | |
176 storage.addAll(basedOn) | 172 storage.addAll(basedOn) |
177 storage.sort() | 173 storage.sort() |
178 val addEvent = ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, 0, storage.size) | 174 notifyAll(ListDataEvent.INTERVAL_ADDED, 0, storage.size) |
179 listeners.forEach { | 175 } |
180 it.contentsChanged(removeEvent) | 176 |
181 it.contentsChanged(addEvent) | 177 /* misc. */ |
182 } | |
183 } | |
184 | 178 |
185 fun toList(): List<String> = storage | 179 fun toList(): List<String> = storage |
180 | |
181 private fun notifyAll(eType: Int, index0: Int, index1: Int): Unit { | |
182 val event = ListDataEvent(this, eType, index0, index1) | |
183 when (eType) { | |
184 ListDataEvent.CONTENTS_CHANGED -> listeners.forEach { it.contentsChanged(event) } | |
185 ListDataEvent.INTERVAL_ADDED -> listeners.forEach { it.intervalAdded(event) } | |
186 ListDataEvent.INTERVAL_REMOVED -> listeners.forEach { it.intervalRemoved(event) } | |
187 else -> throw RuntimeException("unexpected event type!") | |
188 } | |
189 } | |
186 | 190 |
187 /* so we are a proper ListModel */ | 191 /* so we are a proper ListModel */ |
188 | 192 |
189 override fun addListDataListener(l: ListDataListener): Unit { | 193 override fun addListDataListener(l: ListDataListener): Unit { |
190 listeners.add(l) | 194 listeners.add(l) |
197 override fun getElementAt(index: Int): String = storage[index] | 201 override fun getElementAt(index: Int): String = storage[index] |
198 | 202 |
199 override fun getSize(): Int = storage.size | 203 override fun getSize(): Int = storage.size |
200 } | 204 } |
201 | 205 |
202 private class WLAddDialog(parent: SettingsDialog): JDialog(parent) { | 206 protected class WLAddDialog(parent: SettingsDialog): JDialog(parent) { |
203 JTextField text = JTextField(40).apply { | 207 private val BW = parent.BW |
208 private val BW2 = parent.BW2 | |
209 | |
210 private val toAdd = JTextField(40).apply { | |
204 alignmentX = CENTER_ALIGNMENT | 211 alignmentX = CENTER_ALIGNMENT |
205 border = BorderFactory.createEmptyBorder(BW, BW, BW, BW) | 212 border = BorderFactory.createEmptyBorder(BW, BW, BW, BW) |
206 } | 213 } |
207 | 214 |
208 JButton cancelButton = JButton("Cancel").apply { | 215 private val cancelButton = JButton("Cancel").apply { |
209 addActionListener(ActionListener { | 216 addActionListener(ActionListener { |
210 text.text = "" | 217 toAdd.text = "" |
211 setVisible(false) | 218 setVisible(false) |
212 }) | 219 }) |
213 } | 220 } |
214 | 221 |
215 JButton addButton = JButton("Add").apply { | 222 private val addButton = JButton("Add").apply { |
216 addActionListener(ActionListener { | 223 addActionListener(ActionListener { |
217 val newItem = text.text?.trim() | 224 val newItem = toAdd.text?.trim() |
218 if (newItem.isNullOrEmpty()) { | 225 if (newItem.isNullOrEmpty()) { |
219 Toolkit.getDefaultToolkit().beep() | 226 Toolkit.getDefaultToolkit().beep() |
220 } else { | 227 } else { |
221 wlSelectorModel.add(newItem) | 228 parent.wlSelectorModel.add(newItem) |
222 } | 229 } |
223 text.text = "" | 230 toAdd.text = "" |
224 setVisible(false) | 231 setVisible(false) |
225 } | |
226 }) | 232 }) |
227 } | 233 } |
228 | 234 |
229 init { | 235 init { |
230 title = "Add Item to Whitelist" | 236 title = "Add Item to Whitelist" |
231 contentPane.apply { | 237 contentPane.apply { |
232 layout = BoxLayout(this, BoxLayout.Y_AXIS) | 238 layout = BoxLayout(this, BoxLayout.Y_AXIS) |
233 add(text) | 239 add(toAdd) |
234 add(Box(BoxLayout.X_AXIS).apply { | 240 add(Box(BoxLayout.X_AXIS).apply { |
235 alignmentX = CENTER_ALIGNMENT | 241 alignmentX = CENTER_ALIGNMENT |
236 border = BorderFactory.createEmptyBorder(BW, BW, BW, BW) | 242 border = BorderFactory.createEmptyBorder(BW, BW, BW, BW) |
237 add(Box.createHorizontalGlue()) | 243 add(Box.createHorizontalGlue()) |
238 add(cancelButton) | 244 add(cancelButton) |
245 setResizable(false) | 251 setResizable(false) |
246 } | 252 } |
247 } | 253 } |
248 | 254 |
249 /* the JList that holds our whitelist */ | 255 /* the JList that holds our whitelist */ |
250 private val wlSelectorModel = WhiteListModel(whitelist.toList()) | 256 protected val wlSelectorModel = WhiteListModel(whitelist.toList()) |
251 private val wlSelector = JList().apply { | 257 protected val wlSelector: JList<String> = JList<String>().apply { |
252 visibleRowCount = -1 | 258 visibleRowCount = -1 |
253 model = wlSelectorModel | 259 model = wlSelectorModel |
254 clearSelection() | 260 clearSelection() |
255 addListSelectionListener(ListSelectionListener { | 261 addListSelectionListener(ListSelectionListener { |
256 wlDeleteButton.setEnabled(!isSelectionEmpty()) | 262 wlDeleteButton.setEnabled(!isSelectionEmpty()) |
257 } | 263 }) |
258 } | 264 } |
259 | 265 |
260 /* buttons for managing the whitelist */ | 266 /* buttons for managing the whitelist */ |
261 private val wlAddButton = JButton("Add").apply { | 267 protected val wlAddButton = JButton("Add").apply { |
262 addActionListener(ActionListener { wlAddDialog.setVisible(true) }) | 268 addActionListener(ActionListener { wlAddDialog.setVisible(true) }) |
263 } | 269 } |
264 private val wlDeleteButton = JButton("Delete").apply { | 270 protected val wlDeleteButton = JButton("Delete").apply { |
265 addActionListener(ActionListener { | 271 addActionListener(ActionListener { |
266 wlSelector.selectedIndices.forEach { wlSelectorModel.removeAt(it) } | 272 wlSelector.selectedIndices.forEach { wlSelectorModel.removeAt(it) } |
273 setEnabled(false) | |
267 }) | 274 }) |
268 setEnabled(false) | 275 setEnabled(false) |
269 } | 276 } |
270 | 277 |
271 /* the dialog that the Add button pops up */ | 278 /* the dialog that the Add button pops up */ |
272 private val wlAddDialog = WLAddDialog(this) | 279 protected val wlAddDialog = WLAddDialog(this) |
273 | 280 |
274 init { | 281 init { |
282 val home = System.getProperty("user.dir") | |
275 if (_outputTo.isNullOrEmpty()) { | 283 if (_outputTo.isNullOrEmpty()) { |
276 _outputTo = System.getProperty("user.dir") | 284 _outputTo = home |
285 } | |
286 if (_dOutputTo.isNullOrEmpty()) { | |
287 _dOutputTo = home | |
277 } | 288 } |
278 title = "Settings" | 289 title = "Settings" |
279 contentPane.apply { | 290 contentPane.apply { |
280 layout = BoxLayout(this, BoxLayout.Y_AXIS) | 291 layout = BoxLayout(this, BoxLayout.Y_AXIS) |
281 add(JTabbedPane().apply { | 292 add(JTabbedPane().apply { |