1 19 20 25 26 package org.netbeans.modules.css.editor; 27 28 import java.util.logging.Logger ; 29 import org.netbeans.api.lexer.Language; 30 import org.netbeans.api.lexer.TokenId; 31 import org.netbeans.modules.css.loader.CssDataObject; 32 import org.netbeans.modules.css.visual.model.CssMetaModel; 33 import org.netbeans.modules.css.visual.model.CssStyleData; 34 import org.netbeans.modules.css.visual.parser.CssStyleParser; 35 import java.awt.Color ; 36 import java.beans.PropertyChangeEvent ; 37 import java.beans.PropertyChangeListener ; 38 import java.io.IOException ; 39 import javax.swing.JEditorPane ; 40 import javax.swing.SwingUtilities ; 41 import javax.swing.event.CaretEvent ; 42 import javax.swing.event.CaretListener ; 43 import javax.swing.event.DocumentEvent ; 44 import javax.swing.event.DocumentListener ; 45 import javax.swing.text.BadLocationException ; 46 import javax.swing.text.Document ; 47 import javax.swing.text.SimpleAttributeSet ; 48 import javax.swing.text.Style ; 49 import javax.swing.text.StyleConstants ; 50 import javax.swing.text.StyledDocument ; 51 import org.netbeans.api.lexer.TokenHierarchy; 52 import org.netbeans.api.lexer.TokenSequence; 53 import org.netbeans.editor.BaseDocument; 54 import org.netbeans.editor.TokenItem; 55 import org.netbeans.spi.lexer.LanguageProvider; 56 import org.openide.cookies.EditCookie; 57 import org.openide.cookies.EditorCookie; 58 import org.openide.cookies.OpenCookie; 59 import org.openide.cookies.PrintCookie; 60 import org.openide.cookies.SaveCookie; 61 import org.openide.filesystems.FileLock; 62 import org.openide.filesystems.FileObject; 63 import org.openide.text.CloneableEditor; 64 import org.openide.text.DataEditorSupport; 65 import org.openide.text.NbDocument; 66 import org.openide.windows.CloneableOpenSupport; 67 68 69 74 public class CssEditorSupport extends DataEditorSupport implements OpenCookie, EditCookie, 75 EditorCookie.Observable, PrintCookie, PropertyChangeListener { 76 77 private final SimpleAttributeSet ATTR_ADD = new SimpleAttributeSet (); 78 private final SimpleAttributeSet ATTR_REMOVE = new SimpleAttributeSet (); 79 80 CssDataObject cssDataObject = null; 81 82 int currentOffset = -1; 83 int currentLength = -1; 84 int currentHighlightStart = -1; 85 int currentHighlightEnd = -1; 86 87 EditorCookie editorCookie = null; 88 89 boolean highLighted = false; 90 91 private CssCustomEditor cssCustomEditor = null; 92 private CssCloneableEditor cssCloneableEditor = null; 93 94 private JEditorPane activePane; 95 96 97 private final SaveCookie saveCookie = new SaveCookie() { 98 public void save() throws IOException { 99 CssEditorSupport.this.saveDocument(); 100 CssEditorSupport.this.getDataObject().setModified(false); 101 } 102 }; 103 104 105 public CssEditorSupport(CssDataObject dataObject) { 106 super(dataObject, new CssEnvironment(dataObject)); 107 cssDataObject = dataObject; 108 addPropertyChangeListener(this); 109 ATTR_ADD.addAttribute(StyleConstants.Background, Color.red); 110 ATTR_REMOVE.addAttribute(StyleConstants.Background, Color.white); 111 } 112 113 116 protected boolean notifyModified() { 117 if (!super.notifyModified()) return false; 118 cssDataObject.addSaveCookie(saveCookie); 119 return true; 120 } 121 122 public void updateRules(){ 123 } 127 128 131 protected void notifyUnmodified() { 132 super.notifyUnmodified(); 133 cssDataObject.removeSaveCookie(saveCookie); 134 } 135 136 protected CloneableEditor createCloneableEditor() { 137 return new CssCloneableEditor(this); 138 } 139 140 146 public void propertyChange(PropertyChangeEvent evt){ 147 if (evt.getPropertyName().equals(EditorCookie.Observable.PROP_OPENED_PANES)){ 148 CssMetaModel.setDataObject(cssDataObject); 149 JEditorPane [] panes = this.getOpenedPanes(); 151 if (panes != null){ 152 activePane = panes[0]; 153 if(activePane != null){ 154 cssCustomEditor = getCssCustomEditor(activePane); 155 cssCloneableEditor = getCssCloneableEditor(activePane); 156 if(cssCustomEditor != null) { 157 cssCustomEditor.setDataObject(cssDataObject); 158 }else{ 159 System.out.println("CssEditorSupport.propertyChange - Warning! CSS Custome Editor Can not be null. Check! - Winston"); 160 } 161 if(cssCloneableEditor != null) { 162 cssCloneableEditor.requestActive(); 163 cssCloneableEditor.setDataObject(cssDataObject); 164 }else{ 165 System.out.println("CssEditorSupport.propertyChange - Warning! CSS Cloneable Editor Can not be null. Check! - Winston"); 166 } 167 168 activePane.addCaretListener(new CaretListener () { 170 public void caretUpdate(CaretEvent ce) { 171 if(ce.getSource() instanceof JEditorPane ){ 172 JEditorPane edPane = (JEditorPane )ce.getSource(); 173 setActiveNode(edPane.getDocument(), ce.getDot(), false); 174 } 175 } 176 }); 177 178 Document doc = activePane.getDocument(); 179 181 doc.addDocumentListener(new DocumentListener (){ 182 public void insertUpdate(DocumentEvent de){ 183 setActiveNode(de.getDocument(), activePane.getCaret().getDot(), true); 184 } 187 public void removeUpdate(DocumentEvent de){ 188 setActiveNode(de.getDocument(), activePane.getCaret().getDot(), true); 189 } 192 public void changedUpdate(DocumentEvent de){ 193 } 194 }); 195 196 try{ 198 if(doc.getLength() > 0){ 199 boolean searchDone = false; 200 String searchText; 201 int searchPos = 0; 202 do{ 203 searchText = doc.getText(searchPos, 1); 204 if (searchText.equals("{")){ 205 if(!isInComment(doc, searchPos)) { 206 break; 207 } 208 } 213 searchPos++; 214 if(searchPos > doc.getLength()) break; 215 }while(!searchDone); 216 217 if(doc.getLength() > (searchPos + 1)){ 218 activePane.getCaret().setDot(searchPos + 2); 219 } 220 } 221 }catch(BadLocationException ble){ 222 223 } 224 } 225 } 226 } 227 } 228 229 private boolean isInComment(Document doc, int dotPos) { 230 Language cssl = Language.find("text/x-css"); 232 if(cssl != null) { 233 TokenId cssCommentTI = cssl.tokenId("css_comment"); 235 if(cssCommentTI != null) { 236 237 TokenHierarchy th = TokenHierarchy.get(doc); 238 TokenSequence ts = th.tokenSequence(); 239 ts.move(dotPos); 240 if(ts.moveNext()) { 241 if(ts.token().id() == cssCommentTI) { 242 return true; } 244 } 245 } else { 246 Logger.getLogger(this.getClass().getName()).info("No text/x-css language doesn't contain 'css_comment' token ID!"); 247 } 248 } else { 249 Logger.getLogger(this.getClass().getName()).info("No text/x-css language found!"); 250 } 251 return false; 252 } 253 254 258 private void setActiveNode(final Document doc, int dotPos, boolean reparse){ 259 if(isInComment(doc, dotPos)) { 261 return ; 262 } 263 264 int initialPos = -1; 272 int lastPos = -1; 273 int searchPos = -1; 274 if((currentOffset != -1) && (currentLength != -1) && !reparse){ 275 if ((dotPos >= currentOffset) && (dotPos <= (currentOffset + currentLength))){ 276 highlight((StyledDocument )doc, currentOffset, currentLength); 277 return; 278 } 279 } 280 try { 281 searchPos = (dotPos -1) < 0 ? 0 : dotPos -1; 282 String txtBefore = doc.getText(searchPos, 1); 283 while(!txtBefore.equals("{")){ 284 searchPos--; 285 if((searchPos < 0) || txtBefore.equals("}")) break; 286 txtBefore = doc.getText(searchPos, 1); 287 } 288 if(txtBefore.equals("{")){ 289 initialPos = searchPos; 290 searchPos = (dotPos -1) < 0 ? 0 : dotPos -1; 291 String txtAfter = doc.getText(searchPos, 1); 292 while(!txtAfter.equals("}")){ 293 searchPos++; 294 if((searchPos > doc.getLength()) || txtAfter.equals("{")) break; 295 txtAfter = doc.getText(searchPos, 1); 296 } 297 if(txtAfter.equals("}")){ 298 lastPos = searchPos; 299 } 300 } 301 if( (initialPos > -1) && (lastPos > -1) ){ 302 currentOffset = initialPos + 1; 303 currentLength = lastPos - initialPos -1; 304 highlight((StyledDocument )doc, currentOffset, currentLength); 305 String cssProperties = doc.getText(currentOffset, currentLength); 306 307 CssStyleParser cssStyleParser = new CssStyleParser(); 310 final CssStyleData cssStyleData = cssStyleParser.parse(cssProperties.trim()); 311 cssStyleData.addPropertyChangeListener(new PropertyChangeListener (){ 312 public void propertyChange(PropertyChangeEvent evt){ 313 replaceText((BaseDocument)doc, cssStyleData.getFormattedString()); 314 } 315 }); 316 if(cssCustomEditor != null) { 317 cssCustomEditor.setCssStyleData(cssStyleData); 318 }else{ 319 System.out.println("CssEditorSupport.setActiveNode - Warning! CSS Custome Editor Can not be null. Check! - Winston"); } 321 322 if(cssCloneableEditor != null) { 323 cssCloneableEditor.setCssStyleData(cssStyleData); 324 }else{ 325 System.out.println("CssEditorSupport.setActiveNode - Warning! CSS Cloneable Editor Can not be null. Check! - Winston"); } 327 } 328 } catch (Exception e) { 329 e.printStackTrace(); 330 } 331 } 332 333 336 private void highlight(StyledDocument doc, int offset, int length){ 337 int initialPos = offset - 1; 338 int lastPos = length + initialPos + 1; 339 int firstLine = NbDocument.findLineNumber(doc,initialPos); 340 int lastLine = NbDocument.findLineNumber(doc,lastPos); 341 if((firstLine != currentHighlightStart) || (lastLine != currentHighlightEnd)){ 343 if (highLighted && (currentHighlightStart != -1) && (currentHighlightEnd != -1)){ 344 mark(doc, currentHighlightStart, currentHighlightEnd, false); 345 } 346 mark(doc, firstLine, lastLine, true); 347 highLighted = true; 348 349 initialPos = -1; 351 lastPos = -1; 352 try { 353 int searchPos = offset - 1; 354 String txtBefore = doc.getText(searchPos, 1); 355 while(!txtBefore.equals("{")){ 356 searchPos--; 357 if((searchPos < 0) || txtBefore.equals("}")) break; 358 txtBefore = doc.getText(searchPos, 1); 359 } 360 if(txtBefore.equals("{")){ 361 lastPos = searchPos - 1; 362 while(!txtBefore.equals("}")){ 363 searchPos--; 364 if((searchPos < 0) || txtBefore.equals("}") || txtBefore.equals("/")) break; 365 txtBefore = doc.getText(searchPos, 1); 366 } 367 if(txtBefore.equals("}") || txtBefore.equals("/")){ 368 initialPos = searchPos + 2; 369 }else{ 370 initialPos = searchPos + 1; 371 } 372 } 373 374 if ((initialPos != -1) && (lastPos != -1)){ 375 String ruleName = doc.getText(initialPos, lastPos - initialPos); 376 CssMetaModel.getInstance().setSelectedRuleName(ruleName.trim()); 377 } 378 } catch (Exception e) { 379 e.printStackTrace(); 380 } 381 currentHighlightStart = firstLine; 382 currentHighlightEnd = lastLine; 383 } 384 } 385 386 389 public void mark(StyledDocument doc, int startLine, int endLine, boolean mark){ 390 if ((startLine < 0) || (endLine < 0)) return; 391 int lastDoctLine = NbDocument.findLineNumber(doc, doc.getLength()); 392 if ((startLine > lastDoctLine) || (endLine > lastDoctLine)) return; 393 for(int i=startLine; i <= endLine; i++){ 394 int start = NbDocument.findLineOffset(doc, i); 395 if (mark){ 396 Style bp = doc.getStyle(NbDocument.CURRENT_STYLE_NAME); 397 if (bp == null) { 398 bp = doc.addStyle(NbDocument.CURRENT_STYLE_NAME, null); 399 bp.addAttribute(StyleConstants.ColorConstants.Background, new Color (225,236,247)); 400 } 401 doc.setLogicalStyle(start, bp); 402 }else{ 403 Style st = doc.getStyle(NbDocument.NORMAL_STYLE_NAME); 404 if (st == null){ 405 st = doc.addStyle(NbDocument.NORMAL_STYLE_NAME, null); 406 } 407 doc.setLogicalStyle(start, st); 408 } 409 } 410 } 411 412 415 boolean replaceText(BaseDocument doc, String text) { 416 int dotPos = activePane.getCaret().getDot(); 417 doc.atomicLock(); 418 try { 419 if (highLighted){ 420 mark((StyledDocument )doc, currentHighlightStart, currentHighlightEnd, false); 421 highLighted = false; 422 currentHighlightStart = -1; 423 currentHighlightEnd = -1; 424 } 425 doc.remove(currentOffset, currentLength); 426 doc.insertString(currentOffset, text, null); 427 currentLength = text.length(); 428 activePane.getCaret().setDot(currentOffset + 1); 429 } catch( BadLocationException exc ) { 430 return false; 431 } finally { 432 doc.atomicUnlock(); 433 } 434 return true; 435 } 436 437 440 private CssCloneableEditor getCssCloneableEditor(JEditorPane activePane) { 441 CssCloneableEditor cssCloneableEditor = (CssCloneableEditor)SwingUtilities.getAncestorOfClass(CssCloneableEditor.class, activePane); 442 return cssCloneableEditor; 443 } 444 445 448 private CssCustomEditor getCssCustomEditor(JEditorPane activePane) { 449 CssCustomEditor cssCustomEditor = (CssCustomEditor)SwingUtilities.getAncestorOfClass(CssCustomEditor.class, activePane); 450 return cssCustomEditor; 451 } 452 453 456 private static class CssEnvironment extends DataEditorSupport.Env { 457 CssDataObject cssDataObject = null; 458 459 public CssEnvironment(CssDataObject dataObject) { 460 super(dataObject); 461 cssDataObject = dataObject; 462 } 463 464 protected FileObject getFile() { 465 return cssDataObject.getPrimaryFile(); 466 } 467 468 protected FileLock takeLock() throws IOException { 469 return cssDataObject.getPrimaryEntry().takeLock(); 470 } 471 472 public CloneableOpenSupport findCloneableOpenSupport() { 473 return (CssEditorSupport)cssDataObject.getCookie(CssEditorSupport.class); 474 475 } 476 } 477 } 478 | Popular Tags |