Mercurial > cgi-bin > hgweb.cgi > ClipMan
comparison src/name/blackcap/clipman/SettingsDialog.kt @ 41:33fbe3a78d84
Got the settings stuff compiling (untested).
author | David Barts <n5jrn@me.com> |
---|---|
date | Sat, 08 Feb 2020 22:10:01 -0700 |
parents | |
children | 339e2da5bf83 |
comparison
equal
deleted
inserted
replaced
40:c803a2c89ea0 | 41:33fbe3a78d84 |
---|---|
1 /* | |
2 * The dialog that controls font corecion. | |
3 */ | |
4 package name.blackcap.clipman | |
5 | |
6 import java.awt.Color | |
7 import java.awt.Container | |
8 import java.awt.Dimension | |
9 import java.awt.Font | |
10 import java.awt.GraphicsEnvironment | |
11 import java.awt.Toolkit | |
12 import java.awt.event.ActionEvent | |
13 import java.awt.event.ActionListener | |
14 import java.io.BufferedWriter | |
15 import java.io.FileOutputStream | |
16 import java.io.IOException | |
17 import java.io.OutputStreamWriter | |
18 import java.util.Hashtable | |
19 import java.util.Properties | |
20 import java.util.logging.Level | |
21 import java.util.logging.Logger | |
22 import javax.swing.* | |
23 import javax.swing.event.ChangeEvent | |
24 import javax.swing.event.ChangeListener | |
25 import kotlin.math.log10 | |
26 import kotlin.math.pow | |
27 import kotlin.math.roundToInt | |
28 import kotlin.text.toFloat | |
29 import kotlin.text.toInt | |
30 | |
31 /* work around name shadowing */ | |
32 private val _PROPS = PROPERTIES | |
33 | |
34 class SettingsDialog: JDialog(frame.v), ActionListener, ChangeListener { | |
35 /* the proportional font family */ | |
36 private val _pFamily = JComboBox<String>(FONTS).apply { | |
37 selectedItem = _PROPS.getString("prop.family") | |
38 alignmentX = JComboBox.LEFT_ALIGNMENT | |
39 } | |
40 val pFamily: String | |
41 get() { | |
42 return _pFamily.selectedItem as String | |
43 } | |
44 | |
45 /* the proportional font size */ | |
46 private val _pSize = JComboBox<Float>(SIZES).also { | |
47 it.selectedItem = _PROPS.getFloat("prop.size") | |
48 it.alignmentX = JComboBox.LEFT_ALIGNMENT | |
49 it.setEditable(true) | |
50 } | |
51 val pSize: Float | |
52 get() { | |
53 return _pSize.selectedItem as Float | |
54 } | |
55 | |
56 /* the monospaced font family */ | |
57 private val _mFamily = JComboBox<String>(FONTS).apply { | |
58 selectedItem = _PROPS.getString("mono.family") | |
59 alignmentX = JComboBox.LEFT_ALIGNMENT | |
60 } | |
61 val mFamily: String | |
62 get() { | |
63 return _mFamily.selectedItem as String | |
64 } | |
65 | |
66 /* the monospaced font size */ | |
67 private val _mSize = JComboBox<Float>(SIZES).also { | |
68 it.selectedItem = _PROPS.getFloat("mono.size") | |
69 it.alignmentX = JComboBox.LEFT_ALIGNMENT | |
70 it.setEditable(true) | |
71 } | |
72 val mSize: Float | |
73 get() { | |
74 return _mSize.selectedItem as Float | |
75 } | |
76 | |
77 /* max queue length */ | |
78 private val _qLength = _PROPS.getInt("queue.length") | |
79 private val _qlSlider = JSlider(10000, 30000, spinToSlide(_qLength)).also { | |
80 it.majorTickSpacing = 10000 | |
81 it.paintTicks = true | |
82 it.labelTable = Hashtable<Int, String>().apply { | |
83 put(10000, "10") | |
84 put(20000, "100") | |
85 put(30000, "1000") | |
86 } | |
87 it.addChangeListener(this) | |
88 } | |
89 private val _qlSpinner = JSpinner(SpinnerNumberModel(_qLength, 10, 1000, 1)).also { | |
90 it.addChangeListener(this) | |
91 } | |
92 val qLength: Int | |
93 get() { | |
94 return _qlSpinner.value as Int | |
95 } | |
96 | |
97 /* standard spacing between elements (10 pixels ≅ 1/7") and half that */ | |
98 private val BW = 5 | |
99 private val BW2 = 10 | |
100 | |
101 /* buttons */ | |
102 private val _ok = JButton("OK").also { | |
103 it.actionCommand = "OK" | |
104 it.addActionListener(this) | |
105 } | |
106 | |
107 private val _cancel = JButton("Cancel").also { | |
108 it.actionCommand = "Cancel" | |
109 it.addActionListener(this) | |
110 } | |
111 | |
112 private val _rad = JButton("Restore All Defaults").also { | |
113 it.actionCommand = "Restore" | |
114 it.addActionListener(this) | |
115 } | |
116 | |
117 /* initializer */ | |
118 init { | |
119 title = "Preferences" | |
120 contentPane.apply { | |
121 add(Box(BoxLayout.Y_AXIS).apply { | |
122 add(Box(BoxLayout.Y_AXIS).apply { | |
123 border = BorderFactory.createEmptyBorder(BW2, BW2, BW, BW2) | |
124 alignmentX = Box.CENTER_ALIGNMENT | |
125 add(leftLabel("Default proportionally-spaced font:")) | |
126 add(Box.createVerticalStrut(BW)) | |
127 add(Box(BoxLayout.X_AXIS).apply { | |
128 alignmentX = Box.LEFT_ALIGNMENT | |
129 add(Box.createGlue()) | |
130 add(Box(BoxLayout.Y_AXIS).apply { | |
131 add(leftLabel("Family:")) | |
132 add(_pFamily) | |
133 }) | |
134 add(Box.createGlue()) | |
135 add(Box(BoxLayout.Y_AXIS).apply { | |
136 add(leftLabel("Size:")) | |
137 add(_pSize) | |
138 }) | |
139 add(Box.createGlue()) | |
140 }) | |
141 }) | |
142 add(JSeparator()) | |
143 add(Box(BoxLayout.Y_AXIS).apply { | |
144 alignmentX = Box.CENTER_ALIGNMENT | |
145 border = BorderFactory.createEmptyBorder(BW, BW2, BW, BW2) | |
146 add(leftLabel("Default monospaced font:")) | |
147 add(Box.createVerticalStrut(BW)) | |
148 add(Box(BoxLayout.X_AXIS).apply { | |
149 alignmentX = Box.LEFT_ALIGNMENT | |
150 add(Box.createGlue()) | |
151 add(Box(BoxLayout.Y_AXIS).apply { | |
152 add(leftLabel("Family:")) | |
153 add(_mFamily) | |
154 }) | |
155 add(Box.createGlue()) | |
156 add(Box(BoxLayout.Y_AXIS).apply { | |
157 add(leftLabel("Size:")) | |
158 add(_mSize) | |
159 }) | |
160 add(Box.createGlue()) | |
161 }) | |
162 }) | |
163 add(JSeparator()) | |
164 add(Box(BoxLayout.Y_AXIS).apply { | |
165 alignmentX = Box.CENTER_ALIGNMENT | |
166 border = BorderFactory.createEmptyBorder(BW, BW2, BW, BW2) | |
167 add(leftLabel("Maximum queue size:")) | |
168 add(Box.createVerticalStrut(BW)) | |
169 add(Box(BoxLayout.X_AXIS).apply { | |
170 alignmentX = Box.LEFT_ALIGNMENT | |
171 add(Box.createGlue()) | |
172 add(_qlSlider) | |
173 add(Box.createGlue()) | |
174 add(_qlSpinner) | |
175 add(Box.createGlue()) | |
176 }) | |
177 }) | |
178 add(JSeparator()) | |
179 add(Box(BoxLayout.X_AXIS).apply { | |
180 alignmentX = Box.CENTER_ALIGNMENT | |
181 border = BorderFactory.createEmptyBorder(BW, BW2, BW, BW2) | |
182 add(Box.createGlue()) | |
183 add(_rad) | |
184 add(Box.createGlue()) | |
185 add(_cancel) | |
186 add(Box.createGlue()) | |
187 add(_ok) | |
188 add(Box.createGlue()) | |
189 }) | |
190 }) | |
191 } | |
192 rootPane.setDefaultButton(_ok) | |
193 pack() | |
194 setResizable(false) | |
195 } | |
196 | |
197 override fun actionPerformed(e: ActionEvent) { | |
198 when (e.actionCommand) { | |
199 "OK" -> { | |
200 writeProperties() | |
201 queue.v.maxSize = qLength | |
202 setVisible(false) | |
203 } | |
204 "Cancel" -> setVisible(false) | |
205 "Restore" -> revertProperties() | |
206 } | |
207 } | |
208 | |
209 override fun stateChanged(e: ChangeEvent) { | |
210 when (val source = e.source) { | |
211 source === _qlSlider -> | |
212 _qlSpinner.value = (10.0).pow(_qlSlider.value.toDouble() / 10000.0).roundToInt() | |
213 source === _qlSpinner -> | |
214 _qlSlider.value = spinToSlide(_qlSpinner.value as Int) | |
215 } | |
216 } | |
217 | |
218 private fun spinToSlide(value: Int): Int = | |
219 (log10(value.toDouble()) * 10000.0).roundToInt() | |
220 | |
221 private fun leftLabel(text: String) = JLabel(text).apply { | |
222 alignmentX = JLabel.LEFT_ALIGNMENT | |
223 } | |
224 | |
225 private fun badSize(control: JComboBox<Float>, default: Float, fontType: String): Boolean { | |
226 val size = control.selectedItem as? Float | |
227 if (size == null || size < 1.0f) { | |
228 JOptionPane.showMessageDialog(frame.v, | |
229 "Invalid ${fontType} font size.", | |
230 "Error", | |
231 JOptionPane.ERROR_MESSAGE) | |
232 control.selectedItem = default | |
233 return true | |
234 } | |
235 return false | |
236 } | |
237 | |
238 private fun revertProperties() | |
239 { | |
240 val params = arrayOf("mono.family", "mono.size", "prop.family", "prop.size", "queue.length") | |
241 for (param in params) { | |
242 _PROPS.put(param, DPROPERTIES.get(param)) | |
243 } | |
244 _mFamily.selectedItem = _PROPS.getString("mono.family") | |
245 _mSize.selectedItem = _PROPS.getFloat("mono.size") | |
246 _pFamily.selectedItem = _PROPS.getString("prop.family") | |
247 _pSize.selectedItem = _PROPS.getFloat("prop.size") | |
248 val ql = _PROPS.getInt("queue.length") | |
249 _qlSpinner.value = ql | |
250 _qlSlider.value = spinToSlide(ql) | |
251 } | |
252 | |
253 private fun writeProperties() | |
254 { | |
255 try { | |
256 BufferedWriter(OutputStreamWriter(FileOutputStream(PROP_FILE), CHARSET)).use { | |
257 _PROPS.put("mono.family", mFamily) | |
258 _PROPS.put("mono.size", mSize.toString()) | |
259 _PROPS.put("prop.family", pFamily) | |
260 _PROPS.put("prop.size", pSize.toString()) | |
261 _PROPS.put("queue.length", qLength.toString()) | |
262 _PROPS.store(it, null) | |
263 } | |
264 } catch (e: IOException) { | |
265 LOGGER.log(Level.WARNING, "IOException writing properties file") | |
266 val message = e.message | |
267 if (message != null && !message.isEmpty()) { | |
268 LOGGER.log(Level.WARNING, message) | |
269 } | |
270 JOptionPane.showMessageDialog(frame.v, | |
271 "Unable to write settings.", | |
272 "Error", | |
273 JOptionPane.ERROR_MESSAGE) | |
274 } | |
275 } | |
276 } | |
277 | |
278 val settingsDialog = SettingsDialog() | |
279 | |
280 fun Properties.getString(key: String): String = get(key) as String | |
281 | |
282 fun Properties.getInt(key: String): Int = getString(key).toInt() | |
283 | |
284 fun Properties.getFloat(key: String): Float = getString(key).toFloat() |