Mercurial > cgi-bin > hgweb.cgi > ClipMan
annotate src/name/blackcap/clipman/SearchDialog.kt @ 40:c803a2c89ea0
Make the JScrollPane scroll properly to highlighted text.
author | David Barts <n5jrn@me.com> |
---|---|
date | Wed, 05 Feb 2020 16:47:25 -0800 |
parents | 08eaae2aaf76 |
children | 19d9da731c43 |
rev | line source |
---|---|
27 | 1 /* |
2 * The dialog that controls a search. | |
3 */ | |
4 package name.blackcap.clipman | |
5 | |
6 import java.awt.Color | |
7 import java.awt.Toolkit | |
8 import java.awt.event.ActionEvent | |
9 import java.awt.event.ActionListener | |
10 import javax.swing.* | |
11 import javax.swing.event.DocumentEvent | |
12 import javax.swing.event.DocumentListener | |
13 | |
14 class SearchDialog: JDialog(frame.v), ActionListener, DocumentListener { | |
15 /* the search term */ | |
28
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
16 private val _searchFor = JTextField(25).also { |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
17 it.border = BorderFactory.createLineBorder(Color.GRAY, 1) |
27 | 18 it.horizontalAlignment = JTextField.LEFT |
19 it.alignmentX = JTextField.LEFT_ALIGNMENT | |
20 it.text = "" | |
21 it.document.addDocumentListener(this) | |
22 } | |
23 val searchFor: String | |
24 get() { | |
25 return _searchFor.text | |
26 } | |
27 | |
28 /* whether or not we should ignore case */ | |
29 private val _ignoreCase = JCheckBox("Ignore case", true) | |
30 val ignoreCase: Boolean | |
31 get() { | |
32 return _ignoreCase.isSelected() | |
33 } | |
34 | |
35 /* whether or not searches should wrap around */ | |
36 private val _autoWrap = JCheckBox("Auto wrap", false) | |
37 val autoWrap: Boolean | |
38 get() { | |
39 return _autoWrap.isSelected() | |
40 } | |
41 | |
42 /* which direction to search */ | |
43 private val _forwards = JRadioButton("Forward", true) | |
44 private val _backwards = JRadioButton("Backward", false) | |
45 private val _direction = ButtonGroup().apply { | |
46 add(_forwards) | |
47 add(_backwards) | |
48 } | |
49 val direction: PasteboardQueue.Direction | |
50 get() { | |
51 if (_forwards.isSelected()) { | |
52 return PasteboardQueue.Direction.FORWARDS | |
53 } | |
54 if (_backwards.isSelected()) { | |
55 return PasteboardQueue.Direction.BACKWARDS | |
56 } | |
57 throw RuntimeException("impossible button state!") | |
58 } | |
59 | |
31 | 60 /* standard spacing between elements (10 pixels ≅ 1/7") and half that */ |
61 private val BW = 5 | |
62 private val BW2 = 10 | |
28
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
63 |
27 | 64 /* where to begin searching from. unlike the other properties, this |
65 one is read/write. null means to start from the beginning on | |
66 forward searches, and from the end on backward searches (i.e. | |
67 search everything) */ | |
68 var origin: PasteboardQueue.Offset? = null | |
69 | |
70 private val _find = JButton("Find").also { | |
71 it.actionCommand = "Find" | |
72 it.addActionListener(this) | |
73 } | |
74 | |
28
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
75 private val _cancel = JButton("Cancel").also { |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
76 it.actionCommand = "Cancel" |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
77 it.addActionListener(this) |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
78 } |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
79 |
27 | 80 /* initializer */ |
81 init { | |
82 title = "Find" | |
83 contentPane.apply { | |
84 add(Box(BoxLayout.Y_AXIS).apply { | |
85 add(Box(BoxLayout.Y_AXIS).apply { | |
28
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
86 add(JLabel("Search for:").apply { |
27 | 87 horizontalAlignment = JLabel.LEFT |
88 alignmentX = JLabel.LEFT_ALIGNMENT | |
89 }) | |
90 add(_searchFor) | |
28
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
91 alignmentX = Box.CENTER_ALIGNMENT |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
92 border = BorderFactory.createEmptyBorder(BW2, BW2, BW, BW2) |
27 | 93 }) |
94 add(Box(BoxLayout.X_AXIS).apply { | |
28
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
95 add(Box.createGlue()) |
27 | 96 add(Box(BoxLayout.Y_AXIS).apply { |
28
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
97 add(JLabel("Settings:").apply { |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
98 horizontalAlignment = JLabel.CENTER |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
99 alignmentX = JLabel.LEFT_ALIGNMENT |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
100 }) |
27 | 101 add(_ignoreCase) |
102 add(_autoWrap) | |
103 }) | |
28
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
104 add(Box.createGlue()) |
27 | 105 add(Box(BoxLayout.Y_AXIS).apply { |
28
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
106 add(JLabel("Direction:").apply { |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
107 horizontalAlignment = JLabel.CENTER |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
108 alignmentX = JLabel.LEFT_ALIGNMENT |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
109 }) |
27 | 110 add(_forwards) |
111 add(_backwards) | |
112 }) | |
28
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
113 add(Box.createGlue()) |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
114 alignmentX = Box.CENTER_ALIGNMENT |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
115 border = BorderFactory.createEmptyBorder(BW, BW2, BW, BW2) |
27 | 116 }) |
28
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
117 add(Box(BoxLayout.X_AXIS).apply { |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
118 add(Box.createGlue()) |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
119 add(_cancel) |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
120 add(Box.createGlue()) |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
121 add(_find) |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
122 add(Box.createGlue()) |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
123 border = BorderFactory.createEmptyBorder(BW, BW2, BW2, BW2) |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
124 }) |
27 | 125 }) |
126 } | |
127 rootPane.setDefaultButton(_find) | |
28
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
128 pack() |
38
08eaae2aaf76
Stop dialog resizing, fix detection of bad font sizes.
David Barts <n5jrn@me.com>
parents:
31
diff
changeset
|
129 setResizable(false) |
27 | 130 } |
131 | |
132 override fun actionPerformed(e: ActionEvent) { | |
28
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
133 when (e.actionCommand) { |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
134 "Find" -> { |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
135 setVisible(false) |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
136 find() |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
137 } |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
138 "Cancel" -> setVisible(false) |
27 | 139 } |
140 } | |
141 | |
142 override fun setVisible(visible: Boolean) { | |
143 if (visible) { | |
144 _searchFor.run { | |
145 requestFocusInWindow() | |
146 selectAll() | |
147 } | |
148 } | |
149 super.setVisible(visible) | |
150 } | |
151 | |
152 fun find(): Unit { | |
28
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
153 if (searchFor.isEmpty()) { |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
154 Toolkit.getDefaultToolkit().beep() |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
155 origin = null |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
156 return |
f1fcc1281dad
Use BorderFactory; clean up Find dialog.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
157 } |
27 | 158 fun doFind(o: PasteboardQueue.Offset?) = queue.v.find(searchFor, |
159 direction = direction, foldCase = ignoreCase, origin = o) | |
160 var result = doFind(origin) | |
161 if (result == null && origin != null && autoWrap) { | |
162 result = doFind(null) | |
163 } | |
164 if (result == null) { | |
165 Toolkit.getDefaultToolkit().beep() | |
29
c4f53bc01732
Fix searching (and main display).
David Barts <n5jrn@me.com>
parents:
28
diff
changeset
|
166 origin = null |
c4f53bc01732
Fix searching (and main display).
David Barts <n5jrn@me.com>
parents:
28
diff
changeset
|
167 } else { |
c4f53bc01732
Fix searching (and main display).
David Barts <n5jrn@me.com>
parents:
28
diff
changeset
|
168 origin = when(direction) { |
c4f53bc01732
Fix searching (and main display).
David Barts <n5jrn@me.com>
parents:
28
diff
changeset
|
169 PasteboardQueue.Direction.FORWARDS -> |
c4f53bc01732
Fix searching (and main display).
David Barts <n5jrn@me.com>
parents:
28
diff
changeset
|
170 PasteboardQueue.Offset(result.inQueue, result.inItem + 1) |
c4f53bc01732
Fix searching (and main display).
David Barts <n5jrn@me.com>
parents:
28
diff
changeset
|
171 PasteboardQueue.Direction.BACKWARDS -> |
c4f53bc01732
Fix searching (and main display).
David Barts <n5jrn@me.com>
parents:
28
diff
changeset
|
172 if (result.inItem == 0) { |
c4f53bc01732
Fix searching (and main display).
David Barts <n5jrn@me.com>
parents:
28
diff
changeset
|
173 if (result.inQueue == 0) null else PasteboardQueue.Offset(result.inQueue - 1, -1) |
c4f53bc01732
Fix searching (and main display).
David Barts <n5jrn@me.com>
parents:
28
diff
changeset
|
174 } else { |
c4f53bc01732
Fix searching (and main display).
David Barts <n5jrn@me.com>
parents:
28
diff
changeset
|
175 PasteboardQueue.Offset(result.inQueue, result.inItem - 1) |
c4f53bc01732
Fix searching (and main display).
David Barts <n5jrn@me.com>
parents:
28
diff
changeset
|
176 } |
c4f53bc01732
Fix searching (and main display).
David Barts <n5jrn@me.com>
parents:
28
diff
changeset
|
177 } |
27 | 178 } |
179 } | |
180 | |
181 /* changing the search string resets the search origin */ | |
182 override fun changedUpdate(e: DocumentEvent) { | |
183 if (e.document === _searchFor.document) { | |
184 origin = null | |
185 } | |
186 } | |
187 override fun insertUpdate(e: DocumentEvent) = changedUpdate(e) | |
188 override fun removeUpdate(e: DocumentEvent) = changedUpdate(e) | |
189 } | |
190 | |
191 val searchDialog = SearchDialog() |