1 19 20 package org.netbeans.modules.ruby.railsprojects; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.beans.PropertyChangeSupport ; 25 import java.io.File ; 26 import java.net.MalformedURLException ; 27 import java.net.URL ; 28 import java.net.URI ; 29 import java.util.Arrays ; 30 import java.util.ArrayList ; 31 import java.util.Collections ; 32 import java.util.Iterator ; 33 import java.util.List ; 34 import java.util.Map ; 35 import java.util.HashMap ; 36 import java.text.MessageFormat ; 37 import org.openide.ErrorManager; 38 import org.openide.filesystems.FileObject; 39 import org.openide.filesystems.FileUtil; 40 import org.openide.util.WeakListeners; 41 import org.openide.util.Mutex; 42 import org.openide.util.NbBundle; 43 import org.w3c.dom.Element ; 44 import org.w3c.dom.NodeList ; 45 import org.w3c.dom.Document ; 46 import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectHelper; 47 import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectEvent; 48 import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectListener; 49 import org.netbeans.modules.ruby.spi.project.support.rake.EditableProperties; 50 import org.netbeans.modules.ruby.spi.project.support.rake.PropertyEvaluator; 51 import org.netbeans.modules.ruby.spi.project.support.rake.ReferenceHelper; 52 import org.netbeans.api.project.ProjectManager; 53 54 59 public final class SourceRoots { 60 61 public static final String PROP_ROOT_PROPERTIES = "rootProperties"; public static final String PROP_ROOTS = "roots"; 64 public static final String DEFAULT_SOURCE_LABEL = NbBundle.getMessage(SourceRoots.class, "NAME_src.dir"); 65 public static final String DEFAULT_TEST_LABEL = NbBundle.getMessage(SourceRoots.class, "NAME_test.src.dir"); 66 67 private final UpdateHelper helper; 68 private final PropertyEvaluator evaluator; 69 private final ReferenceHelper refHelper; 70 private final String elementName; 71 private final String newRootNameTemplate; 72 private List <String > sourceRootProperties; 73 private List <String > sourceRootNames; 74 private List <FileObject> sourceRoots; 75 private List <URL > sourceRootURLs; 76 private final PropertyChangeSupport support; 77 private final ProjectMetadataListener listener; 78 private final boolean isTest; 79 private final File projectDir; 80 81 88 SourceRoots (UpdateHelper helper, PropertyEvaluator evaluator, ReferenceHelper refHelper, String elementName, boolean isTest, String newRootNameTemplate) { 89 assert helper != null && evaluator != null && refHelper != null && elementName != null && newRootNameTemplate != null; 90 this.helper = helper; 91 this.evaluator = evaluator; 92 this.refHelper = refHelper; 93 this.elementName = elementName; 94 this.isTest = isTest; 95 this.newRootNameTemplate = newRootNameTemplate; 96 this.projectDir = FileUtil.toFile(this.helper.getRakeProjectHelper().getProjectDirectory()); 97 this.support = new PropertyChangeSupport (this); 98 this.listener = new ProjectMetadataListener(); 99 this.evaluator.addPropertyChangeListener (WeakListeners.propertyChange(this.listener,this.evaluator)); 100 this.helper.getRakeProjectHelper().addRakeProjectListener ((RakeProjectListener)WeakListeners.create(RakeProjectListener.class, this.listener,this.helper)); 101 } 102 103 104 110 public String [] getRootNames () { 111 return ProjectManager.mutex().readAccess(new Mutex.Action<String []>() { 112 public String [] run() { 113 synchronized (SourceRoots.this) { 115 if (sourceRootNames == null) { 116 sourceRootNames = new ArrayList <String >(12); 117 sourceRootNames.add(NbBundle.getMessage(SourceRoots.class, "app_controllers")); 119 sourceRootNames.add(NbBundle.getMessage(SourceRoots.class, "app_helpers")); 120 sourceRootNames.add(NbBundle.getMessage(SourceRoots.class, "app_models")); 121 sourceRootNames.add(NbBundle.getMessage(SourceRoots.class, "app_views")); 122 sourceRootNames.add(NbBundle.getMessage(SourceRoots.class, "db")); 123 sourceRootNames.add(NbBundle.getMessage(SourceRoots.class, "lib")); 124 sourceRootNames.add(NbBundle.getMessage(SourceRoots.class, "log")); 125 sourceRootNames.add(NbBundle.getMessage(SourceRoots.class, "config")); 126 sourceRootNames.add(NbBundle.getMessage(SourceRoots.class, "components")); 127 sourceRootNames.add(NbBundle.getMessage(SourceRoots.class, "test_unit")); 128 sourceRootNames.add(NbBundle.getMessage(SourceRoots.class, "test_functional")); 129 sourceRootNames.add(NbBundle.getMessage(SourceRoots.class, "test_fixtures")); 130 sourceRootNames.add(NbBundle.getMessage(SourceRoots.class, "test_mocks")); 131 sourceRootNames.add(NbBundle.getMessage(SourceRoots.class, "test_integration")); 132 } 133 } 134 return sourceRootNames.toArray (new String [sourceRootNames.size()]); 135 } 136 }); 137 138 } 139 140 144 public String [] getRootProperties () { 145 return ProjectManager.mutex().readAccess(new Mutex.Action<String []>() { 146 public String [] run() { 147 synchronized (SourceRoots.this) { 148 if (sourceRootProperties == null) { 149 sourceRootProperties = new ArrayList <String >(12); 151 sourceRootProperties.add("app/controllers"); 152 sourceRootProperties.add("app/helpers"); 153 sourceRootProperties.add("app/models"); 154 sourceRootProperties.add("app/views"); 155 sourceRootProperties.add("db"); 156 sourceRootProperties.add("lib"); 157 sourceRootProperties.add("log"); 158 sourceRootProperties.add("config"); 159 sourceRootProperties.add("components"); 160 sourceRootProperties.add("test/unit"); 161 sourceRootProperties.add("test/functional"); 162 sourceRootProperties.add("test/fixtures"); 163 sourceRootProperties.add("test/mocks"); 164 sourceRootProperties.add("test/integration"); 165 } 166 } 167 return sourceRootProperties.toArray (new String [sourceRootProperties.size()]); 168 } 169 }); 170 } 171 172 176 public FileObject[] getRoots () { 177 return ProjectManager.mutex().readAccess(new Mutex.Action<FileObject[]>() { 178 public FileObject[] run () { 179 synchronized (this) { 180 if (sourceRoots == null) { 182 String [] srcProps = getRootProperties(); 183 List <FileObject> result = new ArrayList <FileObject>(); 184 for (String p : srcProps) { 185 FileObject f = helper.getRakeProjectHelper().resolveFileObject(p); 186 if (f == null) { 187 continue; 188 } 189 if (FileUtil.isArchiveFile(f)) { 190 f = FileUtil.getArchiveRoot(f); 191 } 192 result.add(f); 193 } 194 sourceRoots = Collections.unmodifiableList(result); 195 } 196 } 197 return sourceRoots.toArray(new FileObject[sourceRoots.size()]); 198 } 199 }); 200 } 201 202 206 public URL [] getRootURLs() { 207 return ProjectManager.mutex().readAccess(new Mutex.Action<URL []>() { 208 public URL [] run () { 209 synchronized (this) { 210 if (sourceRootURLs == null) { 212 String [] srcProps = getRootProperties(); 213 List <URL > result = new ArrayList <URL >(); 214 for (int i = 0; i<srcProps.length; i++) { 215 String prop = srcProps[i]; 216 if (prop != null) { 217 File f = helper.getRakeProjectHelper().resolveFile(prop); 218 try { 219 URL url = f.toURI().toURL(); 220 if (!f.exists()) { 221 url = new URL (url.toExternalForm() + "/"); } 223 result.add(url); 224 } catch (MalformedURLException e) { 225 ErrorManager.getDefault().notify(e); 226 } 227 } 228 } 229 sourceRootURLs = Collections.unmodifiableList(result); 230 } 231 } 232 return sourceRootURLs.toArray(new URL [sourceRootURLs.size()]); 233 } 234 }); 235 } 236 237 241 public void addPropertyChangeListener (PropertyChangeListener listener) { 242 this.support.addPropertyChangeListener (listener); 243 } 244 245 249 public void removePropertyChangeListener (PropertyChangeListener listener) { 250 this.support.removePropertyChangeListener (listener); 251 } 252 253 254 334 340 public String getRootDisplayName (String rootName, String propName) { 341 if (rootName == null || rootName.length() ==0) { 342 if (isTest && RailsProjectGenerator.DEFAULT_TEST_SRC_NAME.equals(propName)) { rootName = DEFAULT_TEST_LABEL; 345 } 346 else if (!isTest && RailsProjectGenerator.DEFAULT_SRC_NAME.equals(propName)) { rootName = DEFAULT_SOURCE_LABEL; 348 } 349 else { 350 String propValue = evaluator.getProperty(propName); 353 File sourceRoot = propValue == null ? null : helper.getRakeProjectHelper().resolveFile(propValue); 354 rootName = createInitialDisplayName(sourceRoot); 355 } 356 } 357 return rootName; 358 } 359 360 365 public String createInitialDisplayName (File sourceRoot) { 366 String rootName; 367 if (sourceRoot != null) { 368 String srPath = sourceRoot.getAbsolutePath(); 369 String pdPath = projectDir.getAbsolutePath() + File.separatorChar; 370 if (srPath.startsWith(pdPath)) { 371 rootName = srPath.substring(pdPath.length()); 372 } 373 else { 374 rootName = sourceRoot.getAbsolutePath(); 375 } 376 } 377 else { 378 rootName = isTest ? DEFAULT_TEST_LABEL : DEFAULT_SOURCE_LABEL; 379 } 380 return rootName; 381 } 382 383 388 public boolean isTest () { 389 return this.isTest; 390 } 391 392 private void resetCache (boolean isXMLChange, String propName) { 393 boolean fire = false; 394 synchronized (this) { 395 if (isXMLChange) { 397 this.sourceRootProperties = null; 398 this.sourceRootNames = null; 399 this.sourceRoots = null; 400 this.sourceRootURLs = null; 401 fire = true; 402 } else if (propName == null || (sourceRootProperties != null && sourceRootProperties.contains(propName))) { 403 this.sourceRoots = null; 404 this.sourceRootURLs = null; 405 fire = true; 406 } 407 } 408 if (fire) { 409 if (isXMLChange) { 410 this.support.firePropertyChange (PROP_ROOT_PROPERTIES,null,null); 411 } 412 this.support.firePropertyChange (PROP_ROOTS,null,null); 413 } 414 } 415 416 private void readProjectMetadata () { 417 Element cfgEl = helper.getPrimaryConfigurationData(true); 418 NodeList nl = cfgEl.getElementsByTagNameNS(RailsProjectType.PROJECT_CONFIGURATION_NAMESPACE, elementName); 419 assert nl.getLength() == 0 || nl.getLength() == 1 : "Illegal project.xml"; List <String > rootProps = new ArrayList <String >(); 421 List <String > rootNames = new ArrayList <String >(); 422 if (nl.getLength()==1) { 424 NodeList roots = ((Element )nl.item(0)).getElementsByTagNameNS(RailsProjectType.PROJECT_CONFIGURATION_NAMESPACE, "root"); for (int i=0; i<roots.getLength(); i++) { 426 Element root = (Element ) roots.item(i); 427 String value = root.getAttribute("id"); assert value.length() > 0 : "Illegal project.xml"; 429 rootProps.add(value); 430 value = root.getAttribute("name"); rootNames.add (value); 432 } 433 } 434 this.sourceRootProperties = Collections.unmodifiableList(rootProps); 435 this.sourceRootNames = Collections.unmodifiableList(rootNames); 436 } 437 438 private class ProjectMetadataListener implements PropertyChangeListener ,RakeProjectListener { 439 440 public void propertyChange(PropertyChangeEvent evt) { 441 resetCache (false,evt.getPropertyName()); 442 } 443 444 public void configurationXmlChanged(RakeProjectEvent ev) { 445 resetCache (true,null); 446 } 447 448 public void propertiesChanged(RakeProjectEvent ev) { 449 } 451 } 452 453 } 454 | Popular Tags |