1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 package org.apache.openoffice.ooxml.viewer.xml; 23 24 import java.awt.Color; 25 import java.util.HashMap; 26 import java.util.Map; 27 28 import org.apache.openoffice.ooxml.viewer.tokenview.DocumentFactory; 29 import org.apache.openoffice.ooxml.viewer.tokenview.Style; 30 import org.apache.openoffice.ooxml.viewer.tokenview.TokenView; 31 32 public class DocumentTokenFormatter 33 { DocumentTokenFormatter( final XMLScanner aScanner, final TokenView<TokenType> aView)34 DocumentTokenFormatter ( 35 final XMLScanner aScanner, 36 final TokenView<TokenType> aView) 37 { 38 maScanner = aScanner; 39 maView = aView.GetDocumentFactory(); 40 41 maTagStartEndStyle = new Style().SetForegroundColor(new Color(0x87CEFA)); // Light Sky Blue 42 maNamespaceNameStyle = new Style().SetForegroundColor(new Color(0x7B68EE)); // Medium Slate Blue 43 maIdentifierStyle = new Style() 44 .SetForegroundColor(new Color(0x7B68EE)) // Medium Slate Blue 45 .SetBold(); 46 maTextStyle = new Style().SetForegroundColor(new Color(0xF08080)); // Light Coral 47 maAttributeValueStyle = new Style().SetForegroundColor(new Color(0xFFA07A)); // Light Salmon 48 49 msIndentation = ""; 50 51 maNamespaceMap = new HashMap<String,String>(); 52 } 53 54 55 56 Parse()57 public void Parse () 58 { 59 try 60 { 61 ParseIntro(); 62 AppendText("\n", TokenType.WHITESPACE, null, -1); 63 while (true) 64 { 65 switch (maScanner.Peek().Type) 66 { 67 case EOF: 68 return; 69 70 case TAG_START: 71 case END_TAG_START: 72 ParseTag(); 73 AppendText("\n", TokenType.WHITESPACE, null, -1); 74 break; 75 76 default: 77 ParseText(); 78 } 79 } 80 } 81 catch(final Exception aException) 82 { 83 aException.printStackTrace(); 84 } 85 maView.FinishText(); 86 } 87 88 89 90 GetNamespaceMap()91 Map<String,String> GetNamespaceMap () 92 { 93 return maNamespaceMap; 94 } 95 96 97 98 ParseIntro()99 private void ParseIntro () 100 { 101 final Token aStartToken = maScanner.Next(); 102 ExpectToken(aStartToken, TokenType.INTRO_START); 103 ShowToken(aStartToken); 104 105 ParseTagContent(); 106 107 final Token aEndToken = maScanner.Next(); 108 ExpectToken(aEndToken, TokenType.INTRO_END); 109 ShowToken(aEndToken); 110 } 111 112 113 114 ParseTag()115 private void ParseTag () 116 { 117 final Token aStartToken = maScanner.Next(); 118 ExpectToken(aStartToken, TokenType.TAG_START, TokenType.END_TAG_START); 119 if (aStartToken.Type == TokenType.TAG_START) 120 maView.BeginGroup(); 121 if (aStartToken.Type == TokenType.END_TAG_START) 122 DecreaseIndentation(); 123 ShowToken(aStartToken); 124 125 ParseTagContent(); 126 127 final Token aEndToken = maScanner.Next(); 128 if (aStartToken.Type == TokenType.TAG_START) 129 ExpectToken(aEndToken, TokenType.TAG_END, TokenType.ELEMENT_END); 130 else 131 ExpectToken(aEndToken, TokenType.TAG_END); 132 ShowToken(aEndToken); 133 134 if (aStartToken.Type != TokenType.END_TAG_START 135 && aEndToken.Type != TokenType.ELEMENT_END) 136 { 137 IncreaseIndentation(); 138 } 139 else 140 { 141 maView.EndGroup(); 142 } 143 } 144 145 146 147 ParseTagContent()148 private void ParseTagContent () 149 { 150 ParseQualifiedName(); 151 152 if (maScanner.Peek().Type != TokenType.IDENTIFIER) 153 return; 154 155 IncreaseIndentation(); 156 while (true) 157 { 158 final Token aToken = maScanner.Peek(); 159 if (aToken.Type != TokenType.IDENTIFIER) 160 break; 161 162 if (mbStartNewLineBeforeEachAttribute 163 || mbStartNewLineBeforeNamespaceDefinition && aToken.Text.startsWith("xmlns")) 164 { 165 AppendText("\n", TokenType.WHITESPACE, null, -1); 166 AppendText(" ", TokenType.WHITESPACE, null, -1); 167 } 168 else 169 { 170 AppendText(" ", TokenType.WHITESPACE, null, -1); 171 } 172 173 ParseQualifiedName(); 174 final Token aAssignToken = maScanner.Next(); 175 ExpectToken(aAssignToken, TokenType.ATTRIBUTE_DEFINE); 176 ShowToken(aAssignToken); 177 178 final Token aValueToken = maScanner.Next(); 179 ExpectToken(aValueToken, TokenType.ATTRIBUTE_VALUE); 180 ShowToken(aValueToken, maAttributeValueStyle); 181 182 if (msLastNamespaceName.equals("xmlns")) 183 SaveNamespaceDefinition(msLastName, StripValueQuotes(aValueToken.Text)); 184 } 185 DecreaseIndentation(); 186 } 187 188 189 190 ParseQualifiedName()191 private void ParseQualifiedName () 192 { 193 final Token aNameToken = maScanner.Next(); 194 ExpectToken(aNameToken, TokenType.IDENTIFIER); 195 if (maScanner.Peek().Type == TokenType.COLON) 196 { 197 final Token aSeparatorToken = maScanner.Next(); 198 final Token aSecondNameToken = maScanner.Next(); 199 ExpectToken(aSecondNameToken, TokenType.IDENTIFIER); 200 ShowToken(aNameToken, maNamespaceNameStyle); 201 ShowToken(aSeparatorToken); 202 ShowToken(aSecondNameToken, maIdentifierStyle); 203 204 msLastNamespaceName = aNameToken.Text; 205 msLastName = aSecondNameToken.Text; 206 } 207 else 208 { 209 ShowToken(aNameToken, maIdentifierStyle); 210 211 msLastNamespaceName = ""; 212 msLastName = aNameToken.Text; 213 } 214 } 215 216 217 218 ParseText()219 private void ParseText () 220 { 221 final Token aTextToken = maScanner.Next(); 222 ExpectToken(aTextToken, TokenType.TEXT); 223 ShowToken(aTextToken, maTextStyle); 224 AppendText("\n", TokenType.WHITESPACE, null, -1); 225 } 226 227 228 229 ExpectToken(final Token aToken, final TokenType ... aExcpectedTypes)230 private TokenType ExpectToken (final Token aToken, final TokenType ... aExcpectedTypes) 231 { 232 for (final TokenType eType : aExcpectedTypes) 233 if (aToken.Type == eType) 234 return eType; 235 236 if (aExcpectedTypes.length == 1) 237 { 238 throw new RuntimeException( 239 String.format( 240 "expected '%s' but got %s", 241 aExcpectedTypes[0].toString(), 242 aToken.toString())); 243 } 244 else 245 { 246 String sList = null; 247 for (final TokenType eType : aExcpectedTypes) 248 { 249 if (sList != null) 250 sList += String.format(", '%s'", eType.toString()); 251 else 252 sList = String.format("'%s'", eType.toString()); 253 } 254 throw new RuntimeException( 255 String.format( 256 "expected one of %s but got %s", 257 sList, 258 aToken.toString())); 259 } 260 } 261 262 263 264 ShowToken(final Token aToken)265 private void ShowToken (final Token aToken) 266 { 267 AppendText(aToken.Text, aToken.Type, GetStyle(aToken.Type), aToken.Offset); 268 } 269 270 271 272 ShowToken( final Token aToken, final Style aStyle)273 private void ShowToken ( 274 final Token aToken, 275 final Style aStyle) 276 { 277 AppendText(aToken.Text, aToken.Type, aStyle, aToken.Offset); 278 } 279 280 281 282 AppendText( final String sText, final TokenType eTokenType, final Style aStyle, final int nOffset)283 private void AppendText ( 284 final String sText, 285 final TokenType eTokenType, 286 final Style aStyle, 287 final int nOffset) 288 { 289 try 290 { 291 if (mbIsAtBeginningOfLine) 292 { 293 AddText(msIndentation, TokenType.WHITESPACE, aStyle, -1); 294 mbIsAtBeginningOfLine = false; 295 } 296 AddText(sText, eTokenType, aStyle, nOffset); 297 mbIsAtBeginningOfLine = sText.endsWith("\n"); 298 } 299 catch (RuntimeException e) 300 { 301 e.printStackTrace(); 302 } 303 } 304 305 306 307 AddText( final String sText, final TokenType eTokenType, final Style aStyle, final int nOffset)308 private void AddText ( 309 final String sText, 310 final TokenType eTokenType, 311 final Style aStyle, 312 final int nOffset) 313 { 314 maView.AddText(sText, eTokenType, aStyle, nOffset); 315 } 316 317 318 319 IncreaseIndentation()320 private void IncreaseIndentation () 321 { 322 msIndentation += " "; 323 } 324 325 326 327 DecreaseIndentation()328 private void DecreaseIndentation () 329 { 330 if ( ! msIndentation.isEmpty()) 331 msIndentation = msIndentation.substring(4); 332 } 333 334 335 336 GetStyle(final TokenType eType)337 private Style GetStyle (final TokenType eType) 338 { 339 switch(eType) 340 { 341 case TAG_START: 342 case TAG_END: 343 case END_TAG_START: 344 case INTRO_START: 345 case INTRO_END: 346 case ELEMENT_END: 347 return maTagStartEndStyle; 348 349 case IDENTIFIER: 350 return maIdentifierStyle; 351 352 case TEXT: 353 return maTextStyle; 354 355 case ATTRIBUTE_VALUE: 356 return maAttributeValueStyle; 357 358 default: 359 return null; 360 } 361 } 362 363 364 365 StripValueQuotes(final String sQuotedValue)366 private String StripValueQuotes (final String sQuotedValue) 367 { 368 final String sValue = sQuotedValue.substring(1, sQuotedValue.length()-1); 369 return sValue; 370 } 371 372 373 374 SaveNamespaceDefinition(final String sShortName, final String sLongName)375 private void SaveNamespaceDefinition (final String sShortName, final String sLongName) 376 { 377 maNamespaceMap.put(sShortName, sLongName); 378 } 379 380 381 382 383 private final XMLScanner maScanner; 384 private final DocumentFactory<TokenType> maView; 385 private final Style maTagStartEndStyle; 386 private final Style maNamespaceNameStyle; 387 private final Style maIdentifierStyle; 388 private final Style maTextStyle; 389 private final Style maAttributeValueStyle; 390 private String msIndentation; 391 private boolean mbIsAtBeginningOfLine; 392 393 private String msLastNamespaceName; 394 private String msLastName; 395 private Map<String,String> maNamespaceMap; 396 397 private final boolean mbStartNewLineBeforeEachAttribute = false; 398 private final boolean mbStartNewLineBeforeNamespaceDefinition = true; 399 } 400