001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.cnd.model.tasks;
042:
043: import java.beans.PropertyChangeEvent;
044: import java.beans.PropertyChangeListener;
045: import java.util.ArrayList;
046: import java.util.Arrays;
047: import java.util.Collection;
048: import java.util.Collections;
049: import java.util.HashMap;
050: import java.util.LinkedList;
051: import java.util.List;
052: import java.util.Map;
053: import javax.swing.JEditorPane;
054: import javax.swing.event.ChangeEvent;
055: import javax.swing.event.ChangeListener;
056: import javax.swing.text.Document;
057: import javax.swing.text.JTextComponent;
058: import org.netbeans.api.editor.EditorRegistry;
059: import org.openide.filesystems.FileObject;
060: import org.openide.filesystems.FileUtil;
061: import org.openide.loaders.DataObject;
062: import org.openide.util.Parameters;
063:
064: /**
065: *
066: * @author Jan Lahoda
067: */
068: class OpenedEditors implements PropertyChangeListener {
069:
070: private List<JTextComponent> visibleEditors = new ArrayList<JTextComponent>();
071: private Map<JTextComponent, FileObject> visibleEditors2Files = new HashMap<JTextComponent, FileObject>();
072: private List<ChangeListener> listeners = new ArrayList<ChangeListener>();
073: private static OpenedEditors DEFAULT;
074:
075: private OpenedEditors() {
076: EditorRegistry
077: .addPropertyChangeListener(new PropertyChangeListener() {
078:
079: public void propertyChange(PropertyChangeEvent evt) {
080: stateChanged();
081: }
082: });
083: }
084:
085: public static synchronized OpenedEditors getDefault() {
086: if (DEFAULT == null) {
087: DEFAULT = new OpenedEditors();
088: }
089:
090: return DEFAULT;
091: }
092:
093: public synchronized void addChangeListener(ChangeListener l) {
094: listeners.add(l);
095: }
096:
097: public synchronized void removeChangeListener(ChangeListener l) {
098: listeners.remove(l);
099: }
100:
101: private void fireChangeEvent() {
102: ChangeEvent e = new ChangeEvent(this );
103: List<ChangeListener> listenersCopy = null;
104:
105: synchronized (this ) {
106: listenersCopy = new ArrayList<ChangeListener>(listeners);
107: }
108:
109: for (ChangeListener l : listenersCopy) {
110: l.stateChanged(e);
111: }
112: }
113:
114: public synchronized List<JTextComponent> getVisibleEditors() {
115: return Collections.unmodifiableList(visibleEditors);
116: }
117:
118: public synchronized Collection<FileObject> getVisibleEditorsFiles() {
119: return Collections.unmodifiableCollection(visibleEditors2Files
120: .values());
121: }
122:
123: public synchronized void stateChanged() {
124: for (JTextComponent c : visibleEditors) {
125: c.removePropertyChangeListener(this );
126: visibleEditors2Files.remove(c);
127: }
128:
129: visibleEditors.clear();
130:
131: for (JTextComponent editor : EditorRegistry.componentList()) {
132: if (editor.isShowing()) {
133: FileObject fo = editor != null ? getFileObject(editor)
134: : null;
135:
136: if (editor instanceof JEditorPane && fo != null
137: && isSupported(fo)) {
138: visibleEditors.add(editor);
139: }
140: }
141: }
142:
143: for (JTextComponent c : visibleEditors) {
144: c.addPropertyChangeListener(this );
145: visibleEditors2Files.put(c, getFileObject(c));
146: }
147:
148: fireChangeEvent();
149: }
150:
151: public synchronized void propertyChange(PropertyChangeEvent evt) {
152: JTextComponent c = (JTextComponent) evt.getSource();
153: FileObject originalFile = visibleEditors2Files.get(c);
154: FileObject newFile = getFileObject(c);
155:
156: if (originalFile != newFile) {
157: visibleEditors2Files.put(c, newFile);
158: fireChangeEvent();
159: }
160: }
161:
162: static FileObject getFileObject(JTextComponent pane) {
163: Object source = pane.getDocument().getProperty(
164: Document.StreamDescriptionProperty);
165:
166: if (!(source instanceof DataObject)) {
167: return null;
168: }
169:
170: DataObject file = (DataObject) source;
171:
172: if (file != null) {
173: return file.getPrimaryFile();
174: }
175:
176: return null;
177: }
178:
179: /**
180: * Checks if the given file is supported.
181: */
182: private static boolean isSupported(FileObject file)
183: throws NullPointerException {
184: Parameters.notNull("files", file);
185:
186: return !filterSupportedFiles(Collections.singletonList(file))
187: .isEmpty();
188: }
189:
190: private final static List<String> mimeTypesList = Arrays
191: .asList(new String[] { "text/x-c++", "text/x-c" }); //NOI18N
192:
193: /**
194: * Filter unsupported files from the <code>files</code> parameter.
195: */
196: public static List<FileObject> filterSupportedFiles(
197: Collection<FileObject> files) throws NullPointerException {
198: Parameters.notNull("files", files);
199:
200: List<FileObject> result = new LinkedList<FileObject>();
201:
202: for (FileObject f : files) {
203: String fileMimeType = FileUtil.getMIMEType(f);
204:
205: if (fileMimeType == null) {
206: //unrecognized FileObject
207: continue;
208: }
209:
210: if (mimeTypesList.contains(fileMimeType)) {
211: result.add(f);
212: continue;
213: }
214:
215: String shorterMimeType = fileMimeType;
216:
217: while (true) {
218: int slash = shorterMimeType.indexOf('/');
219:
220: if (slash == (-1)) {
221: break;
222: }
223:
224: int plus = shorterMimeType.indexOf('+', slash);
225:
226: if (plus == (-1)) {
227: break;
228: }
229:
230: shorterMimeType = shorterMimeType.substring(0,
231: slash + 1)
232: + shorterMimeType.substring(plus + 1);
233:
234: if (mimeTypesList.contains(shorterMimeType)) {
235: result.add(f);
236: break;
237: }
238: }
239: }
240:
241: return result;
242: }
243: }
|