1 package org.apache.maven.doxia.sink.impl;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.Collections;
23 import java.util.Enumeration;
24 import java.util.LinkedHashMap;
25 import java.util.Map;
26
27 import javax.swing.text.AttributeSet;
28
29 import org.apache.maven.doxia.sink.SinkEventAttributes;
30
31
32
33
34
35
36
37 public class SinkEventAttributeSet
38 implements SinkEventAttributes, Cloneable
39 {
40
41
42
43 public static final SinkEventAttributes UNDERLINE;
44
45
46
47
48 public static final SinkEventAttributes OVERLINE;
49
50
51
52
53 public static final SinkEventAttributes LINETHROUGH;
54
55
56
57
58 public static final SinkEventAttributes BOXED;
59
60
61
62
63 public static final SinkEventAttributes BOLD;
64
65
66
67
68 public static final SinkEventAttributes ITALIC;
69
70
71
72
73 public static final SinkEventAttributes MONOSPACED;
74
75
76
77
78 public static final SinkEventAttributes LEFT;
79
80
81
82
83 public static final SinkEventAttributes RIGHT;
84
85
86
87
88 public static final SinkEventAttributes CENTER;
89
90
91
92
93 public static final SinkEventAttributes JUSTIFY;
94
95
96 static
97 {
98 UNDERLINE = new SinkEventAttributeSet( DECORATION, "underline" ).unmodifiable();
99 OVERLINE = new SinkEventAttributeSet( DECORATION, "overline" ).unmodifiable();
100 LINETHROUGH = new SinkEventAttributeSet( DECORATION, "line-through" ).unmodifiable();
101 BOXED = new SinkEventAttributeSet( DECORATION, "boxed" ).unmodifiable();
102
103 BOLD = new SinkEventAttributeSet( STYLE, "bold" ).unmodifiable();
104 ITALIC = new SinkEventAttributeSet( STYLE, "italic" ).unmodifiable();
105 MONOSPACED = new SinkEventAttributeSet( STYLE, "monospaced" ).unmodifiable();
106
107 LEFT = new SinkEventAttributeSet( ALIGN, "left" ).unmodifiable();
108 RIGHT = new SinkEventAttributeSet( ALIGN, "right" ).unmodifiable();
109 CENTER = new SinkEventAttributeSet( ALIGN, "center" ).unmodifiable();
110 JUSTIFY = new SinkEventAttributeSet( ALIGN, "justify" ).unmodifiable();
111 }
112
113 private Map<String, Object> attribs;
114
115 private AttributeSet resolveParent;
116
117
118
119
120 public SinkEventAttributeSet()
121 {
122 this( 5 );
123 }
124
125
126
127
128
129
130 public SinkEventAttributeSet( int size )
131 {
132 attribs = new LinkedHashMap<>( size );
133 }
134
135
136
137
138
139
140
141
142 public SinkEventAttributeSet( String... attributes )
143 {
144 int n = attributes.length;
145
146 if ( ( n % 2 ) != 0 )
147 {
148 throw new IllegalArgumentException( "Missing attribute!" );
149 }
150
151 attribs = new LinkedHashMap<>( n / 2 );
152
153 for ( int i = 0; i < n; i += 2 )
154 {
155 attribs.put( attributes[i], attributes[i + 1] );
156 }
157 }
158
159
160
161
162
163
164
165 public SinkEventAttributeSet( AttributeSet attributes )
166 {
167 attribs = new LinkedHashMap<>( attributes.getAttributeCount() );
168
169 Enumeration<?> names = attributes.getAttributeNames();
170
171 while ( names.hasMoreElements() )
172 {
173 Object name = names.nextElement();
174
175 attribs.put( name.toString(), attributes.getAttribute( name ) );
176 }
177 }
178
179
180
181
182
183
184
185
186
187 public SinkEventAttributeSet unmodifiable()
188 {
189 this.attribs = Collections.unmodifiableMap( attribs );
190
191 return this;
192 }
193
194
195
196
197
198
199 public boolean isEmpty()
200 {
201 return attribs.isEmpty();
202 }
203
204
205
206
207
208
209 public int getAttributeCount()
210 {
211 return attribs.size();
212 }
213
214
215 public boolean isDefined( Object attrName )
216 {
217 return attribs.containsKey( attrName );
218 }
219
220
221 public boolean isEqual( AttributeSet attr )
222 {
223 return ( ( getAttributeCount() == attr.getAttributeCount() )
224 && containsAttributes( attr ) );
225 }
226
227
228
229
230
231
232 public AttributeSet copyAttributes()
233 {
234 return ( (AttributeSet) clone() );
235 }
236
237
238
239
240
241
242 public Enumeration<String> getAttributeNames()
243 {
244 return Collections.enumeration( attribs.keySet() );
245 }
246
247
248 public Object getAttribute( Object key )
249 {
250 Object value = attribs.get( key );
251
252 if ( value == null )
253 {
254 AttributeSet parent = getResolveParent();
255
256 if ( parent != null )
257 {
258 value = parent.getAttribute( key );
259 }
260 }
261
262 return value;
263 }
264
265
266 public boolean containsAttribute( Object name, Object value )
267 {
268 return value.equals( getAttribute( name ) );
269 }
270
271
272 public boolean containsAttributes( AttributeSet attributes )
273 {
274 boolean result = true;
275
276 Enumeration<?> names = attributes.getAttributeNames();
277
278 while ( result && names.hasMoreElements() )
279 {
280 Object name = names.nextElement();
281 result = attributes.getAttribute( name ).equals( getAttribute( name ) );
282 }
283
284 return result;
285 }
286
287
288
289
290
291
292 public void addAttribute( Object name, Object value )
293 {
294 attribs.put( name.toString(), value );
295 }
296
297
298 public void addAttributes( AttributeSet attributes )
299 {
300 if ( attributes == null || attributes.getAttributeCount() == 0 )
301 {
302 return;
303 }
304
305 Enumeration<?> names = attributes.getAttributeNames();
306
307 while ( names.hasMoreElements() )
308 {
309 Object name = names.nextElement();
310
311 addAttribute( name, attributes.getAttribute( name ) );
312 }
313 }
314
315
316 public void removeAttribute( Object name )
317 {
318 attribs.remove( name );
319 }
320
321
322 public void removeAttributes( Enumeration<?> names )
323 {
324 while ( names.hasMoreElements() )
325 {
326 removeAttribute( names.nextElement() );
327 }
328 }
329
330
331
332
333
334
335 public void removeAttributes( AttributeSet attributes )
336 {
337 if ( attributes == null )
338 {
339 return;
340 }
341 else if ( attributes == this )
342 {
343 attribs.clear();
344 }
345 else
346 {
347 Enumeration<?> names = attributes.getAttributeNames();
348
349 while ( names.hasMoreElements() )
350 {
351 Object name = names.nextElement();
352 Object value = attributes.getAttribute( name );
353
354 if ( value.equals( getAttribute( name ) ) )
355 {
356 removeAttribute( name );
357 }
358 }
359 }
360 }
361
362
363
364
365
366
367 public AttributeSet getResolveParent()
368 {
369 return this.resolveParent;
370 }
371
372
373 public void setResolveParent( AttributeSet parent )
374 {
375 this.resolveParent = parent;
376 }
377
378
379 @Override
380 public Object clone()
381 {
382 SinkEventAttributeSet attr = new SinkEventAttributeSet( attribs.size() );
383 attr.attribs = new LinkedHashMap<>( attribs );
384
385 if ( resolveParent != null )
386 {
387 attr.resolveParent = resolveParent.copyAttributes();
388 }
389
390 return attr;
391 }
392
393
394 @Override
395 public int hashCode()
396 {
397 final int parentHash = ( resolveParent == null ? 0 : resolveParent.hashCode() );
398
399 return attribs.hashCode() + parentHash;
400 }
401
402
403 @Override
404 public boolean equals( Object obj )
405 {
406 if ( this == obj )
407 {
408 return true;
409 }
410
411 if ( obj instanceof SinkEventAttributeSet )
412 {
413 return isEqual( (SinkEventAttributeSet) obj );
414 }
415
416 return false;
417 }
418
419
420 @Override
421 public String toString()
422 {
423 StringBuilder s = new StringBuilder();
424 Enumeration<String> names = getAttributeNames();
425
426 while ( names.hasMoreElements() )
427 {
428 String key = names.nextElement();
429 String value = getAttribute( key ).toString();
430
431 s.append( ' ' ).append( key ).append( '=' ).append( value );
432 }
433
434 return s.toString();
435 }
436
437
438
439
440 public static class Semantics
441 {
442
443
444
445 public static final SinkEventAttributes EMPHASIS;
446
447
448
449
450 public static final SinkEventAttributes STRONG;
451
452
453
454
455 public static final SinkEventAttributes SMALL;
456
457
458
459
460 public static final SinkEventAttributes LINE_THROUGH;
461
462
463
464
465 public static final SinkEventAttributes CITATION;
466
467
468
469
470 public static final SinkEventAttributes QUOTE;
471
472
473
474
475 public static final SinkEventAttributes DEFINITION;
476
477
478
479
480 public static final SinkEventAttributes ABBREVIATION;
481
482
483
484
485 public static final SinkEventAttributes ITALIC;
486
487
488
489
490 public static final SinkEventAttributes BOLD;
491
492
493
494
495 public static final SinkEventAttributes MONOSPACED;
496
497
498
499
500 public static final SinkEventAttributes CODE;
501
502
503
504
505 public static final SinkEventAttributes VARIABLE;
506
507
508
509
510 public static final SinkEventAttributes SAMPLE;
511
512
513
514
515 public static final SinkEventAttributes KEYBOARD;
516
517
518
519
520 public static final SinkEventAttributes SUPERSCRIPT;
521
522
523
524
525 public static final SinkEventAttributes SUBSCRIPT;
526
527
528
529
530 public static final SinkEventAttributes ANNOTATION;
531
532
533
534
535 public static final SinkEventAttributes HIGHLIGHT;
536
537
538
539
540 public static final SinkEventAttributes RUBY;
541
542
543
544
545 public static final SinkEventAttributes RUBY_BASE;
546
547
548
549
550 public static final SinkEventAttributes RUBY_TEXT;
551
552
553
554
555 public static final SinkEventAttributes RUBY_TEXT_CONTAINER;
556
557
558
559
560 public static final SinkEventAttributes RUBY_PARANTHESES;
561
562
563
564
565 public static final SinkEventAttributes BIDIRECTIONAL_ISOLATION;
566
567
568
569
570 public static final SinkEventAttributes BIDIRECTIONAL_OVERRIDE;
571
572
573
574
575 public static final SinkEventAttributes PHRASE;
576
577
578
579
580 public static final SinkEventAttributes INSERT;
581
582
583
584
585 public static final SinkEventAttributes DELETE;
586
587 static
588 {
589 EMPHASIS = new SinkEventAttributeSet( SEMANTICS, "emphasis" ).unmodifiable();
590 STRONG = new SinkEventAttributeSet( SEMANTICS, "strong" ).unmodifiable();
591 SMALL = new SinkEventAttributeSet( SEMANTICS, "small" ).unmodifiable();
592 LINE_THROUGH = new SinkEventAttributeSet( SEMANTICS, "line-through" ).unmodifiable();
593 CITATION = new SinkEventAttributeSet( SEMANTICS, "citation" ).unmodifiable();
594 QUOTE = new SinkEventAttributeSet( SEMANTICS, "quote" ).unmodifiable();
595 DEFINITION = new SinkEventAttributeSet( SEMANTICS, "definition" ).unmodifiable();
596 ABBREVIATION = new SinkEventAttributeSet( SEMANTICS, "abbreviation" ).unmodifiable();
597 ITALIC = new SinkEventAttributeSet( SEMANTICS, "italic" ).unmodifiable();
598 BOLD = new SinkEventAttributeSet( SEMANTICS, "bold" ).unmodifiable();
599 MONOSPACED = new SinkEventAttributeSet( SEMANTICS, "monospaced" ).unmodifiable();
600 CODE = new SinkEventAttributeSet( SEMANTICS, "code" ).unmodifiable();
601 VARIABLE = new SinkEventAttributeSet( SEMANTICS, "variable" ).unmodifiable();
602 SAMPLE = new SinkEventAttributeSet( SEMANTICS, "sample" ).unmodifiable();
603 KEYBOARD = new SinkEventAttributeSet( SEMANTICS, "keyboard" ).unmodifiable();
604 SUPERSCRIPT = new SinkEventAttributeSet( SEMANTICS, "superscript" ).unmodifiable();
605 SUBSCRIPT = new SinkEventAttributeSet( SEMANTICS, "subscript" ).unmodifiable();
606 ANNOTATION = new SinkEventAttributeSet( SEMANTICS, "annotation" ).unmodifiable();
607 HIGHLIGHT = new SinkEventAttributeSet( SEMANTICS, "highlight" ).unmodifiable();
608 RUBY = new SinkEventAttributeSet( SEMANTICS, "ruby" ).unmodifiable();
609 RUBY_BASE = new SinkEventAttributeSet( SEMANTICS, "rubyBase" ).unmodifiable();
610 RUBY_TEXT = new SinkEventAttributeSet( SEMANTICS, "rubyText" ).unmodifiable();
611 RUBY_TEXT_CONTAINER = new SinkEventAttributeSet( SEMANTICS, "rubyTextContainer" ).unmodifiable();
612 RUBY_PARANTHESES = new SinkEventAttributeSet( SEMANTICS, "rubyParentheses" ).unmodifiable();
613 BIDIRECTIONAL_ISOLATION = new SinkEventAttributeSet( SEMANTICS, "bidirectionalIsolation" ).unmodifiable();
614 BIDIRECTIONAL_OVERRIDE = new SinkEventAttributeSet( SEMANTICS, "bidirectionalOverride" ).unmodifiable();
615 PHRASE = new SinkEventAttributeSet( SEMANTICS, "phrase" ).unmodifiable();
616 INSERT = new SinkEventAttributeSet( SEMANTICS, "insert" ).unmodifiable();
617 DELETE = new SinkEventAttributeSet( SEMANTICS, "delete" ).unmodifiable();
618 }
619 }
620 }