1 19 package org.netbeans.spi.project.support; 20 21 import java.lang.ref.Reference ; 22 import java.lang.ref.WeakReference ; 23 import java.util.ArrayList ; 24 import java.util.Arrays ; 25 import java.util.Collection ; 26 import java.util.Collections ; 27 import java.util.List ; 28 import javax.swing.event.ChangeEvent ; 29 import javax.swing.event.ChangeListener ; 30 import org.netbeans.api.project.SourceGroup; 31 import org.netbeans.api.project.Sources; 32 import org.netbeans.spi.project.LookupMerger; 33 import org.netbeans.spi.project.LookupProvider; 34 import org.openide.ErrorManager; 35 import org.openide.filesystems.FileObject; 36 import org.openide.filesystems.Repository; 37 import org.openide.loaders.DataFolder; 38 import org.openide.loaders.FolderLookup; 39 import org.openide.util.Lookup; 40 import org.openide.util.LookupEvent; 41 import org.openide.util.LookupListener; 42 import org.openide.util.WeakListeners; 43 import org.openide.util.lookup.Lookups; 44 import org.openide.util.lookup.ProxyLookup; 45 46 52 public final class LookupProviderSupport { 53 54 55 private LookupProviderSupport() { 56 } 57 58 67 public static Lookup createCompositeLookup(Lookup baseLookup, String folderPath) { 68 return new DelegatingLookupImpl(baseLookup, folderPath); 69 } 70 71 78 public static LookupMerger createSourcesMerger() { 79 return new SourcesMerger(); 80 } 81 82 private static Lookup createLookup(String folderPath) { 84 FileObject root = Repository.getDefault().getDefaultFileSystem().findResource(folderPath); 85 if (root != null) { 86 DataFolder folder = DataFolder.findFolder(root); 87 return new FolderLookup(folder).getLookup(); 88 } else { return Lookup.EMPTY; 90 } 91 } 92 93 static class DelegatingLookupImpl extends ProxyLookup implements LookupListener { 94 private Lookup baseLookup; 95 private Lookup.Result<LookupProvider> providerResult; 96 private LookupListener providerListener; 97 private List <LookupProvider> old = Collections.emptyList(); 98 private List <Lookup> currentLookups; 99 100 private Lookup.Result<LookupMerger> mergers; 101 private Reference <LookupListener> listenerRef; 102 private List <Lookup.Result<?>> results = new ArrayList <Lookup.Result<?>>(); 104 105 public DelegatingLookupImpl(Lookup base, String path) { 106 this(base, createLookup(path)); 107 } 108 109 public DelegatingLookupImpl(Lookup base, Lookup providerLookup) { 110 super(); 111 assert base != null; 112 baseLookup = base; 113 providerResult = providerLookup.lookup(new Lookup.Template<LookupProvider>(LookupProvider.class)); 114 doDelegate(providerResult.allInstances()); 115 providerListener = new LookupListener() { 116 public void resultChanged(LookupEvent ev) { 117 doDelegate(providerResult.allInstances()); 118 } 119 }; 120 providerResult.addLookupListener(providerListener); 121 } 122 123 124 public void resultChanged(LookupEvent ev) { 125 doDelegate(providerResult.allInstances()); 126 } 127 128 129 private synchronized void doDelegate(Collection <? extends LookupProvider> providers) { 130 for (Lookup.Result<?> r : results) { 132 r.removeLookupListener(this); 133 } 134 135 List <Lookup> newLookups = new ArrayList <Lookup>(); 136 for (LookupProvider elem : providers) { 137 if (old.contains(elem)) { 138 int index = old.indexOf(elem); 139 newLookups.add(currentLookups.get(index)); 140 } else { 141 Lookup newone = elem.createAdditionalLookup(baseLookup); 142 assert newone != null; 143 newLookups.add(newone); 144 } 145 } 146 old = new ArrayList <LookupProvider>(providers); 147 currentLookups = newLookups; 148 newLookups.add(baseLookup); 149 Lookup lkp = new ProxyLookup(newLookups.toArray(new Lookup[newLookups.size()])); 150 151 List <Class <?>> filteredClasses = new ArrayList <Class <?>>(); 153 List <Object > mergedInstances = new ArrayList <Object >(); 154 LookupListener l = listenerRef != null ? listenerRef.get() : null; 155 if (l != null) { 156 mergers.removeLookupListener(l); 157 } 158 mergers = lkp.lookupResult(LookupMerger.class); 159 l = WeakListeners.create(LookupListener.class, this, mergers); 160 listenerRef = new WeakReference <LookupListener>(l); 161 mergers.addLookupListener(l); 162 for (LookupMerger lm : mergers.allInstances()) { 163 Class <?> c = lm.getMergeableClass(); 164 if (filteredClasses.contains(c)) { 165 ErrorManager.getDefault().log(ErrorManager.WARNING, 166 "Two LookupMerger registered for class " + c + 167 ". Only first one will be used"); continue; 169 } 170 filteredClasses.add(c); 171 mergedInstances.add(lm.merge(lkp)); 172 173 Lookup.Result<?> result = lkp.lookupResult(c); 174 175 result.addLookupListener(this); 176 results.add(result); 177 } 178 lkp = Lookups.exclude(lkp, filteredClasses.toArray(new Class <?>[filteredClasses.size()])); 179 Lookup fixed = Lookups.fixed(mergedInstances.toArray(new Object [mergedInstances.size()])); 180 setLookups(fixed, lkp); 181 } 182 } 183 184 185 private static class SourcesMerger implements LookupMerger<Sources> { 186 private SourcesImpl merger; 187 188 public Class <Sources> getMergeableClass() { 189 return Sources.class; 190 } 191 192 public Sources merge(Lookup lookup) { 193 if (merger == null) { 194 merger = new SourcesImpl(); 195 } 196 merger.setLookup(lookup); 197 return merger; 198 } 199 } 200 201 private static class SourcesImpl implements Sources, ChangeListener , LookupListener { 202 private List <ChangeListener > listeners = new ArrayList <ChangeListener >(); 203 private Lookup.Result<Sources> delegates; 204 private Collection <Sources> currentDelegates = new ArrayList <Sources>(); 205 206 public SourcesImpl() { 207 } 208 209 private void setLookup(Lookup lookup) { 210 if (currentDelegates.size() > 0) { 211 for (Sources old : currentDelegates) { 212 old.removeChangeListener(this); 213 } 214 currentDelegates.clear(); 215 } 216 if (delegates != null) { 217 delegates.removeLookupListener(this); 218 } 219 Lookup.Result<Sources> srcs = lookup.lookupResult(Sources.class); 220 for (Sources ns : srcs.allInstances()) { 221 ns.addChangeListener(this); 222 currentDelegates.add(ns); 223 } 224 srcs.addLookupListener(this); 225 delegates = srcs; 226 fireChange(); 227 } 228 229 public SourceGroup[] getSourceGroups(String type) { 230 assert delegates != null; 231 Collection <SourceGroup> result = new ArrayList <SourceGroup>(); 232 for (Sources ns : delegates.allInstances()) { 233 SourceGroup[] grps = ns.getSourceGroups(type); 234 if (grps != null) { 235 result.addAll(Arrays.asList(grps)); 236 } 237 } 238 return result.toArray(new SourceGroup[result.size()]); 239 } 240 241 public synchronized void addChangeListener(ChangeListener listener) { 242 listeners.add(listener); 243 } 244 245 public synchronized void removeChangeListener(ChangeListener listener) { 246 listeners.remove(listener); 247 } 248 249 public void stateChanged(ChangeEvent e) { 250 fireChange(); 251 } 252 253 private void fireChange() { 254 ArrayList <ChangeListener > list = new ArrayList <ChangeListener >(); 255 synchronized (this) { 256 list.addAll(listeners); 257 } 258 for (ChangeListener listener : list) { 259 listener.stateChanged(new ChangeEvent (this)); 260 } 261 } 262 263 public void resultChanged(LookupEvent ev) { 264 if (currentDelegates.size() > 0) { 265 for (Sources old : currentDelegates) { 266 old.removeChangeListener(this); 267 } 268 currentDelegates.clear(); 269 } 270 for (Sources ns : delegates.allInstances()) { 271 ns.addChangeListener(this); 272 currentDelegates.add(ns); 273 } 274 fireChange(); 275 } 276 } 277 278 } 279 | Popular Tags |