ColorModel.java :  » IDE-Netbeans » options.api » org » netbeans » modules » options » colors » Java Open Source

Java Open Source » IDE Netbeans » options.api 
options.api » org » netbeans » modules » options » colors » ColorModel.java
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common
 * Development and Distribution License("CDDL") (collectively, the
 * "License"). You may not use this file except in compliance with the
 * License. You can obtain a copy of the License at
 * http://www.netbeans.org/cddl-gplv2.html
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 * specific language governing permissions and limitations under the
 * License.  When distributing the software, include this License Header
 * Notice in each file and include the License file at
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the GPL Version 2 section of the License file that
 * accompanied this code. If applicable, add the following below the
 * License Header, with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Contributor(s):
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 *
 * If you wish your version of this file to be governed by only the CDDL
 * or only the GPL Version 2, indicate your decision by adding
 * "[Contributor] elects to include this software in this distribution
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 * single choice of license, a recipient has the option to distribute
 * your version of this file under either the CDDL, the GPL Version 2 or
 * to extend the choice of license to its licensees as provided above.
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 * Version 2 license, then the option applies only if the new code is
 * made subject to such option by the copyright holder.
 */

package org.netbeans.modules.options.colors;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.EditorKit;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import org.netbeans.api.editor.settings.EditorStyleConstants;
import org.netbeans.api.lexer.TokenHierarchy;
import org.netbeans.api.lexer.TokenSequence;
import org.netbeans.editor.AnnotationType;
import org.netbeans.editor.AnnotationTypes;
import org.netbeans.editor.SyntaxSupport;
import org.netbeans.editor.TokenItem;
import org.netbeans.editor.Utilities;
import org.netbeans.editor.ext.ExtSyntaxSupport;
import org.netbeans.modules.editor.NbEditorDocument;
import org.netbeans.modules.editor.settings.storage.api.EditorSettings;
import org.netbeans.modules.editor.settings.storage.api.FontColorSettingsFactory;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileSystem;
import org.openide.filesystems.Repository;
import org.openide.text.CloneableEditorSupport;
import org.openide.util.NbBundle;

public final class ColorModel {

    private static final Logger LOG = Logger.getLogger(ColorModel.class.getName());
    
    public static final String ALL_LANGUAGES = NbBundle.getMessage(ColorModel.class, "CTL_All_Languages"); //NOI18N
    private static final String [] EMPTY_MIMEPATH = new String[0];
    
    // schemes .................................................................
    
    public Set<String> getProfiles() {
        return EditorSettings.getDefault().getFontColorProfiles();
    }
    
    public String getCurrentProfile () {
        return EditorSettings.getDefault().getCurrentFontColorProfile ();
    }
    
    public boolean isCustomProfile (String profile) {
        return EditorSettings.getDefault().isCustomFontColorProfile (profile);
    }
    
    public void setCurrentProfile (String profile) {
        EditorSettings.getDefault().setCurrentFontColorProfile (profile);
    }
    
    
    // annotations .............................................................
    
    public Collection<AttributeSet> getAnnotations(String profile) {
        List<AttributeSet> annotations = new ArrayList<AttributeSet>();
        for(Iterator it = AnnotationTypes.getTypes().getAnnotationTypeNames(); it.hasNext(); ) {
            String name = (String) it.next ();
            
            AnnotationType annotationType = AnnotationTypes.getTypes().getType(name);
            if (!annotationType.isVisible()) {
                continue;
            }

            String description = annotationType.getDescription();
            if (description == null) {
                continue;
            }

            SimpleAttributeSet category = new SimpleAttributeSet();
            category.addAttribute(EditorStyleConstants.DisplayName, description);
            category.addAttribute(StyleConstants.NameAttribute, description);
            
            URL iconURL = annotationType.getGlyph ();
            Image image = null;
            if (iconURL.getProtocol ().equals ("nbresloc")) { // NOI18N
                image = org.openide.util.Utilities.loadImage(iconURL.getPath().substring(1));
            } else {
                image = Toolkit.getDefaultToolkit ().getImage (iconURL);
            }
            if (image != null) {
                category.addAttribute("icon", new ImageIcon(image)); //NOI18N
            }
            
            Color bgColor = annotationType.getHighlight();
            if (annotationType.isUseHighlightColor() && bgColor != null) {
                category.addAttribute(StyleConstants.Background, bgColor);
            }
            
            Color fgColor = annotationType.getForegroundColor();
            if (!annotationType.isInheritForegroundColor() && fgColor != null) {
                category.addAttribute(StyleConstants.Foreground, fgColor);
            }

            Color underColor = annotationType.getWaveUnderlineColor();
            if (annotationType.isUseWaveUnderlineColor() && underColor != null) {
                category.addAttribute(EditorStyleConstants.WaveUnderlineColor, underColor);
            }
            
            category.addAttribute("annotationType", annotationType); //NOI18N
            annotations.add(category);
  }
        
  return annotations;
    }
    
    public void setAnnotations (
  String profile, 
  Collection<AttributeSet> annotations
    ) {
  //S ystem.out.println("ColorModelImpl.setAnnotations ");
  for(AttributeSet category : annotations) {
      AnnotationType annotationType = (AnnotationType) 
    category.getAttribute ("annotationType");
            
      if (category.isDefined (StyleConstants.Background)) {
    annotationType.setUseHighlightColor (true);
    annotationType.setHighlight (
                    (Color) category.getAttribute (StyleConstants.Background)
                );
            } else
    annotationType.setUseHighlightColor (false);
      if (category.isDefined (StyleConstants.Foreground)) {
    annotationType.setInheritForegroundColor (false);
    annotationType.setForegroundColor (
                    (Color) category.getAttribute (StyleConstants.Foreground)
                );
            } else
    annotationType.setInheritForegroundColor (true);
      if (category.isDefined (EditorStyleConstants.WaveUnderlineColor)) {
                annotationType.setUseWaveUnderlineColor (true);
                annotationType.setWaveUnderlineColor (
                    (Color) category.getAttribute (EditorStyleConstants.WaveUnderlineColor)
                );
            } else
                annotationType.setUseWaveUnderlineColor (false);
      //S ystem.out.println("  " + category.getDisplayName () + " : " + annotationType + " : " + annotationType.getHighlight() + " : " + annotationType.isUseHighlightColor());
  }
    }
    
    
    // editor categories .......................................................
    
    /**
     * Returns Collection of AttributeSets or null, if the profile does 
     * not exists.
     *
     * @param profile a profile name
     * @return Collection of AttributeSets or null
     */
    public Collection<AttributeSet> getHighlightings (String profile) {
        Map<String, AttributeSet> m = EditorSettings.getDefault().getHighlightings(profile);
        if (m == null) {
            return null;
        }
        return hideDummyCategories(m.values());
    }
    
    public Collection<AttributeSet> getHighlightingDefaults (String profile) {
        Collection<AttributeSet> r = EditorSettings.getDefault().getHighlightingDefaults(profile).values();
        if (r == null) return null;
        return hideDummyCategories (r);
    }
    
    public void setHighlightings(String profile, Collection<AttributeSet> highlihgtings) {
        EditorSettings.getDefault().setHighlightings(profile, toMap(highlihgtings));
    }
    
    // syntax coloring .........................................................
    
    public Set<String> getLanguages() {
        return getLanguageToMimeTypeMap().keySet();
    }
    
    public Collection<AttributeSet> getCategories (
  String profile, 
  String language
    ) {
        String [] mimePath = getMimePath(language);
        FontColorSettingsFactory fcs = EditorSettings.getDefault().getFontColorSettings(mimePath);
        return fcs.getAllFontColors(profile);
    }
    
    public Collection<AttributeSet> getDefaults (
  String profile, 
  String language
    ) {
        String [] mimePath = getMimePath(language);
        FontColorSettingsFactory fcs = EditorSettings.getDefault().getFontColorSettings(mimePath);
        return fcs.getAllFontColorDefaults(profile);
    }
    
    public void setCategories (
        String profile, 
        String language, 
        Collection<AttributeSet> categories
    ) {
        String [] mimePath = getMimePath(language);
        FontColorSettingsFactory fcs = EditorSettings.getDefault().getFontColorSettings(mimePath);
        fcs.setAllFontColors(profile, categories);
    }
  
    public Component getSyntaxColoringPreviewComponent(String language) {
        String mimeType = getMimeType(language);
        return new Preview("test" + hashCode(), mimeType); //NOI18N
    }

    final class Preview extends JPanel {
        
        static final String         PROP_CURRENT_ELEMENT = "currentAElement";
        
        private String testProfileName;
        private String currentMimeType;
        private JEditorPane editorPane;
        private FontColorSettingsFactory fontColorSettings;
        
        
        public Preview (String testProfileName, final String mimeType) {
            super (new BorderLayout ());
            this.testProfileName = testProfileName;
            
            SwingUtilities.invokeLater (new Runnable () {
                public void run () {
                    updateMimeType(mimeType);
                }
            });
            setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR));
        }
        
        public void setParameters(
            String      language,
            final Collection<AttributeSet> defaults,
            final Collection<AttributeSet> highlightings,
            final Collection<AttributeSet> syntaxColorings
        ) {
            final String mimeType = getMimeType(language);
            
            SwingUtilities.invokeLater (new Runnable () {
                public void run () {
                    if (!mimeType.equals(currentMimeType)) {
                        updateMimeType(mimeType);
                    }
                    
                    if (defaults != null) {
                        EditorSettings.getDefault().getFontColorSettings(EMPTY_MIMEPATH).setAllFontColors(
                            testProfileName,
                            defaults
                        );
                    }
                    if (highlightings != null) {
                        EditorSettings.getDefault().setHighlightings (
                            testProfileName,
                            toMap (highlightings)
                        );
                    }
                    if (syntaxColorings != null && currentMimeType.length() != 0) {
                        FontColorSettingsFactory fcs = EditorSettings.getDefault().getFontColorSettings(new String[] { currentMimeType });
                        fcs.setAllFontColors (
                            testProfileName,
                            syntaxColorings
                        );
                    }
                }
            });
        }
        
        /**
         * Sets given mime type to preview and loads proper example text.
         */
        private void updateMimeType(String mimeType) {
            currentMimeType = mimeType;
            
            String [] ret = loadPreviewExample(mimeType);
            String exampleText = ret[0];
            String exampleMimeType = ret[1];
            
            // XXX: There is several hacks in the few lines of code below.
            // First, the 'mimeType' property on a Document is abused for
            // injecting the name of a profile used for previewing changes in
            // colors. This by itself causes several problems in other parts of
            // the IDE that had to be worked around. Second, Document properties
            // are normally not supposed to be changed during a lifetime of a Document
            // and there is no way how to listen for those changes. Which means
            // that we have to fire a property change on the JTextComponent containing
            // the Document, so that the layers can get recalculated.

            String hackMimeType = hackMimeType(exampleMimeType);

            // Replace the whole component, see #113608
            removeAll();
            editorPane = new JEditorPane();
            add(editorPane, BorderLayout.CENTER);
            
            EditorKit kit = CloneableEditorSupport.getEditorKit(hackMimeType);
            Document document = kit.createDefaultDocument();
            document.putProperty(NbEditorDocument.MIME_TYPE_PROP, hackMimeType);
            editorPane.setEditorKit(kit);
            editorPane.setDocument(document);
            
            editorPane.addCaretListener (new CaretListener () {
                public void caretUpdate (CaretEvent e) {
                    int offset = e.getDot ();
                    String elementName = null;
                    
                    TokenHierarchy<Document> th = TokenHierarchy.get(editorPane.getDocument());
                    if (th != null) {
                        elementName = findLexerElement(th, offset);
                    } else {
                        SyntaxSupport ss = Utilities.getSyntaxSupport(editorPane);
                        if (ss instanceof ExtSyntaxSupport) {
                            elementName = findSyntaxElement((ExtSyntaxSupport) ss, offset);
                        }
                    }

                    if (elementName != null) {
                        firePropertyChange(PROP_CURRENT_ELEMENT, null, elementName);
                    }
                }
                
                private String findLexerElement(TokenHierarchy<Document> hierarchy, int offset) {
                    String elementName = null;
                    List<TokenSequence<?>> sequences = hierarchy.embeddedTokenSequences(offset, false);
                    if (!sequences.isEmpty()) {
                        TokenSequence<?> seq = sequences.get(sequences.size() - 1);
                        seq.move(offset);
                        if (seq.moveNext()) {
                            elementName = seq.token().id().primaryCategory();
                            if (elementName == null) {
                                elementName = seq.token().id().name();
                            }
                        }
                    }
                    return elementName;
                }

                private String findSyntaxElement(ExtSyntaxSupport syntax, int offset) {
                    try {
                        TokenItem tokenItem = syntax.getTokenChain(offset, offset + 1);
                        if (tokenItem == null) {
                            return null;
                        }
                        String elementName = tokenItem.getTokenContextPath().getNamePrefix();
                        if (tokenItem.getTokenID().getCategory() != null) {
                            elementName += tokenItem.getTokenID().getCategory().getName();
                        } else {
                            elementName += tokenItem.getTokenID().getName();
                        }
                        return elementName;
                    } catch (BadLocationException ble) {
                        LOG.log(Level.WARNING, null, ble);
                        return null;
                    }
                }
            });
            
            editorPane.setEnabled(false);
            editorPane.setText(exampleText);
            editorPane.setCaretPosition(0);
        }
        
        private String [] loadPreviewExample(String mimeType) {
            FileSystem fs = Repository.getDefault ().getDefaultFileSystem ();
            FileObject exampleFile = null;
            String exampleMimeType = null;
            
            if (mimeType == null || mimeType.length() == 0) {
                FileObject f = fs.findResource("OptionsDialog/PreviewExamples"); //NOI18N
                if (f != null && f.isFolder()) {
                    FileObject [] ff = f.getChildren();
                    for(int i = 0 ; i < ff.length; i++) {
                        if (ff[i].isData()) {
                            exampleFile = ff[i];
                            break;
                        }
                    }
                }
                if (exampleFile != null) {
                    if (exampleFile.getMIMEType().equals("content/unknown")) { //NOI18N
                        exampleMimeType = "text/x-java"; //NOI18N
                    } else {
                        exampleMimeType = exampleFile.getMIMEType();
                    }
                }
            } else {
                exampleFile = fs.findResource("OptionsDialog/PreviewExamples/" + mimeType); //NOI18N
                exampleMimeType = mimeType;
            }
            
            if (exampleFile != null) {
                StringBuilder sb = new StringBuilder((int)exampleFile.getSize());
                
                try {
                    InputStreamReader is = new InputStreamReader(exampleFile.getInputStream());
                    char [] buffer = new char[1024];
                    int size;
                    try {
                        while(0 < (size = is.read(buffer, 0, buffer.length))) {
                            sb.append(buffer, 0, size);
                        }
                    } finally {
                        is.close();
                    }
                } catch (IOException ioe) {
                    LOG.log(Level.WARNING, "Can't read font & colors preview example", ioe); //NOI18N
                }
                
                return new String [] { sb.toString(), exampleMimeType };
            } else {
                return new String [] { "", "text/plain" }; //NOI18N
            }            
        }

        private String hackMimeType(String mimeType) {
            return testProfileName + "_" + mimeType; //NOI18N
        }
    }
    
    
    // private implementation ..................................................

    private String getMimeType(String language) {
        if (language.equals(ALL_LANGUAGES)) {
            return ""; //NOI18N
        } else {
            String mimeType = getLanguageToMimeTypeMap().get(language);
            assert mimeType != null : "Invalid language '" + language + "'"; //NOI18N
            return mimeType;
        }
    }
    
    private String [] getMimePath(String language) {
        if (language.equals(ALL_LANGUAGES)) {
            return EMPTY_MIMEPATH;
        } else {
            String mimeType = getLanguageToMimeTypeMap().get(language);
            assert mimeType != null : "Invalid language '" + language + "'"; //NOI18N
            return new String [] { mimeType };
        }
    }
    
    private Map<String, String> languageToMimeType;
    private Map<String, String> getLanguageToMimeTypeMap() {
        if (languageToMimeType == null) {
            languageToMimeType = new HashMap<String, String>();
            Set<String> mimeTypes = EditorSettings.getDefault().getMimeTypes();
            for(String mimeType : mimeTypes) {
                languageToMimeType.put(
                    EditorSettings.getDefault().getLanguageName(mimeType),
                    mimeType
                );
            }
            languageToMimeType.put(
                    ALL_LANGUAGES,
                    "Defaults" //NOI18N
                    );
        }
        return languageToMimeType;
    }
    
    private Set<AttributeSet> hiddenCategories = new HashSet<AttributeSet>();
    {
//        hiddenCategories.add ("status-bar");
//        hiddenCategories.add ("status-bar-bold");
    }
    
    private Collection<AttributeSet> hideDummyCategories(Collection<AttributeSet> categories) {
        List<AttributeSet> result = new ArrayList<AttributeSet>();
        for(AttributeSet as : categories) {
            if (hiddenCategories.contains(as.getAttribute(StyleConstants.NameAttribute))) {
                continue;
            }
            result.add(as);
        }
        return result;
    }
    
    private static Map<String, AttributeSet> toMap(Collection<AttributeSet> categories) {
        if (categories == null) return null;
        Map<String, AttributeSet> result = new HashMap<String, AttributeSet>();
        for(AttributeSet as : categories) {
            result.put((String) as.getAttribute(StyleConstants.NameAttribute), as);
        }
        return result;
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.