From 67f7ea767777749dfbef9491c17d13a312cdd325 Mon Sep 17 00:00:00 2001 From: LWJGL2 Date: Thu, 13 Nov 2025 17:21:55 +1000 Subject: [PATCH 1/3] Fixed Compile On Save and JPDA Debugger when program running --- .../impl/indexing/RepositoryUpdater.java | 25 ++++---- .../jpda/projects/SourcePathProviderImpl.java | 57 +++++++++++-------- 2 files changed, 49 insertions(+), 33 deletions(-) diff --git a/ide/parsing.indexing/src/org/netbeans/modules/parsing/impl/indexing/RepositoryUpdater.java b/ide/parsing.indexing/src/org/netbeans/modules/parsing/impl/indexing/RepositoryUpdater.java index 0c7cbb9e7a41..487806bfe2f9 100644 --- a/ide/parsing.indexing/src/org/netbeans/modules/parsing/impl/indexing/RepositoryUpdater.java +++ b/ide/parsing.indexing/src/org/netbeans/modules/parsing/impl/indexing/RepositoryUpdater.java @@ -111,7 +111,6 @@ import org.openide.util.RequestProcessor; import org.openide.util.TopologicalSortException; import org.openide.util.Union2; -import org.openide.util.lookup.ServiceProvider; import static org.netbeans.modules.parsing.impl.indexing.Debug.printCollection; import static org.netbeans.modules.parsing.impl.indexing.Debug.printMap; @@ -119,6 +118,7 @@ import org.netbeans.modules.parsing.impl.indexing.implspi.CacheFolderProvider; import org.netbeans.modules.parsing.impl.indexing.implspi.ContextProvider; import org.openide.util.lookup.Lookups; +import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; /** * @@ -1316,6 +1316,7 @@ public void atomicUnlock(AtomicLockEvent e) { private final Task worker; private RepositoryUpdater () { +// LOGGER.setLevel(Level.ALL); LOGGER.log(Level.FINE, "netbeans.indexing.notInterruptible={0}", NOT_INTERRUPTIBLE); //NOI18N LOGGER.log(Level.FINE, "netbeans.indexing.recursiveListeners={0}", rootsListeners.hasRecursiveListeners()); //NOI18N LOGGER.log(Level.FINE, "FILE_LOCKS_DELAY={0}", FILE_LOCKS_DELAY); //NOI18N @@ -5953,8 +5954,7 @@ public void schedule (Work work, boolean wait) { } followUpWorksSorted = false; - - if (!scheduled && (protectedOwners.isEmpty() || offProtectedMode == Thread.currentThread())) { + if (!scheduled && (isEmptyProtectedOwners() || offProtectedMode == Thread.currentThread())) { scheduled = true; LOGGER.fine("scheduled = true"); //NOI18N WORKER.submit(this); @@ -5968,6 +5968,11 @@ public void schedule (Work work, boolean wait) { } } + public boolean isEmptyProtectedOwners() { + protectedOwners.removeIf(Objects::isNull); + return protectedOwners.isEmpty(); + } + void cancelAll(@NullAllowed final Runnable postCleanTask) throws TimeoutException { synchronized (todo) { if (!allCancelled) { @@ -6030,7 +6035,7 @@ public void enterProtectedMode(@NullAllowed Long id) { public void exitProtectedMode(@NullAllowed Long id, @NullAllowed Runnable followupTask) { synchronized (todo) { - if (protectedOwners.isEmpty()) { + if (isEmptyProtectedOwners()) { throw new IllegalStateException("Calling exitProtectedMode without enterProtectedMode"); //NOI18N } @@ -6046,7 +6051,7 @@ public void exitProtectedMode(@NullAllowed Long id, @NullAllowed Runnable follow LOGGER.log(Level.FINE, "Exiting protected mode: {0}", protectedOwners.toString()); //NOI18N } - if (protectedOwners.isEmpty()) { + if (isEmptyProtectedOwners()) { // in normal mode again, restart all delayed jobs final List tasks = followupTasks != null ? followupTasks : Collections.emptyList(); followupTasks = null; @@ -6072,7 +6077,7 @@ T runOffProtecedMode(@NonNull final Callable call) throws Exception { public boolean isInProtectedMode() { synchronized (todo) { - return !protectedOwners.isEmpty(); + return !isEmptyProtectedOwners(); } } @@ -6116,7 +6121,7 @@ public Void call() throws Exception { RunWhenScanFinishedSupport.performScan(() -> _run(), globalLookup); } finally { synchronized (todo) { - if ((!protectedOwners.isEmpty() && offProtectedMode == null) || todo.isEmpty()) { + if ((!isEmptyProtectedOwners() && offProtectedMode == null) || todo.isEmpty()) { scheduled = false; LOGGER.fine("scheduled = false"); //NOI18N } else { @@ -6226,7 +6231,7 @@ private void _run() { private Work getWork () { synchronized (todo) { Work w; - if ((protectedOwners.isEmpty() || offProtectedMode != null) && !todo.isEmpty()) { + if ((isEmptyProtectedOwners() || offProtectedMode != null) && !todo.isEmpty()) { w = todo.remove(0); if (w instanceof FileListWork && ((FileListWork) w).isFollowUpJob() && !followUpWorksSorted) { @@ -6514,12 +6519,12 @@ public Controller() { @Override public void enterProtectedMode() { - worker.enterProtectedMode(Thread.currentThread().getId()); +// worker.enterProtectedMode(Thread.currentThread().getId()); } @Override public void exitProtectedMode(Runnable followUpTask) { - worker.exitProtectedMode(Thread.currentThread().getId(), followUpTask); +// worker.exitProtectedMode(Thread.currentThread().getId(), followUpTask); } @Override diff --git a/java/debugger.jpda.projects/src/org/netbeans/modules/debugger/jpda/projects/SourcePathProviderImpl.java b/java/debugger.jpda.projects/src/org/netbeans/modules/debugger/jpda/projects/SourcePathProviderImpl.java index 2f7aab051214..fa58364f3a59 100644 --- a/java/debugger.jpda.projects/src/org/netbeans/modules/debugger/jpda/projects/SourcePathProviderImpl.java +++ b/java/debugger.jpda.projects/src/org/netbeans/modules/debugger/jpda/projects/SourcePathProviderImpl.java @@ -125,7 +125,7 @@ public SourcePathProviderImpl (ContextProvider contextProvider) { Map properties = contextProvider.lookupFirst(null, Map.class); Set srcRootsToListenForArtifactsUpdates = null; - + // 2) get default allSourceRoots of source roots used for stepping if (logger.isLoggable(Level.FINE)) logger.fine("Have properties = "+properties); if (properties != null) { @@ -151,23 +151,23 @@ public SourcePathProviderImpl (ContextProvider contextProvider) { }); } smartSteppingSourcePath = jdkCP == null ? - smartSteppingSourcePath : + smartSteppingSourcePath : ClassPathSupport.createProxyClassPath ( new ClassPath[] { - jdkCP, + jdkCP, smartSteppingSourcePath, } - ); + ); unorderedOriginalSourcePath = smartSteppingSourcePath; Map orderIndexes = getSourceRootsOrder(baseDir); String[] unorderedOriginalRoots = getSourceRoots(unorderedOriginalSourcePath); String[] sortedOriginalRoots = new String[unorderedOriginalRoots.length]; sourcePathPermutation = createPermutation(unorderedOriginalRoots, - orderIndexes, - sortedOriginalRoots); + orderIndexes, + sortedOriginalRoots); smartSteppingSourcePath = createClassPath(sortedOriginalRoots); - + originalSourcePath = smartSteppingSourcePath; Set disabledRoots; @@ -201,16 +201,29 @@ public SourcePathProviderImpl (ContextProvider contextProvider) { globalCP ); */ + String sourcepathSeperator = ","; + String listeningCP = (String) properties.get("listeningCP"); if (listeningCP != null) { boolean isSourcepath = false; if ("sourcepath".equalsIgnoreCase(listeningCP)) { - listeningCP = ((ClassPath) properties.get ("sourcepath")).toString(ClassPath.PathConversionMode.SKIP); + sourcepathSeperator = File.pathSeparator; + listeningCP = ((ClassPath) properties.get("sourcepath")).toString(ClassPath.PathConversionMode.SKIP); isSourcepath = true; } srcRootsToListenForArtifactsUpdates = new HashSet(); - for (String cp : listeningCP.split(File.pathSeparator)) { - logger.log(Level.FINE, "Listening cp = ''{0}''", cp); + + List list = new ArrayList<>(); + list.addAll(Arrays.asList(listeningCP.split(sourcepathSeperator))); + for (String string : listeningCP.split(";")) { + list.add(string.replace(",", "")); + } + + for (String cp : list) { + cp = cp.replace(",", ""); + cp = cp.replace(";", ""); +// for (String cp : listeningCP.split(File.pathSeparator)) { + logger.log(Level.INFO, "Listening cp = ''{0}''", cp); File f = new File(cp); f = FileUtil.normalizeFile(f); URL entry = FileUtil.urlForArchiveOrDir(f); @@ -235,12 +248,12 @@ public SourcePathProviderImpl (ContextProvider contextProvider) { pathRegistryListener = new PathRegistryListener(); GlobalPathRegistry.getDefault().addGlobalPathRegistryListener( WeakListeners.create(GlobalPathRegistryListener.class, - pathRegistryListener, - GlobalPathRegistry.getDefault())); + pathRegistryListener, + GlobalPathRegistry.getDefault())); JavaPlatformManager.getDefault ().addPropertyChangeListener( WeakListeners.propertyChange(pathRegistryListener, - JavaPlatformManager.getDefault())); - + JavaPlatformManager.getDefault())); + List allSourceRoots = new ArrayList(); Set preferredRoots = new HashSet(); Set addedBinaryRoots = new HashSet(); @@ -311,16 +324,16 @@ public SourcePathProviderImpl (ContextProvider contextProvider) { } Set disabledRoots = getRemoteDisabledSourceRoots(); - + synchronized (this) { unorderedOriginalSourcePath = createClassPath(allSourceRoots.toArray(new FileObject[0])); - + Map orderIndexes = getRemoteSourceRootsOrder(); String[] unorderedOriginalRoots = getSourceRoots(unorderedOriginalSourcePath); String[] sorterOriginalRoots = new String[unorderedOriginalRoots.length]; sourcePathPermutation = createPermutation(unorderedOriginalRoots, - orderIndexes, - sorterOriginalRoots); + orderIndexes, + sorterOriginalRoots); originalSourcePath = createClassPath(sorterOriginalRoots); projectSourceRoots = getSourceRoots(originalSourcePath); @@ -342,13 +355,13 @@ public SourcePathProviderImpl (ContextProvider contextProvider) { } } } - + if (verbose) System.out.println ("SPPI: init originalSourcePath " + originalSourcePath); if (verbose) System.out.println ( - "SPPI: init smartSteppingSourcePath " + smartSteppingSourcePath + "SPPI: init smartSteppingSourcePath " + smartSteppingSourcePath ); if (logger.isLoggable(Level.FINE)) { @@ -1434,9 +1447,7 @@ public void artifactsUpdated(Iterable artifacts) { boolean canFixClasses = Properties.getDefault().getProperties("debugger.options.JPDA"). getBoolean("ApplyCodeChangesOnSave", CAN_FIX_CLASSES_AUTOMATICALLY); - if (logger.isLoggable(Level.FINE)) { - logger.fine("artifactsUpdated("+artifacts+") error = '"+error+"', canFixClasses = "+canFixClasses); - } + logger.info("artifactsUpdated("+artifacts+") error = '"+error+"', canFixClasses = "+canFixClasses); if (error == null) { if (!canFixClasses) { for (File f : artifacts) { From 666fc94b8cd893baa6a8e04c932940d7570dc262 Mon Sep 17 00:00:00 2001 From: LWJGL2 Date: Thu, 13 Nov 2025 17:36:45 +1000 Subject: [PATCH 2/3] Fix JSP java scanning on non web applicaton project and JSP Link provider fix --- .../modules/web/api/webmodule/WebModule.java | 66 ++++++++++++++++++- .../web/core/syntax/JspHyperlinkProvider.java | 23 ++++--- 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/enterprise/api.web.webmodule/src/org/netbeans/modules/web/api/webmodule/WebModule.java b/enterprise/api.web.webmodule/src/org/netbeans/modules/web/api/webmodule/WebModule.java index c521b5dd2e14..e569b6bb2629 100644 --- a/enterprise/api.web.webmodule/src/org/netbeans/modules/web/api/webmodule/WebModule.java +++ b/enterprise/api.web.webmodule/src/org/netbeans/modules/web/api/webmodule/WebModule.java @@ -19,8 +19,14 @@ package org.netbeans.modules.web.api.webmodule; +import java.beans.PropertyChangeListener; import java.util.Iterator; import org.netbeans.api.j2ee.core.Profile; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectUtils; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.Sources; import org.netbeans.modules.j2ee.dd.api.web.WebAppMetadata; import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; import org.netbeans.modules.web.spi.webmodule.WebModuleImplementation; @@ -103,17 +109,71 @@ private WebModule (WebModuleImplementation impl, WebModuleImplementation2 impl2) * to any web module. * @throws NullPointerException if the file parameter is null. */ - public static WebModule getWebModule (FileObject file) { + public static WebModule getWebModule(FileObject file) { Parameters.notNull("file", file); // NOI18N + Iterator it = implementations.allInstances().iterator(); while (it.hasNext()) { + WebModuleProvider impl = it.next(); - WebModule wm = impl.findWebModule (file); + WebModule wm = impl.findWebModule(file); if (wm != null) { return wm; } } - return null; + final WebModule webModule = new WebModule(null, new WebModuleImplementation2() { + @Override + public FileObject getDocumentBase() { + Project project = FileOwnerQuery.getOwner(file); + Sources sources = ProjectUtils.getSources(project); + for (SourceGroup group : sources.getSourceGroups("java")) { + FileObject root = group.getRootFolder(); + if (file.getPath().startsWith(root.getPath())) { + return root; // нашли src-папку, к которой относится файл + } + } + return project.getProjectDirectory(); + } + + @Override + public String getContextPath() { + return "/"; + } + + @Override + public Profile getJ2eeProfile() { + return Profile.JAVA_EE_8_FULL; + } + + @Override + public FileObject getWebInf() { + return null; + } + + @Override + public FileObject getDeploymentDescriptor() { + return null; + } + + @Override + public FileObject[] getJavaSources() { + return new FileObject[0]; + } + + @Override + public MetadataModel getMetadataModel() { + return null; + } + + @Override + public void addPropertyChangeListener(PropertyChangeListener listener) { + } + + @Override + public void removePropertyChangeListener(PropertyChangeListener listener) { + } + }); + return webModule; } /** diff --git a/enterprise/web.core.syntax/src/org/netbeans/modules/web/core/syntax/JspHyperlinkProvider.java b/enterprise/web.core.syntax/src/org/netbeans/modules/web/core/syntax/JspHyperlinkProvider.java index f17567b42ac1..e3f0a373d50b 100644 --- a/enterprise/web.core.syntax/src/org/netbeans/modules/web/core/syntax/JspHyperlinkProvider.java +++ b/enterprise/web.core.syntax/src/org/netbeans/modules/web/core/syntax/JspHyperlinkProvider.java @@ -22,11 +22,13 @@ import java.io.IOException; import java.util.Collections; import java.util.List; -import java.util.Objects; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import javax.lang.model.element.TypeElement; +import javax.servlet.jsp.tagext.TagFileInfo; +import javax.servlet.jsp.tagext.TagInfo; +import javax.servlet.jsp.tagext.TagLibraryInfo; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.JTextComponent; @@ -45,9 +47,6 @@ import org.netbeans.editor.BaseDocument; import org.netbeans.editor.Utilities; import org.netbeans.lib.editor.hyperlink.spi.HyperlinkProvider; -import org.netbeans.modules.web.jsps.parserapi.TagFileInfo; -import org.netbeans.modules.web.jsps.parserapi.TagInfo; -import org.netbeans.modules.web.jsps.parserapi.TagLibraryInfo; import org.openide.awt.StatusDisplayer; import org.openide.cookies.EditCookie; import org.openide.filesystems.FileObject; @@ -122,6 +121,12 @@ public void run() { result.set(containsAttribute(tokenSequence, "file")); } else if ("page".equals(sed.getName())) { result.set(containsAttribute(tokenSequence, "errorPage")); + + while (tokenSequence.moveNext() && tokenSequence.token().id() != JspTokenId.TAG) { + if (tokenSequence.token().id() == JspTokenId.ATTR_VALUE) { + result.set(true); + } + } } return; } @@ -416,11 +421,11 @@ public void run() { Phase.ELEMENTS_RESOLVED, new Worker() { - @Override - public TypeElement process(CompilationInfo info) { - return info.getElements().getTypeElement(className); - } - }); + @Override + public TypeElement process(CompilationInfo info) { + return info.getElements().getTypeElement(className); + } + }); ProgressUtils.runOffEventDispatchThread(compute, NbBundle.getMessage(JspHyperlinkProvider.class, "MSG_goto-source"), From 85ea4b9c73e2c51269e67cf8d7ad3d44099c53de Mon Sep 17 00:00:00 2001 From: LWJGL2 Date: Thu, 13 Nov 2025 18:47:09 +1000 Subject: [PATCH 3/3] CssPreprocessors support for Java SE project --- .../customizer/WebCompositePanelProvider.java | 6 + .../css/prep/util/CssPreprocessorUtils.java | 5 +- .../web/common/spi/ProjectWebRootQuery.java | 20 ++- .../modules/java/j2seproject/J2SEProject.java | 145 ++++++++++++++++++ 4 files changed, 171 insertions(+), 5 deletions(-) diff --git a/enterprise/web.project/src/org/netbeans/modules/web/project/ui/customizer/WebCompositePanelProvider.java b/enterprise/web.project/src/org/netbeans/modules/web/project/ui/customizer/WebCompositePanelProvider.java index b51523df94dc..bc7b7b99a5ea 100644 --- a/enterprise/web.project/src/org/netbeans/modules/web/project/ui/customizer/WebCompositePanelProvider.java +++ b/enterprise/web.project/src/org/netbeans/modules/web/project/ui/customizer/WebCompositePanelProvider.java @@ -223,6 +223,12 @@ public static WebCompositePanelProvider createWebServicesCategory() { public static ProjectCustomizer.CompositeCategoryProvider createCssPreprocessors() { return CssPreprocessorsUI.getDefault().createCustomizer(); } + + @ProjectCustomizer.CompositeCategoryProvider.Registration( + projectType = "org-netbeans-modules-java-j2seproject", position = 500) + public static ProjectCustomizer.CompositeCategoryProvider createCssPreprocessorsj2se() { + return CssPreprocessorsUI.getDefault().createCustomizer(); + } @ProjectCustomizer.CompositeCategoryProvider.Registration( projectType="org-netbeans-modules-web-project", diff --git a/ide/css.prep/src/org/netbeans/modules/css/prep/util/CssPreprocessorUtils.java b/ide/css.prep/src/org/netbeans/modules/css/prep/util/CssPreprocessorUtils.java index e874a4ab9952..af27f0d3d55c 100644 --- a/ide/css.prep/src/org/netbeans/modules/css/prep/util/CssPreprocessorUtils.java +++ b/ide/css.prep/src/org/netbeans/modules/css/prep/util/CssPreprocessorUtils.java @@ -144,6 +144,9 @@ private static String processCompilerOptions(String compilerOptions, @NullAllowe public static FileObject getWebRoot(Project project, FileObject fileObject) { ProjectWebRootProvider projectWebRootProvider = getProjectWebRootProvider(project); if (projectWebRootProvider == null) { + if (projectWebRootProvider == null) { + return project.getProjectDirectory(); + } return null; } return projectWebRootProvider.getWebRoot(fileObject); @@ -153,7 +156,7 @@ public static FileObject getWebRoot(Project project, FileObject fileObject) { public static FileObject getWebRoot(Project project) { ProjectWebRootProvider projectWebRootProvider = getProjectWebRootProvider(project); if (projectWebRootProvider == null) { - return null; + return project.getProjectDirectory(); } Collection webRoots = projectWebRootProvider.getWebRoots(); if (webRoots.isEmpty()) { diff --git a/ide/web.common/src/org/netbeans/modules/web/common/spi/ProjectWebRootQuery.java b/ide/web.common/src/org/netbeans/modules/web/common/spi/ProjectWebRootQuery.java index 1fd8e10f0a58..33483dde85e9 100644 --- a/ide/web.common/src/org/netbeans/modules/web/common/spi/ProjectWebRootQuery.java +++ b/ide/web.common/src/org/netbeans/modules/web/common/spi/ProjectWebRootQuery.java @@ -18,16 +18,20 @@ */ package org.netbeans.modules.web.common.spi; +import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; +import java.util.List; import org.netbeans.api.annotations.common.NonNull; import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectUtils; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.Sources; import org.openide.filesystems.FileObject; import org.openide.util.Parameters; /** - * Clients uses this class to obtain a web root for a file within a web-like project. + * Clients uses this class to obtain a web root for a file within a web-like project. * * @author marekfukala */ @@ -52,7 +56,7 @@ public static FileObject getWebRoot(FileObject file) { ProjectWebRootProvider provider = project.getLookup().lookup(ProjectWebRootProvider.class); if (provider != null) { FileObject root = provider.getWebRoot(file); - if(root == null) { + if (root == null) { return null; } @@ -67,6 +71,7 @@ public static FileObject getWebRoot(FileObject file) { * * @param project a project which you want to get web roots for * @return collection of web roots of the given project, can be empty but never {@code null} + * * @since 1.57 */ @NonNull @@ -74,7 +79,14 @@ public static Collection getWebRoots(@NonNull Project project) { Parameters.notNull("project", project); // NOI18N ProjectWebRootProvider provider = project.getLookup().lookup(ProjectWebRootProvider.class); if (provider == null) { - return Collections.emptyList(); + List objects = new ArrayList<>(); + Sources sources = ProjectUtils.getSources(project); + for (SourceGroup group : sources.getSourceGroups("java")) { + FileObject root = group.getRootFolder(); + objects.add(root); + } + objects.add(project.getProjectDirectory()); + return objects; } Collection webRoots = provider.getWebRoots(); assert webRoots != null : "WebRoots cannot be null in " + provider.getClass().getName(); diff --git a/java/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java b/java/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java index 7ec8541c48c4..95bbc8263238 100644 --- a/java/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java +++ b/java/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.lang.ref.Reference; import java.lang.ref.WeakReference; +import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; @@ -98,6 +99,7 @@ import org.netbeans.spi.project.support.ant.PropertyUtils; import org.netbeans.spi.project.support.ant.ReferenceHelper; import org.netbeans.spi.project.ui.PrivilegedTemplates; +import org.netbeans.spi.project.ui.ProjectOpenedHook; import org.netbeans.spi.project.ui.RecommendedTemplates; import org.netbeans.spi.project.ui.support.UILookupMergerSupport; import org.netbeans.spi.queries.FileBuiltQueryImplementation; @@ -117,6 +119,10 @@ import org.w3c.dom.NodeList; import org.netbeans.spi.whitelist.support.WhiteListQueryMergerSupport; +import org.openide.filesystems.FileAttributeEvent; +import org.openide.filesystems.FileChangeListener; +import org.openide.filesystems.FileEvent; +import org.openide.filesystems.FileRenameEvent; import org.openide.filesystems.URLMapper; import org.openide.loaders.DataObject; import org.openide.modules.SpecificationVersion; @@ -278,6 +284,144 @@ public Lookup getLookup() { public AntProjectHelper getAntProjectHelper() { return helper; } + + private static class SiteRootFolderListener implements FileChangeListener { + + private final J2SEProject p; + private final FileObject siteRootFolder; + + SiteRootFolderListener(J2SEProject p) { + this.p = p; + siteRootFolder = p.getProjectDirectory(); + } + + @Override + public void fileFolderCreated(FileEvent fe) { + checkPreprocessors(fe.getFile()); + } + + @Override + public void fileDataCreated(FileEvent fe) { + checkPreprocessors(fe.getFile()); + } + + @Override + public void fileChanged(FileEvent fe) { + checkPreprocessors(fe.getFile()); + } + + @Override + public void fileDeleted(FileEvent fe) { + checkPreprocessors(fe.getFile()); + } + + @Override + public void fileRenamed(FileRenameEvent fe) { + // XXX: notify BrowserReload about filename change + checkPreprocessors(fe.getFile(), fe.getName(), fe.getExt()); + } + + @Override + public void fileAttributeChanged(FileAttributeEvent fe) { + } + + private void checkPreprocessors(FileObject fileObject) { + try { + ClassLoader globalCl = Lookup.getDefault().lookup(ClassLoader.class); + Class clazz = Class.forName("org.netbeans.modules.web.common.api.CssPreprocessors", true, globalCl); + Object instance = clazz.getMethod("getDefault").invoke(null); + Method processMethod = clazz.getMethod("process", Project.class, FileObject.class); + processMethod.invoke(instance, p, fileObject); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void checkPreprocessors(FileObject fileObject, String originalName, String originalExtension) { + try { + ClassLoader globalCl = Lookup.getDefault().lookup(ClassLoader.class); + Class clazz = Class.forName("org.netbeans.modules.web.common.api.CssPreprocessors", true, globalCl); + Object instance = clazz.getMethod("getDefault").invoke(null); + Method processMethod = clazz.getMethod("process", Project.class, FileObject.class, String.class, String.class); + processMethod.invoke(instance, p, fileObject, originalName, originalExtension); + } catch (Exception e) { + e.printStackTrace(); + } + } + +// private void checkPreprocessors(FileObject fileObject) { +// CssPreprocessors.getDefault().process(p, fileObject); +// } +// +// private void checkPreprocessors(FileObject fileObject, String originalName, String originalExtension) { +// CssPreprocessors.getDefault().process(p, fileObject, originalName, originalExtension); +// } + } + + private static class OpenHookImpl extends ProjectOpenedHook implements PropertyChangeListener { + private final J2SEProject project; + private FileChangeListener siteRootChangesListener; + + // @GuardedBy("this") + private File siteRootFolder; + + + public OpenHookImpl(J2SEProject project) { + this.project = project; + } + + @Override + protected void projectOpened() { + addSiteRootListener(); + } + + + @Override + protected void projectClosed() { + removeSiteRootListener(); + } + + private synchronized void addSiteRootListener() { + assert siteRootFolder == null : "Should not be listening to " + siteRootFolder; + FileObject siteRoot = project.getProjectDirectory(); + if (siteRoot == null) { + return; + } + siteRootFolder = FileUtil.toFile(siteRoot); + if (siteRootFolder == null) { + // should not happen + LOG.log(Level.WARNING, "File not found for FileObject: {0}", siteRoot); + return; + } + siteRootChangesListener = new SiteRootFolderListener(project); + FileUtil.addRecursiveListener(siteRootChangesListener, siteRootFolder); + } + + private synchronized void removeSiteRootListener() { + if (siteRootFolder == null) { + // no listener + return; + } + try { + FileUtil.removeRecursiveListener(siteRootChangesListener, siteRootFolder); + } catch (IllegalArgumentException ex) { + // #216349 + LOG.log(Level.INFO, null, ex); + } + siteRootFolder = null; + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + // change in project properties +// if (ClientSideProjectConstants.PROJECT_SITE_ROOT_FOLDER.equals(evt.getPropertyName())) { + synchronized (this) { + removeSiteRootListener(); + addSiteRootListener(); + } +// } + } + } private Lookup createLookup(final AuxiliaryConfiguration aux, final ProjectOperations.Callback opsCallback) { final PlatformChangedHook platformChangedHook = new PlatformChangedHook(); @@ -289,6 +433,7 @@ private Lookup createLookup(final AuxiliaryConfiguration aux, final ProjectOpera helper.createCacheDirectoryProvider(), helper.createAuxiliaryProperties(), refHelper.createSubprojectProvider(), + new OpenHookImpl(this), LogicalViewProviders.createBuilder( this, eval,