| 1 | /* |
| 2 | GNU Lesser General Public License |
| 3 | |
| 4 | HTMLUtilities - Special Utility Functions For Ekit |
| 5 | Copyright (C) 2003 Rafael Cieplinski & Howard Kistler |
| 6 | |
| 7 | This library is free software; you can redistribute it and/or |
| 8 | modify it under the terms of the GNU Lesser General Public |
| 9 | License as published by the Free Software Foundation; either |
| 10 | version 2.1 of the License, or (at your option) any later version. |
| 11 | |
| 12 | This library is distributed in the hope that it will be useful, |
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 | Lesser General Public License for more details. |
| 16 | |
| 17 | You should have received a copy of the GNU Lesser General Public |
| 18 | License along with this library; if not, write to the Free Software |
| 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 20 | */ |
| 21 | |
| 22 | package com.hexidec.ekit.component; |
| 23 | |
| 24 | import java.io.*; |
| 25 | import java.lang.reflect.*; |
| 26 | import java.util.*; |
| 27 | import javax.swing.*; |
| 28 | import javax.swing.text.*; |
| 29 | import javax.swing.text.html.*; |
| 30 | |
| 31 | import com.hexidec.ekit.EkitCore; |
| 32 | import com.hexidec.ekit.component.*; |
| 33 | |
| 34 | public class HTMLUtilities |
| 35 | { |
| 36 | EkitCore parent; |
| 37 | Hashtable tags = new Hashtable(); |
| 38 | |
| 39 | public HTMLUtilities(EkitCore newParent) |
| 40 | { |
| 41 | parent = newParent; |
| 42 | HTML.Tag[] tagList = HTML.getAllTags(); |
| 43 | for(int i = 0; i < tagList.length; i++) |
| 44 | { |
| 45 | tags.put(tagList[i].toString(), tagList[i]); |
| 46 | } |
| 47 | /* |
| 48 | HTML.Tag classTag = new HTML.Tag(); |
| 49 | Field[] fields = classTag.getClass().getDeclaredFields(); |
| 50 | for(int i = 0; i < fields.length; i++) |
| 51 | { |
| 52 | try |
| 53 | { |
| 54 | System.out.println("Adding " + (String)fields[i].get(null).toString() + " => " + (HTML.Tag)fields[i].get(null)); |
| 55 | tags.put((String)fields[i].get(null).toString(), (HTML.Tag)fields[i].get(null)); |
| 56 | } |
| 57 | catch (IllegalAccessException iae) |
| 58 | { |
| 59 | } |
| 60 | } |
| 61 | */ |
| 62 | } |
| 63 | |
| 64 | /** Diese Methode fügt durch String-Manipulation in jtpSource |
| 65 | * ein neues Listenelement hinzu, content ist dabei der Text der in dem neuen |
| 66 | * Element stehen soll |
| 67 | */ |
| 68 | public void insertListElement(String content) |
| 69 | { |
| 70 | int pos = parent.getCaretPosition(); |
| 71 | String source = parent.getSourcePane().getText(); |
| 72 | boolean hit = false; |
| 73 | String idString; |
| 74 | int counter = 0; |
| 75 | do |
| 76 | { |
| 77 | hit = false; |
| 78 | idString = "diesisteineidzumsuchenimsource" + counter; |
| 79 | if(source.indexOf(idString) > -1) |
| 80 | { |
| 81 | counter++; |
| 82 | hit = true; |
| 83 | if(counter > 10000) |
| 84 | { |
| 85 | return; |
| 86 | } |
| 87 | } |
| 88 | } while(hit); |
| 89 | Element element = getListItemParent(); |
| 90 | if(element == null) |
| 91 | { |
| 92 | return; |
| 93 | } |
| 94 | SimpleAttributeSet sa = new SimpleAttributeSet(element.getAttributes()); |
| 95 | sa.addAttribute("id", idString); |
| 96 | parent.getExtendedHtmlDoc().replaceAttributes(element, sa, HTML.Tag.LI); |
| 97 | parent.refreshOnUpdate(); |
| 98 | source = parent.getSourcePane().getText(); |
| 99 | StringBuffer newHtmlString = new StringBuffer(); |
| 100 | int[] positions = getPositions(element, source, true, idString); |
| 101 | newHtmlString.append(source.substring(0, positions[3])); |
| 102 | newHtmlString.append("<li>"); |
| 103 | newHtmlString.append(content); |
| 104 | newHtmlString.append("</li>"); |
| 105 | newHtmlString.append(source.substring(positions[3] + 1, source.length())); |
| 106 | parent.getTextPane().setText(newHtmlString.toString()); |
| 107 | parent.refreshOnUpdate(); |
| 108 | parent.setCaretPosition(pos - 1); |
| 109 | element = getListItemParent(); |
| 110 | sa = new SimpleAttributeSet(element.getAttributes()); |
| 111 | sa = removeAttributeByKey(sa, "id"); |
| 112 | parent.getExtendedHtmlDoc().replaceAttributes(element, sa, HTML.Tag.LI); |
| 113 | } |
| 114 | |
| 115 | /** Diese Methode löscht durch Stringmanipulation in jtpSource das übergebene Element, |
| 116 | * Alternative für removeElement in ExtendedHTMLDocument, mit closingTag wird angegeben |
| 117 | * ob es ein schließenden Tag gibt |
| 118 | */ |
| 119 | public void removeTag(Element element, boolean closingTag) |
| 120 | { |
| 121 | if(element == null) |
| 122 | { |
| 123 | return; |
| 124 | } |
| 125 | int pos = parent.getCaretPosition(); |
| 126 | HTML.Tag tag = getHTMLTag(element); |
| 127 | // Versieht den Tag mit einer einmaligen ID |
| 128 | String source = parent.getSourcePane().getText(); |
| 129 | boolean hit = false; |
| 130 | String idString; |
| 131 | int counter = 0; |
| 132 | do |
| 133 | { |
| 134 | hit = false; |
| 135 | idString = "diesisteineidzumsuchenimsource" + counter; |
| 136 | if(source.indexOf(idString) > -1) |
| 137 | { |
| 138 | counter++; |
| 139 | hit = true; |
| 140 | if(counter > 10000) |
| 141 | { |
| 142 | return; |
| 143 | } |
| 144 | } |
| 145 | } while(hit); |
| 146 | SimpleAttributeSet sa = new SimpleAttributeSet(element.getAttributes()); |
| 147 | sa.addAttribute("id", idString); |
| 148 | parent.getExtendedHtmlDoc().replaceAttributes(element, sa, tag); |
| 149 | parent.refreshOnUpdate(); |
| 150 | source = parent.getSourcePane().getText(); |
| 151 | StringBuffer newHtmlString = new StringBuffer(); |
| 152 | int[] position = getPositions(element, source, closingTag, idString); |
| 153 | if(position == null) |
| 154 | { |
| 155 | return; |
| 156 | } |
| 157 | for(int i = 0; i < position.length; i++) |
| 158 | { |
| 159 | if(position[i] < 0) |
| 160 | { |
| 161 | return; |
| 162 | } |
| 163 | } |
| 164 | int beginStartTag = position[0]; |
| 165 | int endStartTag = position[1]; |
| 166 | if(closingTag) |
| 167 | { |
| 168 | int beginEndTag = position[2]; |
| 169 | int endEndTag = position[3]; |
| 170 | newHtmlString.append(source.substring(0, beginStartTag)); |
| 171 | newHtmlString.append(source.substring(endStartTag, beginEndTag)); |
| 172 | newHtmlString.append(source.substring(endEndTag, source.length())); |
| 173 | } |
| 174 | else |
| 175 | { |
| 176 | newHtmlString.append(source.substring(0, beginStartTag)); |
| 177 | newHtmlString.append(source.substring(endStartTag, source.length())); |
| 178 | } |
| 179 | parent.getTextPane().setText(newHtmlString.toString()); |
| 180 | parent.refreshOnUpdate(); |
| 181 | } |
| 182 | |
| 183 | /** Diese Methode gibt jeweils den Start- und Endoffset des Elements |
| 184 | * sowie dem entsprechenden schließenden Tag zurück |
| 185 | */ |
| 186 | private int[] getPositions(Element element, String source, boolean closingTag, String idString) |
| 187 | { |
| 188 | HTML.Tag tag = getHTMLTag(element); |
| 189 | int[] position = new int[4]; |
| 190 | for(int i = 0; i < position.length; i++) |
| 191 | { |
| 192 | position[i] = -1; |
| 193 | } |
| 194 | String searchString = "<" + tag.toString(); |
| 195 | int caret = -1; // aktuelle Position im sourceString |
| 196 | if((caret = source.indexOf(idString)) != -1) |
| 197 | { |
| 198 | position[0] = source.lastIndexOf("<",caret); |
| 199 | position[1] = source.indexOf(">",caret)+1; |
| 200 | } |
| 201 | if(closingTag) |
| 202 | { |
| 203 | String searchEndTagString = "</" + tag.toString() + ">"; |
| 204 | int hitUp = 0; |
| 205 | int beginEndTag = -1; |
| 206 | int endEndTag = -1; |
| 207 | caret = position[1]; |
| 208 | boolean end = false; |
| 209 | // Position des 1. Treffer auf den End-Tag wird bestimmt |
| 210 | beginEndTag = source.indexOf(searchEndTagString, caret); |
| 211 | endEndTag = beginEndTag + searchEndTagString.length(); |
| 212 | // Schleife läuft solange, bis keine neuen StartTags mehr gefunden werden |
| 213 | int interncaret = position[1]; |
| 214 | do |
| 215 | { |
| 216 | int temphitpoint = -1; |
| 217 | boolean flaghitup = false; |
| 218 | // Schleife sucht zwischen dem Start- und End-Tag nach neuen Start-Tags |
| 219 | hitUp = 0; |
| 220 | do |
| 221 | { |
| 222 | flaghitup = false; |
| 223 | temphitpoint = source.indexOf(searchString, interncaret); |
| 224 | if(temphitpoint > 0 && temphitpoint < beginEndTag) |
| 225 | { |
| 226 | hitUp++; |
| 227 | flaghitup = true; |
| 228 | interncaret = temphitpoint + searchString.length(); |
| 229 | } |
| 230 | } while(flaghitup); |
| 231 | // hitUp enthält die Anzahl der neuen Start-Tags |
| 232 | if(hitUp == 0) |
| 233 | { |
| 234 | end = true; |
| 235 | } |
| 236 | else |
| 237 | { |
| 238 | for(int i = 1; i <= hitUp; i++) |
| 239 | { |
| 240 | caret = endEndTag; |
| 241 | beginEndTag = source.indexOf(searchEndTagString, caret); |
| 242 | endEndTag = beginEndTag + searchEndTagString.length(); |
| 243 | } |
| 244 | end = false; |
| 245 | } |
| 246 | } while(!end); |
| 247 | if(beginEndTag < 0 | endEndTag < 0) |
| 248 | { |
| 249 | return null; |
| 250 | } |
| 251 | position[2] = beginEndTag; |
| 252 | position[3] = endEndTag; |
| 253 | } |
| 254 | return position; |
| 255 | } |
| 256 | |
| 257 | /* Diese Methode prüft ob der übergebene Tag sich in der Hierachie nach oben befindet */ |
| 258 | public boolean checkParentsTag(HTML.Tag tag) |
| 259 | { |
| 260 | Element e = parent.getExtendedHtmlDoc().getParagraphElement(parent.getCaretPosition()); |
| 261 | String tagString = tag.toString(); |
| 262 | if(e.getName().equalsIgnoreCase(tag.toString())) |
| 263 | { |
| 264 | return true; |
| 265 | } |
| 266 | do |
| 267 | { |
| 268 | if((e = e.getParentElement()).getName().equalsIgnoreCase(tagString)) |
| 269 | { |
| 270 | return true; |
| 271 | } |
| 272 | } while(!(e.getName().equalsIgnoreCase("html"))); |
| 273 | return false; |
| 274 | } |
| 275 | |
| 276 | /* Diese Methoden geben das erste gefundende dem übergebenen tags entsprechende Element zurück */ |
| 277 | public Element getListItemParent() |
| 278 | { |
| 279 | String listItemTag = HTML.Tag.LI.toString(); |
| 280 | Element eleSearch = parent.getExtendedHtmlDoc().getCharacterElement(parent.getCaretPosition()); |
| 281 | do |
| 282 | { |
| 283 | if(listItemTag.equals(eleSearch.getName())) |
| 284 | { |
| 285 | return eleSearch; |
| 286 | } |
| 287 | eleSearch = eleSearch.getParentElement(); |
| 288 | } while(eleSearch.getName() != HTML.Tag.HTML.toString()); |
| 289 | return null; |
| 290 | } |
| 291 | |
| 292 | /* Diese Methoden entfernen Attribute aus dem SimpleAttributeSet, gemäß den übergebenen Werten, und |
| 293 | geben das Ergebnis als SimpleAttributeSet zurück*/ |
| 294 | public SimpleAttributeSet removeAttributeByKey(SimpleAttributeSet sourceAS, String removeKey) |
| 295 | { |
| 296 | SimpleAttributeSet temp = new SimpleAttributeSet(); |
| 297 | temp.addAttribute(removeKey, "NULL"); |
| 298 | return removeAttribute(sourceAS, temp); |
| 299 | } |
| 300 | |
| 301 | public SimpleAttributeSet removeAttribute(SimpleAttributeSet sourceAS, SimpleAttributeSet removeAS) |
| 302 | { |
| 303 | try |
| 304 | { |
| 305 | String[] sourceKeys = new String[sourceAS.getAttributeCount()]; |
| 306 | String[] sourceValues = new String[sourceAS.getAttributeCount()]; |
| 307 | Enumeration sourceEn = sourceAS.getAttributeNames(); |
| 308 | int i = 0; |
| 309 | while(sourceEn.hasMoreElements()) |
| 310 | { |
| 311 | Object temp = new Object(); |
| 312 | temp = sourceEn.nextElement(); |
| 313 | sourceKeys[i] = (String) temp.toString(); |
| 314 | sourceValues[i] = new String(); |
| 315 | sourceValues[i] = (String) sourceAS.getAttribute(temp).toString(); |
| 316 | i++; |
| 317 | } |
| 318 | String[] removeKeys = new String[removeAS.getAttributeCount()]; |
| 319 | String[] removeValues = new String[removeAS.getAttributeCount()]; |
| 320 | Enumeration removeEn = removeAS.getAttributeNames(); |
| 321 | int j = 0; |
| 322 | while(removeEn.hasMoreElements()) |
| 323 | { |
| 324 | removeKeys[j] = (String) removeEn.nextElement().toString(); |
| 325 | removeValues[j] = (String) removeAS.getAttribute(removeKeys[j]).toString(); |
| 326 | j++; |
| 327 | } |
| 328 | SimpleAttributeSet result = new SimpleAttributeSet(); |
| 329 | boolean hit = false; |
| 330 | for(int countSource = 0; countSource < sourceKeys.length; countSource++) |
| 331 | { |
| 332 | hit = false; |
| 333 | if(sourceKeys[countSource] == "name" | sourceKeys[countSource] == "resolver") |
| 334 | { |
| 335 | hit = true; |
| 336 | } |
| 337 | else |
| 338 | { |
| 339 | for(int countRemove = 0; countRemove < removeKeys.length; countRemove++) |
| 340 | { |
| 341 | if(removeKeys[countRemove] != "NULL") |
| 342 | { |
| 343 | if(sourceKeys[countSource].toString() == removeKeys[countRemove].toString()) |
| 344 | { |
| 345 | if(removeValues[countRemove] != "NULL") |
| 346 | { |
| 347 | if(sourceValues[countSource].toString() == removeValues[countRemove].toString()) |
| 348 | { |
| 349 | hit = true; |
| 350 | } |
| 351 | } |
| 352 | else if(removeValues[countRemove] == "NULL") |
| 353 | { |
| 354 | hit = true; |
| 355 | } |
| 356 | } |
| 357 | } |
| 358 | else if(removeKeys[countRemove] == "NULL") |
| 359 | { |
| 360 | if(sourceValues[countSource].toString() == removeValues[countRemove].toString()) |
| 361 | { |
| 362 | hit = true; |
| 363 | } |
| 364 | } |
| 365 | } |
| 366 | } |
| 367 | if(!hit) |
| 368 | { |
| 369 | result.addAttribute(sourceKeys[countSource].toString(), sourceValues[countSource].toString()); |
| 370 | } |
| 371 | } |
| 372 | return result; |
| 373 | } |
| 374 | catch (ClassCastException cce) |
| 375 | { |
| 376 | return null; |
| 377 | } |
| 378 | } |
| 379 | |
| 380 | /* liefert den entsprechenden HTML.Tag zum Element zurück */ |
| 381 | public HTML.Tag getHTMLTag(Element e) |
| 382 | { |
| 383 | if(tags.containsKey(e.getName())) |
| 384 | { |
| 385 | return (HTML.Tag)tags.get(e.getName()); |
| 386 | } |
| 387 | else |
| 388 | { |
| 389 | return null; |
| 390 | } |
| 391 | } |
| 392 | |
| 393 | public String[] getUniString(int strings) |
| 394 | { |
| 395 | parent.refreshOnUpdate(); |
| 396 | String[] result = new String[strings]; |
| 397 | String source = parent.getSourcePane().getText(); |
| 398 | for(int i=0; i<strings; i++) |
| 399 | { |
| 400 | int start = -1, end = -1; |
| 401 | boolean hit = false; |
| 402 | String idString; |
| 403 | int counter = 0; |
| 404 | do |
| 405 | { |
| 406 | hit = false; |
| 407 | idString = "diesisteineidzumsuchen" + counter + "#" + i; |
| 408 | if(source.indexOf(idString) > -1) |
| 409 | { |
| 410 | counter++; |
| 411 | hit = true; |
| 412 | if(counter > 10000) |
| 413 | { |
| 414 | return null; |
| 415 | } |
| 416 | } |
| 417 | } while(hit); |
| 418 | result[i] = idString; |
| 419 | } |
| 420 | return result; |
| 421 | } |
| 422 | |
| 423 | public void delete() |
| 424 | throws BadLocationException,IOException |
| 425 | { |
| 426 | JTextPane jtpMain = parent.getTextPane(); |
| 427 | JTextArea jtpSource = parent.getSourcePane(); |
| 428 | ExtendedHTMLDocument htmlDoc = parent.getExtendedHtmlDoc(); |
| 429 | int selStart = jtpMain.getSelectionStart(); |
| 430 | int selEnd = jtpMain.getSelectionEnd(); |
| 431 | String[] posStrings = getUniString(2); |
| 432 | if(posStrings == null) |
| 433 | { |
| 434 | return; |
| 435 | } |
| 436 | htmlDoc.insertString(selStart,posStrings[0],null); |
| 437 | htmlDoc.insertString(selEnd+posStrings[0].length(),posStrings[1],null); |
| 438 | parent.refreshOnUpdate(); |
| 439 | int start = jtpSource.getText().indexOf(posStrings[0]); |
| 440 | int end = jtpSource.getText().indexOf(posStrings[1]); |
| 441 | if(start == -1 || end == -1) |
| 442 | { |
| 443 | return; |
| 444 | } |
| 445 | String htmlString = new String(); |
| 446 | htmlString += jtpSource.getText().substring(0,start); |
| 447 | htmlString += jtpSource.getText().substring(start + posStrings[0].length(), end); |
| 448 | htmlString += jtpSource.getText().substring(end + posStrings[1].length(), jtpSource.getText().length()); |
| 449 | String source = htmlString; |
| 450 | end = end - posStrings[0].length(); |
| 451 | htmlString = new String(); |
| 452 | htmlString += source.substring(0,start); |
| 453 | htmlString += getAllTableTags(source.substring(start, end)); |
| 454 | htmlString += source.substring(end, source.length()); |
| 455 | parent.getTextPane().setText(htmlString); |
| 456 | parent.refreshOnUpdate(); |
| 457 | } |
| 458 | |
| 459 | private String getAllTableTags(String source) |
| 460 | throws BadLocationException,IOException |
| 461 | { |
| 462 | StringBuffer result = new StringBuffer(); |
| 463 | int caret = -1; |
| 464 | do |
| 465 | { |
| 466 | caret++; |
| 467 | int[] tableCarets = new int[6]; |
| 468 | tableCarets[0] = source.indexOf("<table",caret); |
| 469 | tableCarets[1] = source.indexOf("<tr",caret); |
| 470 | tableCarets[2] = source.indexOf("<td",caret); |
| 471 | tableCarets[3] = source.indexOf("</table",caret); |
| 472 | tableCarets[4] = source.indexOf("</tr",caret); |
| 473 | tableCarets[5] = source.indexOf("</td",caret); |
| 474 | java.util.Arrays.sort(tableCarets); |
| 475 | caret = -1; |
| 476 | for(int i=0; i<tableCarets.length; i++) |
| 477 | { |
| 478 | if(tableCarets[i] >= 0) |
| 479 | { |
| 480 | caret = tableCarets[i]; |
| 481 | break; |
| 482 | } |
| 483 | } |
| 484 | if(caret != -1) |
| 485 | { |
| 486 | result.append(source.substring(caret,source.indexOf(">",caret)+1)); |
| 487 | } |
| 488 | } while(caret != -1); |
| 489 | return result.toString(); |
| 490 | } |
| 491 | |
| 492 | } |