31
|
1 /*
|
|
2 * The dialog that controls font corecion.
|
|
3 */
|
|
4 package name.blackcap.clipman
|
|
5
|
|
6 import java.awt.Color
|
|
7 import java.awt.Font
|
|
8 import java.awt.GraphicsEnvironment
|
|
9 import java.awt.Toolkit
|
|
10 import java.awt.event.ActionEvent
|
|
11 import java.awt.event.ActionListener
|
|
12 import java.util.logging.Level
|
|
13 import java.util.logging.Logger
|
|
14 import javax.swing.*
|
|
15 import javax.swing.event.DocumentEvent
|
|
16 import javax.swing.event.DocumentListener
|
|
17
|
|
18 class CoerceDialog: JDialog(frame.v), ActionListener {
|
|
19 private val FONTS =
|
|
20 GraphicsEnvironment.getLocalGraphicsEnvironment().availableFontFamilyNames.copyOf().apply {
|
|
21 sort()
|
|
22 }
|
|
23 private val SIZES =
|
|
24 arrayOf(9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 16.0f, 18.0f,
|
|
25 24.0f, 36.0f, 48.0f, 64.0f, 72.0f, 96.0f, 144.0f, 288.0f)
|
|
26 private val DSIZEI = 6 /* SIZES[6] = 16 */
|
|
27
|
|
28 /* the proportional font family */
|
|
29 private val _pFamily = JComboBox<String>(FONTS).apply {
|
|
30 selectedIndex = getFontIndex(Font.SERIF)
|
|
31 }
|
|
32 val pFamily: String
|
|
33 get() {
|
|
34 return _pFamily.selectedItem as String
|
|
35 }
|
|
36
|
|
37 /* the proportional font size */
|
|
38 private val _pSize = JComboBox<Float>(SIZES).also {
|
|
39 it.selectedIndex = DSIZEI
|
|
40 it.setEditable(true)
|
|
41 it.actionCommand = "Size"
|
|
42 it.addActionListener(this)
|
|
43 }
|
|
44 val pSize: Float
|
|
45 get() {
|
|
46 return _pSize.selectedItem as Float
|
|
47 }
|
|
48
|
|
49 /* the monospaced font family */
|
|
50 private val _mFamily = JComboBox<String>(FONTS).apply {
|
|
51 selectedIndex = getFontIndex(Font.MONOSPACED)
|
|
52 }
|
|
53 val mFamily: String
|
|
54 get() {
|
|
55 return _mFamily.selectedItem as String
|
|
56 }
|
|
57
|
|
58 /* the monospaced font size */
|
|
59 private val _mSize = JComboBox<Float>(SIZES).also {
|
|
60 it.selectedIndex = DSIZEI
|
|
61 it.setEditable(true)
|
|
62 it.actionCommand = "Size"
|
|
63 it.addActionListener(this)
|
|
64 }
|
|
65 val mSize: Float
|
|
66 get() {
|
|
67 return _mSize.selectedItem as Float
|
|
68 }
|
|
69
|
|
70 /* standard spacing between elements (10 pixels ≅ 1/7") and half that */
|
|
71 private val BW = 5
|
|
72 private val BW2 = 10
|
|
73 private val VSPACE = Box.createVerticalStrut(BW)
|
|
74 private val VSPACE2 = Box.createVerticalStrut(BW2)
|
|
75 private val HSPACE2 = Box.createHorizontalStrut(BW2)
|
|
76
|
|
77 /* buttons */
|
|
78 private val _coerce = JButton("Coerce").also {
|
|
79 it.actionCommand = "Coerce"
|
|
80 it.addActionListener(this)
|
|
81 }
|
|
82
|
|
83 private val _cancel = JButton("Cancel").also {
|
|
84 it.actionCommand = "Cancel"
|
|
85 it.addActionListener(this)
|
|
86 }
|
|
87
|
|
88 /* initializer */
|
|
89 init {
|
|
90 title = "Coerce Fonts"
|
|
91 contentPane.apply {
|
|
92 add(Box(BoxLayout.Y_AXIS).apply {
|
|
93 add(VSPACE2)
|
|
94 add(leftLabel("Coerce proportionally-spaced text to:"))
|
|
95 add(VSPACE)
|
|
96 add(Box(BoxLayout.X_AXIS).apply {
|
|
97 add(HSPACE2)
|
|
98 add(Box.createGlue())
|
|
99 add(Box(BoxLayout.Y_AXIS).apply {
|
|
100 add(leftLabel("Family:"))
|
|
101 add(_pFamily)
|
|
102 })
|
|
103 add(Box.createGlue())
|
|
104 add(Box(BoxLayout.Y_AXIS).apply {
|
|
105 add(leftLabel("Size:"))
|
|
106 add(_pSize)
|
|
107 })
|
|
108 add(Box.createGlue())
|
|
109 add(HSPACE2)
|
|
110 })
|
|
111 add(VSPACE2)
|
|
112 add(JSeparator())
|
|
113 add(VSPACE2)
|
|
114 add(leftLabel("Coerce monospaced text to:"))
|
|
115 add(VSPACE)
|
|
116 add(Box(BoxLayout.X_AXIS).apply {
|
|
117 add(HSPACE2)
|
|
118 add(Box.createGlue())
|
|
119 add(Box(BoxLayout.Y_AXIS).apply {
|
|
120 add(leftLabel("Family:"))
|
|
121 add(_mFamily)
|
|
122 })
|
|
123 add(Box.createGlue())
|
|
124 add(Box(BoxLayout.Y_AXIS).apply {
|
|
125 add(leftLabel("Size:"))
|
|
126 add(_mSize)
|
|
127 })
|
|
128 add(Box.createGlue())
|
|
129 add(HSPACE2)
|
|
130 })
|
|
131 add(VSPACE2)
|
|
132 add(JSeparator())
|
|
133 add(VSPACE2)
|
|
134 add(Box(BoxLayout.X_AXIS).apply {
|
|
135 add(Box.createGlue())
|
|
136 add(_cancel)
|
|
137 add(Box.createGlue())
|
|
138 add(_coerce)
|
|
139 add(Box.createGlue())
|
|
140 })
|
|
141 add(VSPACE2)
|
|
142 })
|
|
143 }
|
|
144 rootPane.setDefaultButton(_coerce)
|
|
145 pack()
|
|
146 }
|
|
147
|
|
148 private fun leftLabel(text: String) = JLabel(text).apply {
|
|
149 horizontalAlignment = JLabel.LEFT
|
|
150 alignmentX = JLabel.LEFT_ALIGNMENT
|
|
151 }
|
|
152
|
|
153 override fun actionPerformed(e: ActionEvent) {
|
|
154 when (e.actionCommand) {
|
|
155 "Size" -> {
|
|
156 val source = e.source as? JComboBox<Float>
|
|
157 if (source != null && (source.selectedItem as Float) < 1.0f) {
|
|
158 Toolkit.getDefaultToolkit().beep()
|
|
159 source.selectedIndex = DSIZEI
|
|
160 }
|
|
161 }
|
|
162 "Coerce" -> {
|
|
163 setVisible(false)
|
|
164 coerce()
|
|
165 }
|
|
166 "Cancel" -> setVisible(false)
|
|
167 }
|
|
168 }
|
|
169
|
|
170 private fun coerce() {
|
|
171 val selected = queue.v.getSelected()
|
|
172 if (selected == null) {
|
|
173 JOptionPane.showMessageDialog(frame.v,
|
|
174 "No item selected.",
|
|
175 "Error",
|
|
176 JOptionPane.ERROR_MESSAGE)
|
|
177 } else {
|
|
178 val (plain, html) = when (selected.contents) {
|
|
179 is PasteboardItem.Plain ->
|
|
180 Pair(selected.contents.plain, null)
|
|
181 is PasteboardItem.HTML ->
|
|
182 Pair(selected.contents.plain, selected.contents.html)
|
|
183 is PasteboardItem.RTF ->
|
|
184 Pair(selected.contents.plain, selected.contents.html)
|
|
185 }
|
|
186 if (html == null) {
|
|
187 JOptionPane.showMessageDialog(frame.v,
|
|
188 "Only styled texts may be coerced.",
|
|
189 "Error",
|
|
190 JOptionPane.ERROR_MESSAGE)
|
|
191 } else {
|
|
192 PasteboardItem.write(
|
|
193 PasteboardItem.HTML(
|
|
194 plain,
|
|
195 coerceHTML(html, normalizeFont(pFamily), pSize,
|
|
196 normalizeFont(mFamily), mSize)))
|
|
197 }
|
|
198 }
|
|
199 }
|
|
200
|
|
201 private fun getFontIndex(font: String): Int {
|
|
202 val found = FONTS.indexOf(font)
|
|
203 if (found < 0) {
|
|
204 LOGGER.log(Level.WARNING, "font '${font}' not found")
|
|
205 return 0
|
|
206 }
|
|
207 return found
|
|
208 }
|
|
209
|
|
210 private fun normalizeFont(font: String): String {
|
|
211 val lcFont = font.toLowerCase()
|
|
212 return when (lcFont) {
|
|
213 in setOf("monospace", "serif", "sans-serif") -> lcFont
|
|
214 "monospaced" -> "monospace"
|
|
215 "sansserif" -> "sans-serif"
|
|
216 else -> font
|
|
217 }
|
|
218 }
|
|
219 }
|
|
220
|
|
221 val coerceDialog = CoerceDialog()
|