source: trunk/src/org/expeditee/gio/swing/SwingTextLayoutManager.java@ 1415

Last change on this file since 1415 was 1415, checked in by bln4, 5 years ago

Renamed Frame.getItems() to Frame.getSortedItems() to better represent its functionality.

-> org.apollo.ApolloGestureActions
-> org.apollo.ApolloSystem
-> org.expeditee.actions.Actions
-> org.expeditee.actions.Debug
-> org.expeditee.actions.ExploratorySearchActions
-> org.expeditee.actions.JfxBrowserActions
-> org.expeditee.actions.Misc
-> org.expeditee.actions.Navigation
-> org.expeditee.actions.ScriptBase
-> org.expeditee.actions.Simple
-> org.expeditee.agents.ComputeTree
-> org.expeditee.agents.CopyTree
-> org.expeditee.agents.DisplayComet
-> org.expeditee.agents.DisplayTree
-> org.expeditee.agents.DisplayTreeLeaves
-> org.expeditee.agents.GraphFramesetLinks
-> org.expeditee.agents.TreeProcessor
-> org.expeditee.gio.gesture.StandardGestureActions
-> org.expeditee.gui.DisplayController
-> org.expeditee.gui.FrameCreator
-> org.expeditee.gui.FrameIO
-> org.expeditee.io.DefaultTreeWriter
-> org.expeditee.io.JavaWriter
-> org.expeditee.io.PDF2Writer
-> org.expeditee.io.TXTWriter
-> org.expeditee.io.WebParser
-> org.expeditee.io.flowlayout.XGroupItem
-> org.expeditee.items.Dot
-> org.expeditee.items.Item
-> org.expeditee.items.ItemUtils
-> org.expeditee.network.FrameShare
-> org.expeditee.stats.TreeStats


Created ItemsList class to wrap ArrayList<Item>. Frames now use this new class to store its body list (used for display) as well as its primaryBody and surrogateBody.

-> org.expeditee.agents.Format
-> org.expeditee.agents.HFormat
-> org.expeditee.gio.gesture.StandardGestureActions
-> org.expeditee.gui.Frame
-> org.expeditee.gui.FrameUtils


Refactorted Frame.setResort(bool) to Frame.invalidateSorted() to better function how it is intended to with a more accurate name.

-> org.expeditee.agents.Sort


When writing out .exp files and getting attributes to respond to LEFT + RIGHT click, boolean items are by default true. This has always been the case. An ammendment to this is that defaults can now be established.
Also added 'EnterClick' functionality. If cursored over a item with this property and you press enter, it acts as if you have clicked on it instead.

-> org.expeditee.assets.resources-public.framesets.authentication.1.exp to 6.exp
-> org.expeditee.gio.gesture.StandardGestureActions
-> org.expeditee.gio.input.KBMInputEvent
-> org.expeditee.gio.javafx.JavaFXConversions
-> org.expeditee.gio.swing.SwingConversions
-> org.expeditee.gui.AttributeUtils
-> org.expeditee.io.Conversion
-> org.expeditee.io.DefaultFrameWriter
-> org.expeditee.items.Item


Fixed a bug caused by calling Math.abs on Integer.MIN_VALUE returning unexpected result. Due to zero being a thing, you cannot represent Math.abs(Integer.MIN_VALUE) in a Integer object. The solution is to use Integer.MIN_VALUE + 1 instead of Integer.MIN_VALUE.

-> org.expeditee.core.bounds.CombinationBounds
-> org.expeditee.io.flowlayout.DimensionExtent


Recoded the contains function in EllipticalBounds so that intersection tests containing circles work correctly.

-> org.expeditee.core.bounds.EllipticalBounds


Added toString() to PolygonBounds to allow for useful printing during debugging.

-> org.expeditee.core.bounds.PolygonBounds

Implemented Surrogate Mode!

-> org.expeditee.encryption.io.EncryptedExpReader
-> org.expeditee.encryption.io.EncryptedExpWriter
-> org.expeditee.encryption.items.surrogates.EncryptionDetail
-> org.expeditee.encryption.items.surrogates.Label
-> org.expeditee.gui.FrameUtils
-> org.expeditee.gui.ItemsList
-> org.expeditee.items.Item
-> org.expeditee.items.Text


???? Use Integer.MAX_VALUE cast to a float instead of Float.MAX_VALUE. This fixed some bug which I cannot remember.

-> org.expeditee.gio.TextLayoutManager
-> org.expeditee.gio.swing.SwingTextLayoutManager


Improved solution for dealing with the F10 key taking focus away from Expeditee due to it being a assessibility key.

-> org.expeditee.gio.swing.SwingInputManager


Renamed variable visibleItems in FrameGraphics.paintFrame to itemsToPaintCanditates to better represent functional intent.

-> org.expeditee.gui.FrameGraphics


Improved checking for if personal resources exist before recreating them

-> org.expeditee.gui.FrameIO


Repeated messages to message bay now have a visual feedback instead of just a beep. This visual feedback is in the form of a count of the amount of times it has repeated.

-> org.expeditee.gui.MessageBay


Updated comment on the Vector class to explain what vectors are.

-> org.expeditee.gui.Vector


Added constants to represent all of the property keys in DefaultFrameReader and DefaultFrameWriter.

-> org.expeditee.io.DefaultFrameReader
-> org.expeditee.io.DefaultFrameWriter


Updated the KeyList setting to be more heirarcial with how users will store their Secrets.

-> org.expeditee.settings.identity.secrets.KeyList

File size: 8.4 KB
Line 
1package org.expeditee.gio.swing;
2
3import java.awt.Rectangle;
4import java.awt.font.FontRenderContext;
5import java.awt.font.LineBreakMeasurer;
6import java.awt.font.TextAttribute;
7import java.text.AttributedString;
8import java.util.HashMap;
9import java.util.LinkedList;
10import java.util.List;
11
12import org.expeditee.core.Font;
13import org.expeditee.core.Line;
14import org.expeditee.core.Point;
15import org.expeditee.core.TextHitInfo;
16import org.expeditee.core.TextLayout;
17import org.expeditee.core.bounds.AxisAlignedBoxBounds;
18import org.expeditee.gio.TextLayoutManager;
19
20/**
21 * TODO: Comment. cts16
22 *
23 * @author cts16
24 */
25public class SwingTextLayoutManager extends TextLayoutManager
26{
27 /** Singleton instance. */
28 private static SwingTextLayoutManager _instance = null;
29
30 /** Singleton instantiator. */
31 public static SwingTextLayoutManager getInstance()
32 {
33 if (_instance == null) {
34 _instance = new SwingTextLayoutManager();
35 }
36
37 return _instance;
38 }
39
40 /** Mapping from Expeditee text-layout objects to swing equivalents. */
41 private HashMap<Long, java.awt.font.TextLayout> _layoutMap;
42
43 private SwingTextLayoutManager()
44 {
45 _layoutMap = new HashMap<Long, java.awt.font.TextLayout>();
46 }
47
48 private synchronized void register(TextLayout layout, java.awt.font.TextLayout swingLayout)
49 {
50 if (layout == null || swingLayout == null) {
51 return;
52 }
53
54 _layoutMap.put(layout.getHandle(), swingLayout);
55 }
56
57 public synchronized java.awt.font.TextLayout getInternalLayout(TextLayout layout)
58 {
59 if (!isTextLayoutValid(layout)) {
60 return null;
61 }
62
63 return _layoutMap.get(layout.getHandle());
64 }
65
66 public synchronized boolean isTextLayoutValid(TextLayout layout)
67 {
68 if (layout == null) {
69 return false;
70 }
71
72 return _layoutMap.containsKey(layout.getHandle());
73 }
74
75 @Override
76 public float getAdvance(TextLayout layout)
77 {
78 if (!isTextLayoutValid(layout)) {
79 return Float.NaN;
80 }
81
82 return getInternalLayout(layout).getAdvance();
83 }
84
85 @Override
86 public int getCharacterCount(TextLayout layout)
87 {
88 if (!isTextLayoutValid(layout)) {
89 return 0;
90 }
91
92 return getInternalLayout(layout).getCharacterCount();
93 }
94
95 @Override
96 public TextHitInfo getNextLeftHit(TextLayout layout, int offset)
97 {
98 if (!isTextLayoutValid(layout)) {
99 return null;
100 }
101
102 return SwingConversions.fromSwingTextHitInfo(getInternalLayout(layout).getNextLeftHit(offset));
103 }
104
105 @Override
106 public TextHitInfo getNextLeftHit(TextLayout layout, TextHitInfo hit)
107 {
108 if (!isTextLayoutValid(layout)) {
109 return null;
110 }
111
112 return SwingConversions.fromSwingTextHitInfo(getInternalLayout(layout).getNextLeftHit(SwingConversions.toSwingTextHitInfo(hit)));
113 }
114
115 @Override
116 public TextHitInfo getNextRightHit(TextLayout layout, int offset)
117 {
118 if (!isTextLayoutValid(layout)) {
119 return null;
120 }
121
122 return SwingConversions.fromSwingTextHitInfo(getInternalLayout(layout).getNextRightHit(offset));
123 }
124
125 @Override
126 public TextHitInfo getNextRightHit(TextLayout layout, TextHitInfo hit)
127 {
128 if (!isTextLayoutValid(layout)) {
129 return null;
130 }
131
132 return SwingConversions.fromSwingTextHitInfo(getInternalLayout(layout).getNextRightHit(SwingConversions.toSwingTextHitInfo(hit)));
133 }
134
135 @Override
136 public float[] getCaretInfo(TextLayout layout, TextHitInfo hit) {
137 if (!isTextLayoutValid(layout)) {
138 return null;
139 }
140
141 return getInternalLayout(layout).getCaretInfo(SwingConversions.toSwingTextHitInfo(hit));
142 }
143
144 @Override
145 public TextHitInfo hitTestChar(TextLayout layout, float x, float y)
146 {
147 if (!isTextLayoutValid(layout)) {
148 return null;
149 }
150
151 return SwingConversions.fromSwingTextHitInfo(getInternalLayout(layout).hitTestChar(x, y));
152 }
153
154 @Override
155 public AxisAlignedBoxBounds getPixelBounds(TextLayout layout, float x, float y)
156 {
157 if (!isTextLayoutValid(layout)) {
158 return null;
159 }
160
161 return SwingConversions.fromSwingRectangle(getInternalLayout(layout).getPixelBounds(null, x, y));
162 }
163
164 @Override
165 public AxisAlignedBoxBounds getLogicalHighlightShape(TextLayout layout, int firstEndpoint, int secondEndpoint)
166 {
167 if (!isTextLayoutValid(layout)) {
168 return null;
169 }
170
171 Rectangle rect = getInternalLayout(layout).getLogicalHighlightShape(firstEndpoint, secondEndpoint).getBounds();
172
173 return SwingConversions.fromSwingRectangle(rect);
174 }
175
176 @Override
177 public float getAscent(TextLayout layout)
178 {
179 if (!isTextLayoutValid(layout)) {
180 return Float.NaN;
181 }
182
183 return getInternalLayout(layout).getAscent();
184 }
185
186 @Override
187 public float getDescent(TextLayout layout)
188 {
189 if (!isTextLayoutValid(layout)) {
190 return Float.NaN;
191 }
192
193 return getInternalLayout(layout).getDescent();
194 }
195
196 @Override
197 public float getLeading(TextLayout layout)
198 {
199 if (!isTextLayoutValid(layout)) {
200 return Float.NaN;
201 }
202
203 return getInternalLayout(layout).getLeading();
204 }
205
206 @Override
207 public synchronized void releaseLayout(TextLayout layout)
208 {
209 if (!isTextLayoutValid(layout)) {
210 return;
211 }
212
213 _layoutMap.remove(layout.getHandle());
214 }
215
216 @Override
217 public List<TextLayout> layoutString(String string, Font font, Point start, Line[] lineBreakers, int widthLimit, int lineSpacing, boolean dontBreakWords, boolean fullJustify)
218 {
219 if (string == null || font == null || start == null) {
220 return null;
221 }
222
223 // Make sure we have a swing font to use
224 java.awt.Font swingFont;
225 SwingFontManager fontManager = SwingMiscManager.getIfUsingSwingFontManager();
226 if (fontManager == null) {
227 return null;
228 }
229 swingFont = fontManager.getInternalFont(font);
230 if (swingFont == null) {
231 return null;
232 }
233
234 // Temporary list to accumulate the TextLayouts in to
235 List<java.awt.font.TextLayout> layouts = new LinkedList<java.awt.font.TextLayout>();
236 List<Integer> offsets = new LinkedList<Integer>();
237 offsets.add(0);
238 List<Point> positions = new LinkedList<Point>();
239 positions.add(new Point(start));
240
241 // Set up a line-break measurer to layout the text
242 AttributedString paragraphText = new AttributedString(string);
243 paragraphText.addAttribute(TextAttribute.FONT, swingFont);
244 FontRenderContext frc = new FontRenderContext(null, true, true);
245 LineBreakMeasurer lineBreaker = new LineBreakMeasurer(paragraphText.getIterator(), frc);
246 lineBreaker.setPosition(0);
247
248 // Keep laying out text until the input string is completely laid out
249 while (lineBreaker.getPosition() < string.length()) {
250
251 int width = widthLimit;
252 if (lineBreakers != null) {
253 width = Math.min(width, (int) getLineWidth(start, lineBreakers));
254 }
255
256 int end = string.length();
257 for (int i = lineBreaker.getPosition() + 1; i < string.length(); i++) {
258 if (string.charAt(i) == '\n') {
259 end = i;
260 break;
261 }
262 }
263
264 java.awt.font.TextLayout layout = null;
265
266 try {
267 layout = lineBreaker.nextLayout(width, end, dontBreakWords);
268 } catch (ArrayIndexOutOfBoundsException e) {
269 e.printStackTrace();
270 }
271
272 // If it's impossible to layout any more text without breaking a word, just do it
273 if (layout == null && width == widthLimit) {
274 layout = lineBreaker.nextLayout(width, end, false);
275 // If still impossible, give up
276
277 if (layout == null) {
278 break;
279 }
280 }
281
282 if (fullJustify && lineBreaker.getPosition() < string.length()) {
283 layout = layout.getJustifiedLayout(width);
284 }
285
286 layouts.add(layout);
287 offsets.add(lineBreaker.getPosition());
288 int lineDrop = (int) (layout.getAscent() + layout.getDescent());
289 if (lineSpacing >= 0) {
290 lineDrop += lineSpacing;
291 } else {
292 lineDrop += layout.getLeading();
293 }
294 start.setY(start.getY() + lineDrop);
295 positions.add(new Point(start));
296 }
297
298 // Convert the accumulated list into an internal-type array
299 List<TextLayout> ret = new LinkedList<TextLayout>();
300 for (int i = 0; i < layouts.size(); i++) {
301 java.awt.font.TextLayout swingLayout = layouts.get(i);
302 int startCharIndex = offsets.get(i);
303 int endCharIndex = offsets.get(i + 1) - 1;
304 String line = string.substring(startCharIndex, endCharIndex + 1);
305 TextLayout layout = TextLayout.get(line, font, startCharIndex, endCharIndex);
306 register(layout, swingLayout);
307 ret.add(layout);
308 }
309
310 return ret;
311
312 }
313
314 @Override
315 public int getStringWidth(Font font, String string)
316 {
317 SwingGraphicsManager g = SwingMiscManager.getIfUsingSwingGraphicsManager();
318 SwingFontManager f = SwingMiscManager.getIfUsingSwingFontManager();
319
320 if (g == null || f == null) {
321 return -1;
322 }
323
324 if (font != null) {
325 return g.getFontMetrics(f.getInternalFont(font)).stringWidth(string);
326 } else {
327 return g.getFontMetrics(f.getInternalFont(f.getDefaultFont())).stringWidth(string);
328 }
329
330 }
331
332}
Note: See TracBrowser for help on using the repository browser.