Mercurial > cgi-bin > hgweb.cgi > ClipMan
comparison src/name/blackcap/clipman/PasteboardQueue.kt @ 27:8aa2dfac27eb
Big reorg; compiled but untested.
author | David Barts <n5jrn@me.com> |
---|---|
date | Wed, 29 Jan 2020 10:50:07 -0800 |
parents | c10a447b9e1b |
children | c4f53bc01732 |
comparison
equal
deleted
inserted
replaced
26:ff35fabaea3a | 27:8aa2dfac27eb |
---|---|
9 import java.util.Collections | 9 import java.util.Collections |
10 import java.util.LinkedList | 10 import java.util.LinkedList |
11 import java.util.logging.Level | 11 import java.util.logging.Level |
12 import java.util.logging.Logger | 12 import java.util.logging.Logger |
13 import javax.swing.* | 13 import javax.swing.* |
14 import javax.swing.text.JTextComponent | 14 import javax.swing.text.DefaultHighlighter |
15 | 15 |
16 /** | 16 /** |
17 * A queue that tracks the data we display and the widgets used to | 17 * A queue that tracks the data we display and the widgets used to |
18 * display them. We never explicitly remove stuff from the queue, | 18 * display them. We never explicitly remove stuff from the queue, |
19 * though items will get silently discarded to prevent the queue from | 19 * though items will get silently discarded to prevent the queue from |
54 * Add a QueueItem to the end of the queue. | 54 * Add a QueueItem to the end of the queue. |
55 * @param item QueueItem to add | 55 * @param item QueueItem to add |
56 */ | 56 */ |
57 @Synchronized fun add(item: QueueItem) { | 57 @Synchronized fun add(item: QueueItem) { |
58 inSwingThread { | 58 inSwingThread { |
59 parent.add(item.component) | 59 parent.add(item.view.contents) |
60 scrollPane?.run { | 60 scrollPane?.run { |
61 validate() | 61 validate() |
62 verticalScrollBar.run { value = maximum + 1 } | 62 verticalScrollBar.run { value = maximum + 1 } |
63 } | 63 } |
64 } | 64 } |
65 queue.addLast(item) | 65 queue.addLast(item) |
66 truncate() | 66 truncate() |
67 } | |
68 | |
69 /** | |
70 * Delete something from the queue. | |
71 * @param object to delete | |
72 */ | |
73 @Synchronized fun delete(item: QueueItem) { | |
74 if (queue.remove(item)) { | |
75 parent.validate() | |
76 } | |
67 } | 77 } |
68 | 78 |
69 /** | 79 /** |
70 * Find and highlight the next occurrence of the specified string | 80 * Find and highlight the next occurrence of the specified string |
71 * @param string to search | 81 * @param string to search |
75 * @return position where start of string was found, or null | 85 * @return position where start of string was found, or null |
76 */ | 86 */ |
77 fun find(needle: String, direction: Direction = Direction.FORWARDS, | 87 fun find(needle: String, direction: Direction = Direction.FORWARDS, |
78 foldCase: Boolean = true, origin: Offset? = null): Offset? | 88 foldCase: Boolean = true, origin: Offset? = null): Offset? |
79 { | 89 { |
80 /* canonicalize the origin */ | 90 /* clean up any old highlights */ |
81 val norigin = if (origin == null) { | 91 queue.forEach { |
82 if (direction == Direction.FORWARDS) { | 92 val hiliter = it.view.searchable.highlighter |
83 Offset(0, 0) | 93 hiliter.highlights.forEach { |
84 } else { | 94 hiliter.removeHighlight(it) |
85 Offset(queue.size - 1, queue.last.searchable.document.length) | |
86 } | 95 } |
87 } else { | |
88 origin | |
89 } | 96 } |
90 | 97 |
91 /* XXX - not finished */ | 98 /* get starting item index */ |
99 val qMax = queue.size | |
100 var norigin = origin ?: when (direction) { | |
101 Direction.FORWARDS -> Offset(0, 0) | |
102 Direction.BACKWARDS -> Offset(qMax - 1, -1) | |
103 } | |
104 | |
105 /* loop initialization */ | |
106 val (start, incr, search) = if (direction == Direction.FORWARDS) { | |
107 Triple( 0, 1, { n: String, h: String, o: Int -> h.indexOf(n, o, foldCase) }) | |
108 } else { | |
109 Triple(-1, -1, { n: String, h: String, o: Int -> h.lastIndexOf(n, o, foldCase) }) | |
110 } | |
111 val painter = DefaultHighlighter.DefaultHighlightPainter(null); | |
112 var pos = -1 | |
113 | |
114 /* try and find it */ | |
115 while (norigin.inQueue >= 0 && norigin.inQueue < qMax) { | |
116 val si = queue.get(norigin.inQueue).view.searchable | |
117 val doc = si.document | |
118 val text = doc.getText(0, doc.length) | |
119 pos = if (norigin.inItem >= 0) norigin.inItem else text.length - 1 | |
120 pos = search(needle, text, pos) | |
121 if (pos >= 0) { | |
122 si.highlighter.addHighlight(pos, pos+needle.length, painter) | |
123 break | |
124 } | |
125 norigin = Offset(norigin.inQueue + incr, start) | |
126 } | |
127 return if (pos >= 0) Offset(norigin.inQueue, pos) else null | |
128 } | |
129 | |
130 /** | |
131 * Ensure none of the searchables in this queue are selected. | |
132 */ | |
133 fun deselectAll() { | |
134 queue.forEach { | |
135 val s = it.view.searchable as? ClipText | |
136 if (s != null && s.selected) { | |
137 s.selected = false | |
138 s.validate() | |
139 } | |
140 } | |
141 } | |
142 | |
143 /** | |
144 * Return the selected item, or null if nothing has been selected | |
145 */ | |
146 fun getSelected(): QueueItem? { | |
147 queue.forEach { | |
148 if ((it.view.searchable as? ClipText)?.selected ?: false) { | |
149 return it | |
150 } | |
151 } | |
92 return null | 152 return null |
93 } | 153 } |
94 | 154 |
95 private fun truncate() { | 155 private fun truncate() { |
96 if (_maxSize > 0) { | 156 if (_maxSize > 0) { |
97 var size = queue.size | 157 var size = queue.size |
98 var dirty = false | 158 var dirty = false |
99 while (size > _maxSize) { | 159 while (size > _maxSize) { |
100 var extra = queue.removeFirst().component | 160 var extra = queue.removeFirst().view |
101 inSwingThread { parent.remove(extra) } | 161 inSwingThread { |
162 if (extra.searchable.selected) { | |
163 SelectionRequired.disable() | |
164 } | |
165 parent.remove(extra.contents) | |
166 } | |
102 dirty = true | 167 dirty = true |
103 size -= 1 | 168 size -= 1 |
104 } | 169 } |
105 if (dirty) { | 170 if (dirty) { |
106 inSwingThread { parent.validate() } | 171 inSwingThread { parent.validate() } |
108 } | 173 } |
109 } | 174 } |
110 } | 175 } |
111 | 176 |
112 /** | 177 /** |
113 * An item in the above queue. | 178 * An item in the above queue. Linking model to view here sorta violates |
179 * MVC principles, but rules are sometimes best broken. Doing it this way | |
180 * makes it impossible for the view queue to fail to follow the data | |
181 * queue. | |
114 */ | 182 */ |
115 data class QueueItem( | 183 data class QueueItem(val contents: PasteboardItem, val view: PasteboardItemView) |
116 val component: JComponent, | |
117 val searchable: JTextComponent, | |
118 val contents: PasteboardItem) |