This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 243650
Collapse All | Expand All

(-)a/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/csm/core/DeepReparsingUtils.java (-1 / +1 lines)
Lines 500-506 Link Here
500
        }
500
        }
501
    }
501
    }
502
    
502
    
503
    static String toString(Collection<?> files) {
503
    public static String toString(Collection<?> files) {
504
        StringBuilder out = new StringBuilder();
504
        StringBuilder out = new StringBuilder();
505
        for (Object elem : files) {
505
        for (Object elem : files) {
506
            if (elem instanceof FileImpl) {
506
            if (elem instanceof FileImpl) {
(-)a/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/csm/core/ModelImpl.java (-6 / +11 lines)
Lines 381-387 Link Here
381
381
382
    @Override
382
    @Override
383
    public Cancellable enqueue(Runnable task, CharSequence name) {
383
    public Cancellable enqueue(Runnable task, CharSequence name) {
384
        return enqueue(userTasksProcessor, task, clientTaskPrefix + " :" + name); // NOI18N
384
        return enqueueOrCreate(true, userTasksProcessor, task, clientTaskPrefix + " :" + name); // NOI18N
385
    }
385
    }
386
386
387
    public static ModelImpl instance() {
387
    public static ModelImpl instance() {
Lines 389-397 Link Here
389
    }
389
    }
390
390
391
    public RequestProcessor.Task enqueueModelTask(Runnable task, String name) {
391
    public RequestProcessor.Task enqueueModelTask(Runnable task, String name) {
392
        return enqueue(modelProcessor, task, modelTaskPrefix + ": " + name); // NOI18N
392
        return enqueueOrCreate(true, modelProcessor, task, modelTaskPrefix + ": " + name); // NOI18N
393
    }
393
    }
394
    
394
395
    public RequestProcessor.Task createModelTask(Runnable task, String name) {
396
        return enqueueOrCreate(true, modelProcessor, task, modelTaskPrefix + ": " + name); // NOI18N
397
    }
398
395
    public static boolean isModelRequestProcessorThread() {
399
    public static boolean isModelRequestProcessorThread() {
396
        return ModelImpl.instance().modelProcessor.isRequestProcessorThread();
400
        return ModelImpl.instance().modelProcessor.isRequestProcessorThread();
397
    }
401
    }
Lines 405-415 Link Here
405
        task.waitFinished();
409
        task.waitFinished();
406
    }
410
    }
407
    
411
    
408
    private RequestProcessor.Task enqueue(RequestProcessor processor, final Runnable task, final String taskName) {
412
    private RequestProcessor.Task enqueueOrCreate(boolean post, RequestProcessor processor, final Runnable task, final String taskName) {
409
        if (TraceFlags.TRACE_182342_BUG) {
413
        if (TraceFlags.TRACE_182342_BUG) {
410
            new Exception(taskName).printStackTrace(System.err);
414
            new Exception(taskName).printStackTrace(System.err);
411
        }
415
        }
412
        return processor.post(new Runnable() {
416
        final Runnable r = new Runnable() {
413
            @Override
417
            @Override
414
            public void run() {
418
            public void run() {
415
                String oldName = Thread.currentThread().getName();
419
                String oldName = Thread.currentThread().getName();
Lines 422-428 Link Here
422
                    Thread.currentThread().setName(oldName);
426
                    Thread.currentThread().setName(oldName);
423
                }
427
                }
424
            }
428
            }
425
        });
429
        };
430
        return post ? processor.post(r) : processor.create(r);
426
    }
431
    }
427
432
428
    @Override
433
    @Override
(-)a/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/csm/core/NativeProjectListenerImpl.java (-269 lines)
Removed Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 * 
27
 * Contributor(s):
28
 * 
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
31
 * Microsystems, Inc. All Rights Reserved.
32
 * 
33
 * If you wish your version of this file to be governed by only the CDDL
34
 * or only the GPL Version 2, indicate your decision by adding
35
 * "[Contributor] elects to include this software in this distribution
36
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
37
 * single choice of license, a recipient has the option to distribute
38
 * your version of this file under either the CDDL, the GPL Version 2 or
39
 * to extend the choice of license to its licensees as provided above.
40
 * However, if you add GPL Version 2 code and therefore, elected the GPL
41
 * Version 2 license, then the option applies only if the new code is
42
 * made subject to such option by the copyright holder.
43
 */
44
45
package org.netbeans.modules.cnd.modelimpl.csm.core;
46
47
import java.util.ArrayList;
48
import java.util.List;
49
import java.util.logging.Level;
50
import java.util.logging.Logger;
51
import org.netbeans.modules.cnd.api.project.NativeFileItem;
52
import org.netbeans.modules.cnd.api.project.NativeProject;
53
import org.netbeans.modules.cnd.api.project.NativeProjectItemsListener;
54
import org.netbeans.modules.cnd.modelimpl.debug.TraceFlags;
55
import org.netbeans.modules.cnd.modelimpl.platform.ModelSupport;
56
import org.netbeans.modules.cnd.modelimpl.repository.RepositoryUtils;
57
58
/**
59
 * Implementation of the NativeProjectItemsListener interface
60
 * @author Vladimir Kvashin
61
 */
62
// package-local
63
class NativeProjectListenerImpl implements NativeProjectItemsListener {
64
    private static final boolean TRACE;
65
    private static final Logger LOG = Logger.getLogger("NativeProjectListenerImpl"); // NOI18N
66
    static {
67
        TRACE = LOG.isLoggable(Level.FINE);
68
    }
69
    
70
    private final NativeProject nativeProject;
71
    private final ProjectBase projectBase;
72
    private volatile boolean enabledEventsHandling = true;
73
74
    public NativeProjectListenerImpl(ModelImpl model, NativeProject nativeProject, ProjectBase project) {
75
        this.nativeProject = nativeProject;
76
        this.projectBase = project;
77
    }
78
79
    @Override
80
    public void filesAdded(List<NativeFileItem> fileItems) {
81
        if (TRACE) {
82
            String title = "Native event filesAdded:" + fileItems.size(); // NOI18N
83
            LOG.log(Level.INFO, title + "\n" +DeepReparsingUtils.toString(fileItems), new Exception(title));
84
        }
85
        if (enabledEventsHandling) {
86
            ArrayList<NativeFileItem> list = new ArrayList<>();
87
            for (NativeFileItem item : fileItems) {
88
                if (!item.isExcluded()) {
89
                    list.add(item);
90
                }
91
            }            
92
            itemsAddedImpl(list);
93
        } else {
94
            if (TraceFlags.TIMING) {
95
                LOG.log(Level.INFO, "skipped filesAdded(list) {0}...", nativeProject.getProjectDisplayName());
96
            }
97
        }
98
    }
99
100
    @Override
101
    public void filesRemoved(List<NativeFileItem> fileItems) {
102
        if (TRACE) {
103
            String title = "Native event filesRemoved:" + fileItems.size(); // NOI18N
104
            LOG.log(Level.INFO, title + "\n" +DeepReparsingUtils.toString(fileItems), new Exception(title));
105
        }
106
        if (enabledEventsHandling) {
107
            itemsRemovedImpl(fileItems);
108
        } else {
109
            if (TraceFlags.TIMING) {
110
                LOG.log(Level.INFO, "skipped filesRemoved(list) {0}...", nativeProject.getProjectDisplayName());
111
            }
112
        }
113
    }
114
115
    @Override
116
    public void fileRenamed(String oldPath, NativeFileItem newFileIetm){
117
        if (TRACE) {
118
            LOG.log(Level.INFO, "Native event fileRenamed:\tOld Name:"+oldPath+ "\tNew Name:"+newFileIetm.getAbsolutePath(), new Exception("fileRenamed"));
119
        }
120
        if (!enabledEventsHandling) {
121
            LOG.log(Level.INFO, "UNEXPECTED fileRenamed {0}...", nativeProject.getProjectDisplayName());
122
        }
123
	itemRenamedImpl(oldPath, newFileIetm);
124
    }
125
126
    /*package*/
127
    final void enableListening(boolean enable) {
128
        if (TraceFlags.TIMING) {
129
            LOG.log(Level.INFO, "\n%{0} ProjectListeners {1}...", new Object[] {enable ? "enable" : "disable",
130
                    nativeProject.getProjectDisplayName()});
131
        }
132
        enabledEventsHandling = enable;
133
    }
134
135
    @Override
136
    public void filesPropertiesChanged(final List<NativeFileItem> fileItems) {
137
        if (TRACE) {
138
            String title = "Native event filesPropertiesChanged:" + fileItems.size(); // NOI18N
139
            LOG.log(Level.INFO, title + "\n" +DeepReparsingUtils.toString(fileItems), new Exception(title));
140
        }
141
        if (enabledEventsHandling) {
142
            itemsPropertiesChangedImpl(fileItems, false);
143
        } else {
144
            if (TraceFlags.TIMING) {
145
                LOG.log(Level.INFO, "skipped filesPropertiesChanged(list) {0}...", nativeProject.getProjectDisplayName());
146
            }
147
        }
148
    }
149
150
    @Override
151
    public void filesPropertiesChanged() {
152
        List<NativeFileItem> allFiles = nativeProject.getAllFiles();
153
        if (TRACE) {
154
            String title = "Native event projectPropertiesChanged:" + allFiles.size(); // NOI18N
155
            LOG.log(Level.INFO, title, new Exception(title));
156
        }
157
        if (enabledEventsHandling) {
158
            ArrayList<NativeFileItem> list = new ArrayList<>();
159
            for(NativeFileItem item : allFiles){
160
                if (!item.isExcluded()) {
161
                    switch(item.getLanguage()){
162
                        case C:
163
                        case CPP:
164
                        case FORTRAN:
165
                            list.add(item);
166
                            break;
167
                        default:
168
                            break;
169
                    }
170
                }
171
            }
172
            itemsPropertiesChangedImpl(list, true);
173
        } else {
174
            if (TraceFlags.TIMING) {
175
                LOG.log(Level.INFO, "skipped filesPropertiesChanged {0}...", nativeProject.getProjectDisplayName());
176
            }
177
        }
178
    }
179
180
    @Override
181
    public void projectDeleted(NativeProject nativeProject) {
182
        if (TRACE) {
183
            LOG.log(Level.INFO, "projectDeleted {0}", nativeProject);  // NOI18N
184
        }
185
	RepositoryUtils.onProjectDeleted(nativeProject);
186
    }
187
188
    private void itemsAddedImpl(final List<NativeFileItem> items) {
189
        if (!items.isEmpty()){
190
            ModelImpl.instance().enqueueModelTask(new Runnable() {
191
192
                @Override
193
                public void run() {
194
                    try {
195
                        projectBase.onFileItemsAdded(items);
196
                    } catch( Exception e ) {
197
                        e.printStackTrace(System.err);
198
                    }
199
                }
200
            }, "Applying add items"); // NOI18N         
201
        }
202
    }
203
    
204
    private void itemsRemovedImpl(final List<NativeFileItem> items) {
205
        if (!items.isEmpty()) {
206
            ModelImpl.instance().enqueueModelTask(new Runnable() {
207
208
                @Override
209
                public void run() {
210
                    try {
211
                        projectBase.onFileItemsRemoved(items);
212
                    } catch( Exception e ) {
213
                        e.printStackTrace(System.err);
214
                    }
215
                }
216
            }, "Applying remove items"); // NOI18N                
217
        }
218
    }
219
220
    private void itemRenamedImpl(final String oldPath, final NativeFileItem newFileIetm) {
221
        ModelImpl.instance().enqueueModelTask(new Runnable() {
222
223
            @Override
224
            public void run() {
225
                try {
226
                    projectBase.onFileItemRenamed(oldPath, newFileIetm);
227
                } catch( Exception e ) {
228
                    //TODO: FIX (most likely in Makeproject: path == null in this situation,
229
                    //this cause NPE
230
                    e.printStackTrace(System.err);
231
                }
232
            }
233
        }, "Applying rename item"); // NOI18N          
234
    }
235
    
236
    private void itemsPropertiesChangedImpl(final List<NativeFileItem> items, final boolean invalidateLibraries) {
237
        if (!items.isEmpty()) {
238
            ModelImpl.instance().enqueueModelTask(new Runnable() {
239
240
                @Override
241
                public void run() {
242
                    try {
243
                        projectBase.onFileItemsPropertyChanged(items, invalidateLibraries);
244
                    } catch (Exception e) {
245
                        e.printStackTrace(System.err);
246
                    }
247
                }
248
            }, "Applying property changes"); // NOI18N            
249
        }
250
    }
251
252
    @Override
253
    public void fileOperationsStarted(NativeProject nativeProject) {
254
        if (TRACE) {
255
            String title = "fileOperationsStarted:" + nativeProject.getProjectDisplayName(); // NOI18N
256
            LOG.log(Level.INFO, title, new Exception(title));
257
        }        
258
        ModelSupport.instance().suspendDeleteEvents();
259
    }
260
261
    @Override
262
    public void fileOperationsFinished(NativeProject nativeProject) {
263
        if (TRACE) {
264
            String title = "fileOperationsFinished:" + nativeProject.getProjectDisplayName(); // NOI18N
265
            LOG.log(Level.INFO, title, new Exception(title));
266
        }
267
        ModelSupport.instance().resumeDeleteEvents();
268
    }
269
}
(-)a/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/csm/core/ProjectBase.java (-37 / +36 lines)
Lines 126-131 Link Here
126
import org.netbeans.modules.cnd.modelimpl.debug.TraceFlags;
126
import org.netbeans.modules.cnd.modelimpl.debug.TraceFlags;
127
import org.netbeans.modules.cnd.modelimpl.impl.services.FileInfoQueryImpl;
127
import org.netbeans.modules.cnd.modelimpl.impl.services.FileInfoQueryImpl;
128
import org.netbeans.modules.cnd.modelimpl.parser.apt.APTRestorePreprocStateWalker;
128
import org.netbeans.modules.cnd.modelimpl.parser.apt.APTRestorePreprocStateWalker;
129
import org.netbeans.modules.cnd.modelimpl.platform.CsmEventDispatcher;
129
import org.netbeans.modules.cnd.modelimpl.platform.ModelSupport;
130
import org.netbeans.modules.cnd.modelimpl.platform.ModelSupport;
130
import org.netbeans.modules.cnd.modelimpl.repository.ClassifierContainerKey;
131
import org.netbeans.modules.cnd.modelimpl.repository.ClassifierContainerKey;
131
import org.netbeans.modules.cnd.modelimpl.repository.FileContainerKey;
132
import org.netbeans.modules.cnd.modelimpl.repository.FileContainerKey;
Lines 810-848 Link Here
810
    }    
811
    }    
811
812
812
    public final void enableProjectListeners(boolean enable) {
813
    public final void enableProjectListeners(boolean enable) {
813
        synchronized (projectListenerLock) {
814
        if (platformProject instanceof NativeProject) {
814
            if (projectListener != null) {
815
            // should be in ProjectImpl, but leaving it here makes diff more clear
815
                projectListener.enableListening(enable);
816
            CsmEventDispatcher.getInstance().enableListening(this, enable);
817
        }
818
    }
819
820
    protected final void registerProjectListeners() {
821
        if (platformProject instanceof NativeProject) {
822
            // should be in ProjectImpl, but leaving it here makes diff more clear
823
            CsmEventDispatcher.getInstance().registerProject(this);
824
            NativeProject nativeProject = (NativeProject) platformProject;
825
            for (FileSystem fs : getIncludesFileSystems(nativeProject)) {
826
                CndFileSystemProvider.addFileSystemProblemListener(this, fs);
816
            }
827
            }
817
        }
828
        }
818
    }
829
    }
819
830
820
    protected final void registerProjectListeners() {
821
        synchronized (projectListenerLock) {
822
            if (platformProject instanceof NativeProject) {
823
                if (projectListener == null) {
824
                    projectListener = new NativeProjectListenerImpl(getModel(), (NativeProject) platformProject, this);
825
                }
826
                NativeProject nativeProject = (NativeProject) platformProject;
827
                nativeProject.addProjectItemsListener(projectListener);
828
                for (FileSystem fs : getIncludesFileSystems(nativeProject)) {
829
                    CndFileSystemProvider.addFileSystemProblemListener(this, fs);
830
                }
831
            }
832
        }
833
    }
834
835
    protected final void unregisterProjectListeners() {
831
    protected final void unregisterProjectListeners() {
836
        synchronized (projectListenerLock) {
832
        if (platformProject instanceof NativeProject) {
837
            if (projectListener != null) {
833
            // should be in ProjectImpl, but leaving it here makes diff more clear
838
                if (platformProject instanceof NativeProject) {
834
            CsmEventDispatcher.getInstance().unregisterProject(this);
839
                    NativeProject nativeProject = (NativeProject) platformProject;
835
            NativeProject nativeProject = (NativeProject) platformProject;                
840
                    nativeProject.removeProjectItemsListener(projectListener);
836
            for (FileSystem fs : getIncludesFileSystems(nativeProject)) {
841
                    for (FileSystem fs : getIncludesFileSystems(nativeProject)) {
837
                CndFileSystemProvider.removeFileSystemProblemListener(this, fs);
842
                        CndFileSystemProvider.removeFileSystemProblemListener(this, fs);
843
                    }
844
                }
845
                projectListener = null;
846
            }
838
            }
847
        }
839
        }
848
    }
840
    }
Lines 2465-2492 Link Here
2465
        }
2457
        }
2466
        return removedFromProject;
2458
        return removedFromProject;
2467
    }
2459
    }
2468
    
2460
2469
    public final void onFileObjectExternalCreate(FileObject file) {
2461
    public final void onFileObjectExternalCreate(FileObject file) {
2462
        onFileObjectExternalCreate(Arrays.asList(file));
2463
    }
2464
2465
    public final void onFileObjectExternalCreate(Collection<FileObject> files) {
2470
        try {
2466
        try {
2471
            ParserQueue.instance().onStartAddingProjectFiles(this);
2467
            ParserQueue.instance().onStartAddingProjectFiles(this);
2472
            CndFileUtils.clearFileExistenceCache();
2468
            CndFileUtils.clearFileExistenceCache();
2473
            // #196664 - Code Model ignores the generated files"
2469
            // #196664 - Code Model ignores the generated files"
2474
            // when external file was created and assigned to this project => 
2470
            // when external file was created and assigned to this project => 
2475
            // create csm file for it if possible
2471
            // create csm file for it if possible
2476
            NativeFileItem nativeFileItem = null;
2472
            List<NativeFileItem> nativeFileItems = new ArrayList<>();
2477
            // Try to find native file
2473
            // Try to find native file
2478
            if (getPlatformProject() instanceof NativeProject) {
2474
            if (getPlatformProject() instanceof NativeProject) {
2479
                NativeProject prj = (NativeProject) getPlatformProject();
2475
                NativeProject prj = (NativeProject) getPlatformProject();
2480
                if (prj != null) {
2476
                for (FileObject fo : files) {
2481
                    nativeFileItem = prj.findFileItem(file);
2477
                    if (prj != null) {
2478
                        NativeFileItem item = prj.findFileItem(fo);
2479
                        if (item != null) {
2480
                            nativeFileItems.add(item);
2481
                        }
2482
                    }
2482
                }
2483
                }
2483
            }
2484
            }
2484
            // schedule reparse like added NFI
2485
            // schedule reparse like added NFI
2485
            if (nativeFileItem != null) {
2486
            if (!nativeFileItems.isEmpty()) {
2486
                onFileItemsAdded(Collections.singletonList(nativeFileItem));
2487
                onFileItemsAdded(nativeFileItems);
2487
            }
2488
            }
2488
            // allow to fix broken includes
2489
            // allow to fix broken includes
2489
            DeepReparsingUtils.reparseOnAdded(file, this);
2490
            DeepReparsingUtils.reparseOnAdded(nativeFileItems, this);
2490
        } finally {
2491
        } finally {
2491
            ParserQueue.instance().onEndAddingProjectFiles(this);   
2492
            ParserQueue.instance().onEndAddingProjectFiles(this);   
2492
        }
2493
        }
Lines 3585-3592 Link Here
3585
    private static final class FileContainerLock {}
3586
    private static final class FileContainerLock {}
3586
    private final Object fileContainerLock = new FileContainerLock();
3587
    private final Object fileContainerLock = new FileContainerLock();
3587
    private final Key graphStorageKey;
3588
    private final Key graphStorageKey;
3588
    private volatile NativeProjectListenerImpl projectListener;
3589
    private final Object projectListenerLock = new Object();
3590
    
3589
    
3591
    // test variables.
3590
    // test variables.
3592
    private static final boolean TRACE_PP_STATE_OUT = DebugUtils.getBoolean("cnd.dump.preproc.state", false); // NOI18N
3591
    private static final boolean TRACE_PP_STATE_OUT = DebugUtils.getBoolean("cnd.dump.preproc.state", false); // NOI18N
(-)a/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/platform/CndIndexer.java (-33 / +16 lines)
Lines 66-71 Link Here
66
 * @author Egor Ushakov <gorrus@netbeans.org>
66
 * @author Egor Ushakov <gorrus@netbeans.org>
67
 */
67
 */
68
public class CndIndexer extends CustomIndexer {
68
public class CndIndexer extends CustomIndexer {
69
    
70
    /*package*/ interface Delegate {
71
        void index(FileObject file);
72
        void removed(FileObject root);
73
    }
74
    
75
    private static volatile Delegate delegate;
76
    
77
    /*package*/ static void setDelegate(Delegate d) {
78
        delegate = d;
79
    }
69
80
70
    @Override
81
    @Override
71
    protected void index(Iterable<? extends Indexable> files, Context context) {
82
    protected void index(Iterable<? extends Indexable> files, Context context) {
Lines 79-109 Link Here
79
        FileObject root = context.getRoot();
90
        FileObject root = context.getRoot();
80
        for (Indexable idx : files) {
91
        for (Indexable idx : files) {
81
            final FileObject fo = root.getFileObject(idx.getRelativePath());
92
            final FileObject fo = root.getFileObject(idx.getRelativePath());
82
            final ModelImpl model = ModelSupport.instance().getModel();
93
            if (delegate != null) {
83
            model.enqueueModelTask(new Runnable() {
94
                delegate.index(fo);
84
                @Override
95
            }
85
                public void run() {
86
                    CsmFile[] files = model.findFiles(FSPath.toFSPath(fo), false, false);
87
                    Set<ProjectBase> handledProjects = new HashSet<>();
88
                    for (int i = 0; i < files.length; ++i) {
89
                        FileImpl file = (FileImpl) files[i];
90
                        ProjectBase project = file.getProjectImpl(true);
91
                        if (project != null) {
92
                            handledProjects.add(project);
93
                            project.onFileImplExternalChange(file);
94
                        }
95
                    }
96
                    Collection<CsmProject> ownerCsmProjects = CsmUtilities.getOwnerCsmProjects(fo);
97
                    for (CsmProject prj : ownerCsmProjects) {
98
                        if (prj instanceof ProjectBase) {
99
                            ProjectBase project = (ProjectBase) prj;
100
                            if (!handledProjects.contains(project)) {
101
                                project.onFileObjectExternalCreate(fo);
102
                            }
103
                        }
104
                    }
105
                }
106
            }, "External File Updater"); // NOI18N
107
        }
96
        }
108
    }
97
    }
109
98
Lines 133-146 Link Here
133
                return;
122
                return;
134
            }
123
            }
135
            FileObject root = context.getRoot();
124
            FileObject root = context.getRoot();
136
            Collection<CsmProject> projects = CsmUtilities.getOwnerCsmProjects(root);
125
            if (delegate != null) {
137
            for (final CsmProject csmProject : projects) {
126
                delegate.removed(root);
138
                ModelSupport.instance().getModel().enqueueModelTask(new Runnable() {
139
                    @Override
140
                    public void run() {
141
                        ((ProjectBase) csmProject).checkForRemoved();
142
                    }
143
                }, "External File Updater"); // NOI18N
144
            }
127
            }
145
        }
128
        }
146
129
(-)6af4fdb2bcd9 (+173 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2014 Sun Microsystems, Inc.
41
 */
42
43
package org.netbeans.modules.cnd.modelimpl.platform;
44
45
import java.util.logging.Logger;
46
import org.netbeans.modules.cnd.api.project.NativeFileItem;
47
import org.netbeans.modules.cnd.api.project.NativeProject;
48
import org.netbeans.modules.cnd.modelimpl.debug.TraceFlags;
49
import org.openide.filesystems.FileObject;
50
51
/**
52
 * Combines file events (as in FileChangeListener)
53
 * and native project item events (as in NativeProjectListener)
54
 * @author Vladimir Kvashin
55
 */
56
/*package*/ class CsmEvent {
57
58
    public static final Logger LOG = Logger.getLogger("CsmEvent"); // NOI18N
59
60
    public enum Kind {
61
62
        FILE_DELETED(FileObject.class),
63
        FILE_CREATED(FileObject.class),
64
        FILE_RENAMED_CREATED(FileObject.class),
65
        FILE_RENAMED_DELETED(FileObject.class),
66
        FOLDER_CREATED(FileObject.class),
67
        FILE_CHANGED(FileObject.class),
68
        FILE_ATTRIBUTE_CHANGED(FileObject.class),
69
        ITEM_ADDED(NativeFileItem.class),
70
        ITEM_REMOVED(NativeFileItem.class),
71
        ITEM_PROPERTY_CHANGED(NativeFileItem.class),
72
        ITEMS_ALL_PROPERTY_CHANGED(null),
73
        ITEM_RENAMED_DELETED(NativeFileItem.class),
74
        ITEM_RENAMED_CREATED(NativeFileItem.class),
75
        PROJECT_DELETED(NativeProject.class),
76
        FILES_IN_SOURCE_ROOT_DELETED(FileObject.class),
77
        FILE_INDEXED(FileObject.class),
78
        NULL(null);
79
80
        private final Class cls;
81
82
        private Kind(Class cls) {
83
            this.cls = cls;
84
        }
85
    }
86
87
    private final Kind kind;
88
    private final Object object;
89
    private final String oldPath;
90
91
    /*package*/ static CsmEvent create(Kind kind, CsmEvent event) {
92
        return new CsmEvent(kind, event.object, event.oldPath);
93
    }
94
95
    /*package*/ static CsmEvent createItemEvent(Kind kind, NativeFileItem item) {
96
        return new CsmEvent(kind, item, null);
97
    }
98
99
    /*package*/ static CsmEvent createItemEvent(Kind kind, NativeFileItem item, String oldPath) {
100
        return new CsmEvent(kind, item, oldPath);
101
    }
102
103
    /*package*/ static CsmEvent createFileEvent(Kind kind, FileObject fileObject) {
104
        return new CsmEvent(kind, fileObject, null);
105
    }
106
107
    /*package*/ static CsmEvent createFileEvent(Kind kind, FileObject fileObject, String oldNameExt) {
108
        return new CsmEvent(kind, fileObject, oldNameExt);
109
    }
110
111
    /*package*/ static CsmEvent createEmptyEvent(Kind kind) {
112
        return new CsmEvent(kind, null, null);
113
    }
114
115
    /*package*/ static CsmEvent createProjectEvent(Kind kind, NativeProject project) {
116
        return new CsmEvent(kind, project, null);
117
    }
118
119
    private CsmEvent(Kind kind, Object object, String oldPath) {
120
        assert (object == null) ? kind.cls == null : kind.cls.isAssignableFrom(object.getClass());
121
        this.kind = kind;
122
        this.object = object;
123
        this.oldPath = oldPath;
124
    }
125
126
    public Kind getKind() {
127
        return kind;
128
    }
129
130
    public String getPath() {
131
        if (object instanceof FileObject) {
132
            return ((FileObject) object).getPath();
133
        } else if (object instanceof NativeFileItem) {
134
            return ((NativeFileItem) object).getAbsolutePath();
135
        } else {
136
            return null;
137
        }
138
    }
139
140
    public String getOldPath() {
141
        return oldPath;
142
    }
143
144
    public FileObject getFileObject() {
145
        return get(FileObject.class);
146
    }
147
    
148
    public NativeFileItem getNativeFileItem() {
149
        return get(NativeFileItem.class);
150
    }
151
    
152
    public NativeProject getNativeProject() {
153
        return get(NativeProject.class);
154
    }
155
    
156
    private <T> T get(Class<T> cls) {
157
        if (object != null && cls.isAssignableFrom(object.getClass())) {
158
            return (T) object;
159
        }
160
        return null;
161
    }
162
163
    @Override
164
    public String toString() {
165
        return getClass().getSimpleName() + ' ' + kind + ' ' + object + ' ' + oldPath;
166
    }
167
168
    public static void trace(String format, Object... args) {
169
        if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
170
            System.out.printf("CsmEvent: %s\n", String.format(format, args));
171
        }
172
    }
173
}
(-)6af4fdb2bcd9 (+523 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2014 Sun Microsystems, Inc.
41
 */
42
43
package org.netbeans.modules.cnd.modelimpl.platform;
44
45
import java.util.Collection;
46
import java.util.HashMap;
47
import java.util.HashSet;
48
import java.util.LinkedList;
49
import java.util.List;
50
import java.util.Set;
51
import java.util.logging.Level;
52
import org.netbeans.modules.cnd.api.model.CsmFile;
53
import org.netbeans.modules.cnd.api.model.CsmProject;
54
import org.netbeans.modules.cnd.api.project.NativeFileItem;
55
import org.netbeans.modules.cnd.api.project.NativeProject;
56
import org.netbeans.modules.cnd.api.project.NativeProjectItemsListener;
57
import org.netbeans.modules.cnd.debug.CndTraceFlags;
58
import org.netbeans.modules.cnd.modelimpl.csm.core.FileImpl;
59
import org.netbeans.modules.cnd.modelimpl.csm.core.ModelImpl;
60
import org.netbeans.modules.cnd.modelimpl.csm.core.ProjectBase;
61
import org.netbeans.modules.cnd.modelimpl.debug.TraceFlags;
62
import org.netbeans.modules.cnd.modelutil.CsmUtilities;
63
import org.netbeans.modules.cnd.spi.utils.CndFileSystemProvider;
64
import org.netbeans.modules.cnd.utils.CndPathUtilities;
65
import org.netbeans.modules.cnd.utils.CndUtils;
66
import org.netbeans.modules.cnd.utils.FSPath;
67
import org.netbeans.modules.cnd.utils.MIMENames;
68
import org.netbeans.modules.dlight.libs.common.InvalidFileObjectSupport;
69
import org.openide.filesystems.FileAttributeEvent;
70
import org.openide.filesystems.FileChangeListener;
71
import org.openide.filesystems.FileEvent;
72
import org.openide.filesystems.FileObject;
73
import org.openide.filesystems.FileRenameEvent;
74
import org.openide.filesystems.FileUtil;
75
import org.openide.util.RequestProcessor;
76
77
/**
78
 * File events come from
79
 *  1) FileChangeListener 
80
 *  2) NativeProjectItemsListener 
81
 *  3) CndIndexer
82
 * 
83
 * @author Vladimir Kvashin
84
 */
85
public final class CsmEventDispatcher {
86
    
87
    // static (singleton) members
88
    
89
    private static final CsmEventDispatcher instance = new CsmEventDispatcher();
90
91
    public static CsmEventDispatcher getInstance() {
92
        return instance;
93
    }
94
    
95
    // instance members
96
    
97
    private final FileListener fileListener;
98
    private final ItemListener itemListener;
99
    private final CndIndexer.Delegate indexListener;
100
101
    private final Object listenersLock = new Object();
102
    private final HashMap<NativeProject, CsmEventListener> listeners = new HashMap<>();
103
104
    private final RequestProcessor RP = new RequestProcessor(getClass().getSimpleName(), 1);
105
    private final RequestProcessor.Task task = RP.create(new Worker());
106
107
    private final Object eventsLock = new Object();
108
    private LinkedList<CsmEvent> eventsQueue = new LinkedList<>();
109
110
    private CsmEventDispatcher() {
111
        itemListener = new ItemListener();
112
        fileListener = new FileListener();
113
        indexListener = new IndexListener();
114
    }
115
116
    /*package*/ void startup() {
117
        if (CndTraceFlags.USE_INDEXING_API) {
118
            CndIndexer.setDelegate(indexListener);
119
        } else {
120
            CndFileSystemProvider.addFileChangeListener(fileListener);
121
        }        
122
    }
123
124
    /*package*/ void shutdown() {
125
        if (CndTraceFlags.USE_INDEXING_API) {
126
            CndFileSystemProvider.removeFileChangeListener(fileListener);
127
        } else {
128
            CndIndexer.setDelegate(null);
129
        }
130
        // todo: clean up events ,etc
131
    }
132
133
    // shouldn't it be ProjectImpl ?
134
    public void registerProject(ProjectBase project) {        
135
        Object pp = project.getPlatformProject();
136
        if (pp instanceof NativeProject) {
137
            NativeProject nativeProject = (NativeProject) pp;
138
            synchronized (listenersLock) {
139
                CndUtils.assertNull(listeners.get(nativeProject), "Listener already exist for " + nativeProject); //NOI18N
140
                CsmEventListener listener = new CsmEventListener(project);
141
                listeners.put(nativeProject, listener);                
142
                nativeProject.addProjectItemsListener(itemListener);
143
            }
144
        } else {
145
            // I wouldn't say its totally incorrect, just not we expect => something goes wrong => warn
146
            CndUtils.assertTrue(false, "platform ptoject should be NativeProject, but is " + pp + " for " + project); //NOI18N
147
        }
148
    }
149
    
150
    // shouldn't it be ProjectImpl ?
151
    public void unregisterProject(ProjectBase project) {
152
        Object pp = project.getPlatformProject();
153
        if (pp instanceof NativeProject) {
154
            NativeProject nativeProject = (NativeProject) pp;
155
            synchronized (listenersLock) {
156
                nativeProject.removeProjectItemsListener(itemListener);
157
                listeners.remove(nativeProject);
158
            }
159
        } else {
160
            // I wouldn't say its totally incorrect, just not we expect => something goes wrong => warn
161
            CndUtils.assertTrue(false, "platform ptoject should be NativeProject, but is " + pp + " for " + project); //NOI18N
162
        }
163
    }
164
    
165
    public void enableListening(ProjectBase project, boolean enable) {
166
        Object pp = project.getPlatformProject();
167
        if (pp instanceof NativeProject) {
168
            synchronized (listenersLock) {
169
                CsmEventListener listener = listeners.get((NativeProject) pp);
170
                if (listener != null) {
171
                    listener.enableListening(enable);
172
                }
173
            }
174
        }
175
    }
176
177
    private void registerEvent(CsmEvent.Kind kind, FileObject fileObject) {
178
        synchronized (eventsLock) {
179
            eventsQueue.addLast(CsmEvent.createFileEvent(kind, fileObject));
180
        }
181
        task.schedule(0);
182
    }
183
    
184
    private void registerEvents(CsmEvent... events) {
185
        synchronized (eventsLock) {
186
            for (CsmEvent e : events) {
187
                eventsQueue.addLast(e);
188
            }            
189
        }
190
        task.schedule(0);
191
    }
192
193
    private void registerEvents(CsmEvent.Kind kind, List<NativeFileItem> items) {
194
        synchronized (eventsLock) {
195
            for (NativeFileItem item : items) {
196
                eventsQueue.addLast(CsmEvent.createItemEvent(kind, item));
197
            }            
198
        }
199
        task.schedule(0);
200
    }
201
    
202
    private class Worker implements Runnable {
203
        @Override
204
        public void run() {
205
            while (true) {
206
                LinkedList<CsmEvent> curEvents;
207
                synchronized (eventsLock) {
208
                    if (eventsQueue.isEmpty()) {
209
                        return;
210
                    }
211
                    curEvents = eventsQueue;
212
                    eventsQueue = new LinkedList<>();
213
                }
214
                for (CsmEvent event : curEvents) {
215
                    processEvent(event);
216
                }
217
            }            
218
        }        
219
    }
220
221
    private void processEvent(CsmEvent event) {
222
        final ModelImpl model = ModelSupport.instance().getModel();
223
        if (model == null) {
224
            return;
225
        }
226
        CsmEvent.trace("dispatching %s", event);
227
        switch (event.getKind()) {
228
            case ITEM_ADDED:
229
            case ITEM_REMOVED:
230
            case ITEM_PROPERTY_CHANGED:
231
            case ITEM_RENAMED_DELETED:
232
            case ITEM_RENAMED_CREATED:
233
            {
234
                NativeFileItem item = event.getNativeFileItem();
235
                CndUtils.assertNotNullInConsole(item, "NativeFileItem should not be null: " + event); //NOI18N
236
                dispatch(event, item.getNativeProject());
237
                break;
238
            }
239
            case FILE_DELETED:
240
            case FILE_CREATED:
241
            case FILE_RENAMED_CREATED:
242
            case FILE_RENAMED_DELETED:
243
            case FILE_CHANGED:
244
            case FILE_INDEXED:
245
            {
246
                FileObject fo = event.getFileObject();
247
                CndUtils.assertNotNullInConsole(fo, "FileObject should not be null: " + event); //NOI18N
248
                CsmFile[] files = model.findFiles(FSPath.toFSPath(fo), false, false);
249
                Set<ProjectBase> handledProjects = new HashSet<>();
250
                for (int i = 0; i < files.length; ++i) {
251
                    FileImpl file = (FileImpl) files[i];
252
                    ProjectBase project = file.getProjectImpl(true);
253
                    if (project != null) {
254
                        handledProjects.add(project);
255
                        dispatch(CsmEvent.createFileEvent(CsmEvent.Kind.FILE_CHANGED, fo), project);
256
                    }
257
                }
258
                if (event.getKind() == CsmEvent.Kind.FILE_CREATED || event.getKind() == CsmEvent.Kind.FILE_INDEXED) {
259
                    Collection<CsmProject> ownerCsmProjects = CsmUtilities.getOwnerCsmProjects(fo);
260
                    for (CsmProject prj : ownerCsmProjects) {
261
                        if (prj instanceof ProjectBase) {
262
                            ProjectBase project = (ProjectBase) prj;
263
                            if (!handledProjects.contains(project)) {
264
                                dispatch(event.getKind() == CsmEvent.Kind.FILE_INDEXED
265
                                        ? CsmEvent.createFileEvent(CsmEvent.Kind.FILE_CREATED, fo)
266
                                        : event, project);
267
                            }
268
                        }
269
                    }
270
                }
271
                break;
272
            }
273
            case ITEMS_ALL_PROPERTY_CHANGED:
274
                dispatchAll(event);
275
                break;
276
            case PROJECT_DELETED:
277
            {
278
                NativeProject nativeProject = event.getNativeProject();
279
                CndUtils.assertNotNullInConsole(nativeProject, "NativeProject should not be null: " + event); //NOI18N
280
                dispatch(event, nativeProject);
281
                break;
282
            }
283
            case FILES_IN_SOURCE_ROOT_DELETED:
284
            {
285
                FileObject fo = event.getFileObject();
286
                CndUtils.assertNotNullInConsole(fo, "FileObject should not be null: " + event); //NOI18N
287
                Collection<CsmProject> projects = CsmUtilities.getOwnerCsmProjects(fo);
288
                for (CsmProject project : projects) {
289
                    dispatch(event, project);
290
                }
291
                break;
292
            }
293
            case FOLDER_CREATED:
294
            case FILE_ATTRIBUTE_CHANGED:
295
            case NULL:
296
                // ignore assert?
297
                break;
298
            default:
299
                throw new AssertionError(event.getKind().name());
300
        }
301
302
        //<editor-fold defaultstate="collapsed" desc="Previous Implementation">
303
        /*
304
        NativeFileItem item = event.getNativeFileItem();
305
        if (item != null) {
306
            // this is an item event
307
            dispatch(event, item.getNativeProject());
308
        } else {
309
            // this is a file event
310
            FileObject fo = event.getFileObject();
311
            CndUtils.assertNotNull(fo, "Event does not contain neither FileObject nor NativeFileItem"); //NOI18N
312
313
            if (event.getKind() == CsmEvent.Kind.FILES_IN_SOURCE_ROOT_DELETED) {
314
                Collection<CsmProject> projects = CsmUtilities.getOwnerCsmProjects(fo);
315
                for (CsmProject project : projects) {
316
                    dispatch(event, project);
317
                }
318
            } else {
319
                CsmFile[] files = model.findFiles(FSPath.toFSPath(fo), false, false);
320
                Set<ProjectBase> handledProjects = new HashSet<>();
321
                for (int i = 0; i < files.length; ++i) {
322
                    FileImpl file = (FileImpl) files[i];
323
                    ProjectBase project = file.getProjectImpl(true);
324
                    if (project != null) {
325
                        handledProjects.add(project);
326
                        dispatch(event, project);
327
                    }
328
                }
329
                if (event.getKind() == CsmEvent.Kind.FILE_CREATED || event.getKind() == CsmEvent.Kind.FILE_INDEXED) {
330
                    Collection<CsmProject> ownerCsmProjects = CsmUtilities.getOwnerCsmProjects(fo);
331
                    for (CsmProject prj : ownerCsmProjects) {
332
                        if (prj instanceof ProjectBase) {
333
                            ProjectBase project = (ProjectBase) prj;
334
                            if (!handledProjects.contains(project)) {
335
                                dispatch(event.getKind() == CsmEvent.Kind.FILE_INDEXED ?
336
                                        CsmEvent.createFileEvent(CsmEvent.Kind.FILE_CREATED, fo) :
337
                                        event, project);
338
                            }
339
                        }
340
                    }
341
                }
342
            }
343
        }
344
        */
345
        //</editor-fold>
346
    }
347
348
    private void dispatchAll(CsmEvent event) {
349
        Collection<CsmEventListener> listenersCopy;
350
        synchronized (listenersLock) {
351
            listenersCopy = listeners.values();
352
        }
353
        for (CsmEventListener l : listenersCopy) {
354
            l.fireEvent(event);
355
        }
356
    }
357
            
358
    private void dispatch(CsmEvent event, CsmProject project) {
359
        CsmEventListener listener = getListener(project);
360
        if (listener != null) {
361
            listener.fireEvent(event);
362
        } else {
363
            CsmEvent.LOG.log(Level.FINEST, "Skipping event {0}", event);
364
        }
365
    }
366
    
367
    private void dispatch(CsmEvent event, NativeProject project) {
368
        CsmEventListener listener = getListener(project);
369
        if (listener != null) {
370
            listener.fireEvent(event);
371
        } else {
372
            CsmEvent.LOG.log(Level.FINEST, "Skipping event {0}", event);
373
        }
374
    }
375
    
376
    private CsmEventListener getListener(CsmProject project) {
377
        Object pp = project.getPlatformProject();
378
        if (pp instanceof NativeProject) {
379
            synchronized (listenersLock) {
380
                return listeners.get((NativeProject) pp);
381
            }
382
        } 
383
        return null;
384
    }
385
386
    private CsmEventListener getListener(NativeProject project) {
387
        if (project != null) {
388
            synchronized (listenersLock) {
389
                return listeners.get(project);
390
            }
391
        }
392
        return null;
393
    }
394
395
    private boolean isCOrCpp(FileObject fo) {
396
        String mime = fo.getMIMEType();
397
        if (mime == null) {
398
            mime = FileUtil.getMIMEType(fo);
399
            if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
400
                CsmEvent.LOG.log(Level.INFO, "External updates: MIME resolved: {0}", mime);
401
            }
402
        }
403
        return MIMENames.isFortranOrHeaderOrCppOrC(mime);
404
    }
405
    
406
    private boolean isCOrCppOrInvalid(FileObject fo) {
407
        return !fo.isValid() || isCOrCpp(fo);
408
    }
409
    
410
    private class ItemListener implements NativeProjectItemsListener {
411
412
        @Override
413
        public void filesAdded(List<NativeFileItem> items) {
414
            registerEvents(CsmEvent.Kind.ITEM_ADDED, items);
415
        }
416
417
        @Override
418
        public void filesRemoved(List<NativeFileItem> items) {
419
            registerEvents(CsmEvent.Kind.ITEM_REMOVED, items);
420
        }
421
422
        @Override
423
        public void filesPropertiesChanged(List<NativeFileItem> items) {
424
            registerEvents(CsmEvent.Kind.ITEM_PROPERTY_CHANGED, items);
425
        }
426
427
        @Override
428
        public void filesPropertiesChanged() {
429
            registerEvents(CsmEvent.createEmptyEvent(CsmEvent.Kind.ITEMS_ALL_PROPERTY_CHANGED));
430
        }
431
432
        @Override
433
        public void fileRenamed(String oldPath, NativeFileItem newFileIetm) {
434
            registerEvents(
435
                    CsmEvent.createItemEvent(CsmEvent.Kind.ITEM_RENAMED_DELETED, newFileIetm, oldPath),
436
                    CsmEvent.createItemEvent(CsmEvent.Kind.ITEM_RENAMED_CREATED, newFileIetm, oldPath));
437
        }
438
439
        @Override
440
        public void projectDeleted(NativeProject nativeProject) {
441
            registerEvents(CsmEvent.createProjectEvent(CsmEvent.Kind.PROJECT_DELETED, nativeProject));
442
        }
443
444
        @Override
445
        public void fileOperationsStarted(NativeProject nativeProject) {
446
            CsmEventListener listener = getListener(nativeProject);
447
            if (listener != null) {
448
                listener.suspend();
449
            }
450
        }
451
452
        @Override
453
        public void fileOperationsFinished(NativeProject nativeProject) {
454
            CsmEventListener listener = getListener(nativeProject);
455
            if (listener != null) {
456
                listener.resume();
457
            }
458
        }        
459
    }
460
    
461
    private class FileListener implements FileChangeListener {
462
463
        @Override
464
        public void fileFolderCreated(FileEvent fe) {
465
            // ignore
466
        }
467
468
        @Override
469
        public void fileDataCreated(FileEvent fe) {
470
            if (isCOrCppOrInvalid(fe.getFile())) {
471
                registerEvent(CsmEvent.Kind.FILE_CREATED, fe.getFile());
472
            }
473
        }
474
475
        @Override
476
        public void fileChanged(FileEvent fe) {
477
            if (isCOrCppOrInvalid(fe.getFile())) {
478
                registerEvent(CsmEvent.Kind.FILE_CHANGED, fe.getFile());
479
            }
480
        }
481
482
        @Override
483
        public void fileDeleted(FileEvent fe) {
484
            if (isCOrCppOrInvalid(fe.getFile())) {
485
                registerEvent(CsmEvent.Kind.FILE_DELETED, fe.getFile());
486
            }
487
        }
488
489
        @Override
490
        public void fileRenamed(FileRenameEvent fe) {
491
            FileObject fo = fe.getFile();
492
            if (isCOrCppOrInvalid(fo)) {
493
                FSPath newPath = FSPath.toFSPath(fo);
494
                String strPrevExt = (fe.getExt() == null || fe.getExt().isEmpty()) ? "" : "." + fe.getExt(); // NOI18N
495
                String strPrevPath = CndPathUtilities.getDirName(newPath.getPath()) + '/' + fe.getName() + strPrevExt; // NOI18N
496
                FSPath prevPath = new FSPath(newPath.getFileSystem(), strPrevPath);        
497
                FileObject removedFO = InvalidFileObjectSupport.getInvalidFileObject(prevPath.getFileSystem(), prevPath.getPath());
498
                registerEvents(
499
                        CsmEvent.createFileEvent(CsmEvent.Kind.FILE_RENAMED_DELETED, removedFO),
500
                        CsmEvent.createFileEvent(CsmEvent.Kind.FILE_RENAMED_CREATED, fo));
501
            }
502
        }
503
504
        @Override
505
        public void fileAttributeChanged(FileAttributeEvent fe) {
506
            // nothing
507
        }        
508
    }
509
    
510
    private class IndexListener implements CndIndexer.Delegate {
511
512
        @Override
513
        public void index(FileObject file) {
514
            registerEvent(CsmEvent.Kind.FILE_INDEXED, file);
515
        }
516
517
        @Override
518
        public void removed(FileObject root) {
519
            registerEvent(CsmEvent.Kind.FILES_IN_SOURCE_ROOT_DELETED, root); 
520
        }
521
    }    
522
}
523
(-)6af4fdb2bcd9 (+673 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2014 Sun Microsystems, Inc.
41
 */
42
43
package org.netbeans.modules.cnd.modelimpl.platform;
44
45
import java.util.ArrayList;
46
import java.util.Collection;
47
import java.util.HashMap;
48
import java.util.Iterator;
49
import java.util.LinkedHashMap;
50
import java.util.List;
51
import java.util.Map;
52
import java.util.logging.Level;
53
import org.netbeans.modules.cnd.api.model.CsmFile;
54
import org.netbeans.modules.cnd.api.project.NativeFileItem;
55
import org.netbeans.modules.cnd.api.project.NativeProject;
56
import org.netbeans.modules.cnd.modelimpl.csm.core.FileImpl;
57
import org.netbeans.modules.cnd.modelimpl.csm.core.ProjectBase;
58
import org.netbeans.modules.cnd.modelimpl.debug.TraceFlags;
59
import org.netbeans.modules.cnd.modelimpl.repository.RepositoryUtils;
60
import org.netbeans.modules.cnd.utils.CndUtils;
61
import org.openide.filesystems.FileObject;
62
import org.openide.filesystems.FileStateInvalidException;
63
import org.openide.util.Exceptions;
64
import org.openide.util.RequestProcessor;
65
66
/**
67
 * @author Vladimir Voskresensky
68
 * @author Vladimir Kvashin
69
 */
70
/*package*/ final class CsmEventListener {
71
72
    private final ProjectBase project;
73
    private final NativeProject nativeProject;
74
    private volatile boolean enabledEventsHandling = true;
75
76
    //private static final RequestProcessor RP = new RequestProcessor(CsmEventListener.class.getSimpleName());
77
    private final RequestProcessor.Task task;
78
    private final Object eventsLock = new Object();
79
    private int suspendCount = 0;
80
81
    private HashMap<String, CsmEvent> events = new LinkedHashMap<>();
82
83
    private static final CsmEvent NULL = CsmEvent.createEmptyEvent(CsmEvent.Kind.NULL);
84
85
    public CsmEventListener(ProjectBase project) {
86
        assert project.getPlatformProject() instanceof NativeProject;
87
        this.project = project;
88
        this.nativeProject = (NativeProject) project.getPlatformProject();
89
        this.task = ModelSupport.instance().getModel().createModelTask(new Worker(), getClass().getSimpleName());
90
    }
91
92
    public ProjectBase getProject() {
93
        return project;
94
    }
95
96
    public NativeProject getNativeProject() {
97
        return nativeProject;
98
    }
99
    
100
    public void enableListening(boolean enable) {
101
        if (TraceFlags.TIMING) {
102
            CsmEvent.LOG.log(Level.INFO, "\n%{0} ProjectListeners {1}...", new Object[] {enable ? "enable" : "disable",
103
                    nativeProject.getProjectDisplayName()});
104
        }
105
        enabledEventsHandling = enable;
106
    }
107
108
    void fireEvent(CsmEvent event) {
109
        switch (event.getKind()) {
110
            case FILE_INDEXED:
111
            case FOLDER_CREATED:
112
            case FILE_ATTRIBUTE_CHANGED:
113
            case NULL:
114
                return;
115
        }
116
        CsmEvent.trace("%s dispatched to %s", event, project);
117
        checkEvent(event);
118
        String path = getPath(event);
119
        synchronized (eventsLock) {
120
            CsmEvent prev = events.get(path);
121
            events.put(path, convert(prev, event));
122
        }
123
        task.schedule(0); // fe.runWhenDeliveryOver(taskScheduler); ???
124
    }
125
126
    String getPath(CsmEvent event) {
127
        FileObject fo = event.getFileObject();
128
        if (fo != null) {
129
            return fo.getPath();
130
        }
131
        NativeFileItem item = event.getNativeFileItem();
132
        if (item != null) {
133
            return item.getAbsolutePath();
134
        }
135
        NativeProject np = event.getNativeProject();
136
        if (np != null) {
137
            return np.getProjectRoot();
138
        }
139
        return "/"; //NOI18N
140
    }
141
142
    void checkEvent(CsmEvent event) {
143
        FileObject fo = event.getFileObject();
144
        if (fo != null) {
145
            try {
146
                assert fo.getFileSystem().equals(nativeProject.getFileSystem());
147
            } catch (FileStateInvalidException ex) {
148
                Exceptions.printStackTrace(ex);
149
            }
150
        }
151
        NativeProject np = event.getNativeProject();
152
        if (np == null) {
153
            NativeFileItem item = event.getNativeFileItem();
154
            if (item != null) {
155
                np = item.getNativeProject();
156
            }
157
        }
158
        if (np != null) {
159
            assert np.equals(nativeProject);
160
        }
161
    }
162
163
    void resume() {
164
        boolean schedule;
165
        synchronized (eventsLock) {
166
            CndUtils.assertTrue(suspendCount > 0, "resume without suspend " + suspendCount);
167
            suspendCount--;
168
            if (suspendCount < 0) {
169
                suspendCount = 0;
170
            }
171
            schedule = (suspendCount == 0);
172
        }
173
        if (schedule) {
174
            task.schedule(0);
175
        }
176
    }
177
178
    void suspend() {
179
        synchronized (eventsLock) {
180
            CndUtils.assertTrue(suspendCount >= 0, "suspend with " + suspendCount);
181
            suspendCount++;
182
        }
183
    }
184
185
    /*package*/void flush() {
186
        task.schedule(0);
187
        task.waitFinished();
188
    }
189
190
    //<editor-fold defaultstate="collapsed" desc="old impl">
191
    /***
192
   private void processEvents(Collection<CsmEvent> events) {
193
        if (!enabledEventsHandling) {
194
            CsmEvent.trace("events processing disabled, skipping %d events", events.size());
195
            return;
196
        }
197
        CsmEvent.trace("processing %d events", events.size());
198
        boolean checkForRemoved = false;
199
        for (CsmEvent event : events) {
200
            CsmEvent.trace("processing %s", event);
201
            switch (event.getKind()) {
202
                case FILE_DELETED:
203
                case ITEM_REMOVED:
204
                case FILE_RENAMED_DELETED:
205
                case ITEM_RENAMED_DELETED:
206
                    checkForRemoved = true;
207
                    break;
208
                case FILE_CREATED:
209
                case FILE_RENAMED_CREATED:
210
                    project.onFileObjectExternalCreate(event.getFileObject());
211
                    break;
212
                case ITEM_ADDED:
213
                    project.onFileItemsAdded(Arrays.asList(event.getNativeFileItem()));
214
                    break;
215
                case FOLDER_CREATED:
216
                    // nothing
217
                    break;
218
                case FILE_CHANGED:
219
                    project.findFile(event.getPath(), false, false);
220
                    break;
221
                case FILE_ATTRIBUTE_CHANGED:
222
                    // nothing
223
                    break;
224
                case ITEM_PROPERTY_CHANGED:
225
                    project.onFileItemsPropertyChanged(Arrays.asList(event.getNativeFileItem()), false);
226
                    break;
227
                case ITEMS_ALL_PROPERTY_CHANGED:
228
                    List<NativeFileItem> items = new ArrayList<>();
229
                    for (NativeFileItem item : nativeProject.getAllFiles()) {
230
                        if (!item.isExcluded()) {
231
                            switch (item.getLanguage()) {
232
                                case C:
233
                                case CPP:
234
                                case FORTRAN:
235
                                    items.add(item);
236
                                    break;
237
                                default:
238
                                    break;
239
                            }
240
                        }
241
                        project.onFileItemsPropertyChanged(items, true);
242
                    }
243
                    break;
244
                case ITEM_RENAMED_CREATED:
245
                    project.onFileItemRenamed(event.getOldPath(), event.getNativeFileItem());
246
                    break;
247
                case PROJECT_DELETED:
248
                    RepositoryUtils.onProjectDeleted(nativeProject);
249
                    break;
250
                case FILES_IN_SOURCE_ROOT_DELETED:
251
                    checkForRemoved = true;
252
                    break;
253
                case FILE_INDEXED:
254
                    CndUtils.assertTrue(false, "FILE_INDEXED event should never reach end listener"); //NOI18N
255
                    break;
256
                case NULL:
257
                    // nothing
258
                    break;
259
                default:
260
                    throw new AssertionError(event.getKind().name());
261
            }
262
            if (checkForRemoved) {
263
                project.checkForRemoved();
264
            }
265
        }
266
    }
267
     */
268
    //</editor-fold>
269
270
    private void processEvents(Collection<CsmEvent> events) {
271
        if (!enabledEventsHandling) {
272
            CsmEvent.trace("events processing disabled, skipping %d events", events.size());
273
            return;
274
        }
275
        CsmEvent.trace("processing %d events", events.size());
276
277
        boolean projectDeleted = false;
278
        boolean checkForRemoved = false;
279
        boolean projectRemoved = false;
280
        boolean allPropertiesChanged = false;
281
        List<FileObject> createdFiles = new ArrayList<>();
282
        List<NativeFileItem> addedItems = new ArrayList<>();
283
        List<NativeFileItem> changedItemProps = new ArrayList<>();
284
        List<String> changedFiles = new ArrayList<>();
285
        List<CsmEvent> renamedItems = new ArrayList<>();
286
287
        for (CsmEvent event : events) {
288
            CsmEvent.trace("processing %s", event);
289
            switch (event.getKind()) {
290
                case FILE_DELETED:
291
                case ITEM_REMOVED:
292
                case FILE_RENAMED_DELETED:
293
                case ITEM_RENAMED_DELETED:
294
                    checkForRemoved = true;
295
                    break;
296
                case FILE_CREATED:
297
                case FILE_RENAMED_CREATED:
298
                    createdFiles.add(event.getFileObject());
299
                    break;
300
                case ITEM_ADDED:
301
                    addedItems.add(event.getNativeFileItem());
302
                    break;
303
                case FOLDER_CREATED:
304
                    // nothing
305
                    break;
306
                case FILE_CHANGED:
307
                    changedFiles.add(event.getPath());
308
                    break;
309
                case FILE_ATTRIBUTE_CHANGED:
310
                    // nothing
311
                    break;
312
                case ITEM_PROPERTY_CHANGED:
313
                    changedItemProps.add(event.getNativeFileItem());
314
                    break;
315
                case ITEMS_ALL_PROPERTY_CHANGED:
316
                    allPropertiesChanged = true;
317
                    break;
318
                case ITEM_RENAMED_CREATED:
319
                    renamedItems.add(event);
320
                    break;
321
                case PROJECT_DELETED:
322
                    projectDeleted = true;
323
                    break;
324
                case FILES_IN_SOURCE_ROOT_DELETED:
325
                    checkForRemoved = true;
326
                    break;
327
                case FILE_INDEXED:
328
                    CndUtils.assertTrue(false, "FILE_INDEXED event should never reach end listener"); //NOI18N
329
                    break;
330
                case NULL:
331
                    // nothing
332
                    break;
333
                default:
334
                    throw new AssertionError(event.getKind().name());
335
            }
336
337
            if (projectDeleted) {
338
                RepositoryUtils.onProjectDeleted(nativeProject);
339
                return;
340
            }
341
342
            if (!renamedItems.isEmpty()) {
343
                for (CsmEvent csmEvent : renamedItems) {
344
                    project.onFileItemRenamed(event.getOldPath(), event.getNativeFileItem());
345
                }
346
            }
347
348
            if (allPropertiesChanged) {
349
                List<NativeFileItem> items = new ArrayList<>();
350
                for (NativeFileItem item : nativeProject.getAllFiles()) {
351
                    if (!item.isExcluded()) {
352
                        switch (item.getLanguage()) {
353
                            case C:
354
                            case CPP:
355
                            case FORTRAN:
356
                                items.add(item);
357
                                break;
358
                            default:
359
                                break;
360
                        }
361
                    }
362
                    project.onFileItemsPropertyChanged(items, true);
363
                }
364
                changedItemProps.clear();
365
            }
366
367
            if(!changedFiles.isEmpty()) {
368
                for (String path : changedFiles) {
369
                    CsmFile csmFile = project.findFile(path, false, false);
370
                    if (csmFile != null) {
371
                        project.onFileImplExternalChange((FileImpl) csmFile);
372
                    }
373
                }
374
            }
375
            if (!changedItemProps.isEmpty()) {
376
                project.onFileItemsPropertyChanged(changedItemProps, false);
377
            }
378
            if (!createdFiles.isEmpty()) {
379
                project.onFileObjectExternalCreate(createdFiles);
380
            }
381
            if (!addedItems.isEmpty()) {
382
                project.onFileItemsAdded(addedItems);
383
            }
384
            if (checkForRemoved) {
385
                project.checkForRemoved();
386
            }
387
        }
388
    }
389
390
// the table below is incomplete: to me, it's easier to just fill the switch/case and add some comments there
391
// but I left it just in case I decide to fill it later :)
392
/*-------------------------------------------------------------------------------------------------------------------------------------------
393
                                     (prevKind)
394
(curKind) | F/DEL  | F/CR    | F/REN_CR | F/REN_DL |   F/CH   | I/ADD  | I/RM   | I/PROP | I/ALPROP | I/REN_CR | I/REN_DL | P/DEL  | F/RT_DEL |
395
----------------------------------------------------------------------------------------------------------------------------------------------
396
F/DEL     | F/DEL  | null    | null     | assert   | F/DEL    | null   | F/DEL  | F/DEL  | assert   | null     | assert   | P/DEL  | assert   |
397
I/RM      | I/RM   | null    | null     | assert   | I/RM     | null   | I/RM   | I/RM   | assert   | null     | assert   | P/DEL  | assert   |
398
F/RT_DEL  | assert | assert  | assert   | assert   | assert   | assert | assert | assert | assert   | assert   | assert   | P/DEL  | F/RT_DEL |
399
F/CR      | F/CH   | F/CR    | assert   | F/CH     | F/CH     | I/ADD  | ?      | ?      | assert   |          |          | P/DEL  |          |
400
I/ADD     | I/ADD  | I/ADD?  | I/ADD    | I/ADD    | I/ADD?   | I/ADD  | F/CH   |        | assert   |          |          | P/DEL  | assert   |
401
F/REN_CR  | F/CH   | assert  | assert   | F/CH     | assert   |        |        |        | assert   |          |          | P/DEL  |          |
402
I/REN_CR  |        |         |          |          |          |        |        |        | assert   |          |          | P/DEL  |          |
403
F/REN_DL  | assert | null (?)| null (?) | assert   | F/REN_DL |        |        |        | assert   |          |          | P/DEL  |          |
404
I/REN_DL  |        |         |          |          |          |        |        |        | assert   |          |          | P/DEL  |          |
405
F/CH      | assert | F/CR    | F/REN_CR | assert   | F/CH     |        |        |        | assert   |          |          | P/DEL  |          |
406
I/PROP    | null   | F/CR    | null     | assert   | I/PROP   | I/ADD  | I/RM   | I/PROP | assert   | I/REN_CR | assert   | P/DEL  | assert   |
407
I/ALPROP  | assert | assert  | assert   | assert   | assert   | assert | assert | assert | assert   | assert   | assert   | P/DEL  |          |
408
P/DEL     | P/DEL  | P/DEL   | P/DEL    | P/DEL    | P/DEL    | P/DEL  | P/DEL  | P/DEL  | P/DEL    | P/DEL    | P/DEL    | P/DEL  | P/DEL    |
409
----------------------------------------------------------------------------------------------------------------------------------------------*/
410
411
    private static CsmEvent convert(CsmEvent prev, CsmEvent cur) {
412
        if (prev == null || prev.getKind() == CsmEvent.Kind.NULL) {
413
            return cur;
414
        }
415
416
        if (prev.getKind() == CsmEvent.Kind.PROJECT_DELETED) {
417
            return prev;
418
        } else if (cur.getKind() == CsmEvent.Kind.PROJECT_DELETED) {
419
            return cur;
420
        }
421
422
        switch (cur.getKind()) {
423
            case FILE_DELETED: //<editor-fold defaultstate="collapsed" desc="...">
424
                switch (prev.getKind()) {
425
                    case FILE_DELETED:                  return cur;
426
                    case ITEM_REMOVED:                  return cur; // doesn't matter, processing is the same
427
                    case FILE_CREATED:                  return doNull();
428
                    case ITEM_ADDED:                    return doNull();
429
                    case FILE_RENAMED_CREATED:          return doNull();
430
                    case ITEM_RENAMED_CREATED:          return doNull();
431
                    case FILE_RENAMED_DELETED:          return doAssert(prev, cur);
432
                    case ITEM_RENAMED_DELETED:          return doAssert(prev, cur);
433
                    case FILE_CHANGED:                  return cur;
434
                    case ITEM_PROPERTY_CHANGED:         return cur;
435
                    case ITEMS_ALL_PROPERTY_CHANGED:    return doAssert(prev, cur, prev); // does that mean that the project is deleted?
436
                    case FILES_IN_SOURCE_ROOT_DELETED:  return cur; // doesn't matter, processing is thesame
437
                    default:    throw new IllegalArgumentException("unexpected " + prev.getKind()); // NOI18N
438
                }   //</editor-fold>   
439
            case FILE_CREATED://<editor-fold defaultstate="collapsed" desc="...">
440
                switch (prev.getKind()) {
441
                    case FILE_DELETED:                  return doChanged(cur);
442
                    case ITEM_REMOVED:                  return doChanged(cur);
443
                    case FILE_CREATED:                  return prev;
444
                    case ITEM_ADDED:                    return prev; // item events are stronger
445
                    case FILE_RENAMED_CREATED:          return doAssert(prev, cur);
446
                    case ITEM_RENAMED_CREATED:          return prev; // ITEM_RENAMED_CREATED will finally cause checkForRemove and nativeItemAdded
447
                    case FILE_RENAMED_DELETED:          return doChanged(cur);
448
                    case ITEM_RENAMED_DELETED:          return doChanged(cur);
449
                    case FILE_CHANGED:                  return prev;
450
                    case ITEM_PROPERTY_CHANGED:         return prev; // ?
451
                    case ITEMS_ALL_PROPERTY_CHANGED:    return doAssert(prev, cur, prev); // prev event path is a project path!
452
                    case FILES_IN_SOURCE_ROOT_DELETED:  return doAssert(prev, cur); // prev event path is a project path!
453
                    default:    throw new AssertionError(prev.getKind());
454
                }//</editor-fold>
455
            case FILE_RENAMED_CREATED://<editor-fold defaultstate="collapsed" desc="...">
456
                switch (prev.getKind()) {
457
                    case FILE_DELETED:                  return doChanged(cur);
458
                    case ITEM_REMOVED:                  return doChanged(cur);
459
                    case FILE_CREATED:                  return doAssert(prev, cur);
460
                    case ITEM_ADDED:                    return prev;
461
                    case FILE_RENAMED_CREATED:          return doAssert(prev, cur);
462
                    case ITEM_RENAMED_CREATED:          return doAssert(prev, cur);
463
                    case FILE_RENAMED_DELETED:          return doChanged(cur);
464
                    case ITEM_RENAMED_DELETED:          return doChanged(cur);
465
                    case FILE_CHANGED:                  return doAssert(prev, cur);
466
                    case ITEM_PROPERTY_CHANGED:         return cur; //?
467
                    case ITEMS_ALL_PROPERTY_CHANGED:    return doAssert(prev, cur, prev); // prev event path is a project path!
468
                    case FILES_IN_SOURCE_ROOT_DELETED:  return doAssert(prev, cur, prev); // prev event path is a project path!
469
                    default:    throw new AssertionError(prev.getKind());
470
                }//</editor-fold>
471
            case FILE_RENAMED_DELETED://<editor-fold defaultstate="collapsed" desc="...">
472
                switch (prev.getKind()) {
473
                    case FILE_DELETED:                  return doAssert(prev, cur);
474
                    case ITEM_REMOVED:                  return doNullOnRename(prev, cur); //?
475
                    case FILE_CREATED:                  return doNullOnRename(prev, cur);
476
                    case ITEM_ADDED:                    return doNullOnRename(prev, cur);
477
                    case FILE_RENAMED_CREATED:          return doNullOnRename(prev, cur);
478
                    case ITEM_RENAMED_CREATED:          return doNullOnRename(prev, cur);
479
                    case FILE_RENAMED_DELETED:          return doAssert(prev, cur);
480
                    case ITEM_RENAMED_DELETED:          return doAssert(prev, cur);
481
                    case FILE_CHANGED:                  return cur;
482
                    case ITEM_PROPERTY_CHANGED:         return cur;
483
                    case ITEMS_ALL_PROPERTY_CHANGED:    return doAssert(prev, cur, prev); // prev event path is a project path!
484
                    case FILES_IN_SOURCE_ROOT_DELETED:  return doAssert(prev, cur, prev); // prev event path is a project path!
485
                    default:    throw new AssertionError(prev.getKind());
486
                }//</editor-fold>
487
            case FILE_CHANGED://<editor-fold defaultstate="collapsed" desc="...">
488
                switch (prev.getKind()) {
489
                    case FILE_DELETED:                  return doAssert(prev, cur);
490
                    case ITEM_REMOVED:                  return cur;
491
                    case FILE_CREATED:                  return prev;
492
                    case FILE_RENAMED_CREATED:          return prev;
493
                    case FILE_RENAMED_DELETED:          return doAssert(prev, cur);
494
                    case FILE_CHANGED:                  return cur;
495
                    case ITEM_ADDED:                    return cur;
496
                    case ITEM_PROPERTY_CHANGED:         return prev;
497
                    case ITEM_RENAMED_CREATED:          return prev;
498
                    case ITEM_RENAMED_DELETED:          return doAssert(prev, cur);
499
                    case ITEMS_ALL_PROPERTY_CHANGED:    return doAssert(prev, cur, prev); // prev event path is a project path!
500
                    case FILES_IN_SOURCE_ROOT_DELETED:  return doAssert(prev, cur, prev); // prev event path is a project path!
501
                    default:    throw new IllegalArgumentException("unexpected " + prev.getKind()); // NOI18N
502
                }//</editor-fold>
503
            case ITEM_ADDED://<editor-fold defaultstate="collapsed" desc="...">
504
                switch (prev.getKind()) {
505
                    case FILE_DELETED:                  return cur;
506
                    case ITEM_REMOVED:                  return doChanged(CsmEvent.Kind.ITEM_PROPERTY_CHANGED,  cur);
507
                    case FILE_CREATED:                  return cur;
508
                    case ITEM_ADDED:                    return cur;
509
                    case FILE_RENAMED_CREATED:          return cur;
510
                    case ITEM_RENAMED_CREATED:          return cur; //?
511
                    case FILE_RENAMED_DELETED:          return cur; //?
512
                    case ITEM_RENAMED_DELETED:          return cur; //?
513
                    case FILE_CHANGED:                  return cur;
514
                    case ITEM_PROPERTY_CHANGED:         return cur; //?
515
                    case ITEMS_ALL_PROPERTY_CHANGED:    return doAssert(prev, cur, prev); // prev event path is a project path!
516
                    case FILES_IN_SOURCE_ROOT_DELETED:  return doAssert(prev, cur, prev); // prev event path is a project path!
517
                    default:    throw new IllegalArgumentException("unexpected " + prev.getKind()); // NOI18N
518
                }//</editor-fold>
519
            case ITEM_REMOVED://<editor-fold defaultstate="collapsed" desc="...">
520
                switch (prev.getKind()) {
521
                    case FILE_DELETED:                  return cur; // procssing is the same
522
                    case ITEM_REMOVED:                  return cur;
523
                    case FILE_CREATED:                  return cur; //?
524
                    case ITEM_ADDED:                    return doNull();
525
                    case FILE_RENAMED_CREATED:          return doNull();
526
                    case ITEM_RENAMED_CREATED:          return doNull();
527
                    case FILE_RENAMED_DELETED:          return cur; // processing is the same
528
                    case ITEM_RENAMED_DELETED:          return cur; // processing is the same
529
                    case FILE_CHANGED:                  return cur;
530
                    case ITEM_PROPERTY_CHANGED:         return cur; //???
531
                    case ITEMS_ALL_PROPERTY_CHANGED:    return doAssert(prev, cur, prev); // prev event path is a project path!
532
                    case FILES_IN_SOURCE_ROOT_DELETED:  return doAssert(prev, cur, prev); // prev event path is a project path!
533
                    default:    throw new IllegalArgumentException("unexpected " + prev.getKind()); // NOI18N
534
                }//</editor-fold>
535
            case ITEM_PROPERTY_CHANGED://<editor-fold defaultstate="collapsed" desc="...">
536
                switch (prev.getKind()) {
537
                    case FILE_DELETED:                  return doNull();
538
                    case ITEM_REMOVED:                  return doNull();
539
                    case FILE_CREATED:                  return cur;
540
                    case ITEM_ADDED:                    return prev;
541
                    case FILE_RENAMED_CREATED:          return prev;
542
                    case ITEM_RENAMED_CREATED:          return prev;
543
                    case FILE_RENAMED_DELETED:          return doNull();
544
                    case ITEM_RENAMED_DELETED:          return doNull();
545
                    case FILE_CHANGED:                  return cur; // item event is stronger
546
                    case ITEM_PROPERTY_CHANGED:         return cur;
547
                    case ITEMS_ALL_PROPERTY_CHANGED:    return doAssert(prev, cur, prev); // prev event path is a project path!
548
                    case FILES_IN_SOURCE_ROOT_DELETED:  return doAssert(prev, cur, prev); // prev event path is a project path!
549
                    default:    throw new IllegalArgumentException("unexpected " + prev.getKind()); // NOI18N
550
                }//</editor-fold>
551
            case ITEMS_ALL_PROPERTY_CHANGED://<editor-fold defaultstate="collapsed" desc="...">
552
                switch (prev.getKind()) {
553
                    case FILE_DELETED:                  // fallthrough
554
                    case ITEM_REMOVED:                  // fallthrough
555
                    case FILE_CREATED:                  // fallthrough
556
                    case FILE_RENAMED_CREATED:          // fallthrough
557
                    case FILE_RENAMED_DELETED:          // fallthrough
558
                    case FILE_CHANGED:                  // fallthrough
559
                    case ITEM_ADDED:                    // fallthrough
560
                    case ITEM_PROPERTY_CHANGED:         // fallthrough
561
                    case ITEM_RENAMED_CREATED:          // fallthrough
562
                    case ITEM_RENAMED_DELETED:          return doAssert(prev, cur); // cur path is project, prev path is file
563
                    case ITEMS_ALL_PROPERTY_CHANGED:    return cur;
564
                    case FILES_IN_SOURCE_ROOT_DELETED:  return cur; // should we create a synthetic event for this?
565
                    default:    throw new IllegalArgumentException("unexpected " + prev.getKind()); // NOI18N
566
                }//</editor-fold>
567
            case ITEM_RENAMED_DELETED://<editor-fold defaultstate="collapsed" desc="...">
568
                switch (prev.getKind()) {
569
                    case FILE_DELETED:                  return doNull();
570
                    case ITEM_REMOVED:                  return doNull();
571
                    case FILE_CREATED:                  return cur;
572
                    case ITEM_ADDED:                    return doNull();
573
                    case FILE_RENAMED_CREATED:          return doNull();
574
                    case ITEM_RENAMED_CREATED:          return doNull();
575
                    case FILE_RENAMED_DELETED:          return cur;
576
                    case ITEM_RENAMED_DELETED:          return cur;
577
                    case FILE_CHANGED:                  return cur;
578
                    case ITEM_PROPERTY_CHANGED:         return cur; //???
579
                    case ITEMS_ALL_PROPERTY_CHANGED:    return doAssert(prev, cur, prev); // prev event path is a project path!
580
                    case FILES_IN_SOURCE_ROOT_DELETED:  return doAssert(prev, cur, prev); // prev event path is a project path!
581
                    default:    throw new IllegalArgumentException("unexpected " + prev.getKind()); // NOI18N
582
                }//</editor-fold>
583
            case ITEM_RENAMED_CREATED://<editor-fold defaultstate="collapsed" desc="...">
584
                switch (prev.getKind()) {
585
                    case FILE_DELETED:                  return doChanged(cur);
586
                    case ITEM_REMOVED:                  return doChanged(cur);
587
                    case FILE_CREATED:                  return cur;
588
                    case ITEM_ADDED:                    return prev;// or cur... doesn/t really matter
589
                    case FILE_RENAMED_CREATED:          return cur;
590
                    case ITEM_RENAMED_CREATED:          return cur;
591
                    case FILE_RENAMED_DELETED:          return doChanged(cur);
592
                    case ITEM_RENAMED_DELETED:          return doChanged(cur);
593
                    case FILE_CHANGED:                  return cur;
594
                    case ITEM_PROPERTY_CHANGED:         return cur;
595
                    case ITEMS_ALL_PROPERTY_CHANGED:    return doAssert(prev, cur, prev); // prev event path is a project path!
596
                    case FILES_IN_SOURCE_ROOT_DELETED:  return doAssert(prev, cur, prev); // prev event path is a project path!
597
                    default:    throw new IllegalArgumentException("unexpected " + prev.getKind()); // NOI18N
598
                }//</editor-fold>
599
            case FILES_IN_SOURCE_ROOT_DELETED://<editor-fold defaultstate="collapsed" desc="...">
600
                switch (prev.getKind()) {
601
                    case FILE_DELETED:                  // fallthrough
602
                    case ITEM_REMOVED:                  // fallthrough
603
                    case FILE_CREATED:                  // fallthrough
604
                    case ITEM_ADDED:                    // fallthrough
605
                    case FILE_RENAMED_CREATED:          // fallthrough
606
                    case ITEM_RENAMED_CREATED:          // fallthrough
607
                    case FILE_RENAMED_DELETED:          // fallthrough
608
                    case ITEM_RENAMED_DELETED:          // fallthrough
609
                    case FILE_CHANGED:                  // fallthrough
610
                    case ITEM_PROPERTY_CHANGED:         return doAssert(prev, cur); // cur path is project, prev path is item ?!
611
                    case ITEMS_ALL_PROPERTY_CHANGED:    return prev; // ??? should we create a combined event?
612
                    case FILES_IN_SOURCE_ROOT_DELETED:  return cur;
613
                    default:    throw new IllegalArgumentException("unexpected " + prev.getKind()); // NOI18N
614
                }//</editor-fold>
615
            default:    throw new AssertionError(prev.getKind());
616
        }
617
    }
618
619
    private static CsmEvent doAssert(CsmEvent prev, CsmEvent cur) {
620
        return doAssert(prev, cur, cur);
621
    }
622
623
    private static CsmEvent doAssert(CsmEvent prev, CsmEvent cur, CsmEvent correct ){
624
        CndUtils.assertTrueInConsole(false, "invalid states " + prev + " " + cur);
625
        return correct;
626
    }
627
628
    private static CsmEvent doChanged(CsmEvent.Kind kind, CsmEvent cur) {
629
        return CsmEvent.create(kind, cur);
630
    }
631
632
    private static CsmEvent doChanged(CsmEvent cur) {
633
        return CsmEvent.create(CsmEvent.Kind.FILE_CHANGED, cur);
634
    }
635
636
    private static CsmEvent doNull() {
637
        return NULL;
638
    }
639
640
    private static CsmEvent doNullOnRename(CsmEvent prev, CsmEvent cur) {
641
        return NULL;
642
    }
643
644
    private final class Worker implements Runnable {
645
        @Override
646
        public void run() {
647
            HashMap<String, CsmEvent> curEvents;
648
            synchronized (eventsLock) {
649
                if (events.isEmpty()) {
650
                    return;
651
                }
652
                curEvents = events;
653
                if (suspendCount == 0) {
654
                    events = new LinkedHashMap<>();
655
                } else {
656
                    HashMap<String, CsmEvent> suspendedRemoves = new LinkedHashMap<>();
657
                    for (Iterator<Map.Entry<String, CsmEvent>> it = curEvents.entrySet().iterator(); it.hasNext();) {
658
                        Map.Entry<String, CsmEvent> entry = it.next();
659
                        CsmEvent value = entry.getValue();
660
                        // hold on with delete events and delete/create pair from rename event
661
                        if (value.getKind() == CsmEvent.Kind.FILE_DELETED || value.getKind() == CsmEvent.Kind.ITEM_REMOVED) {
662
                            //(value.getKind() == CsmEvent.Kind.FILE_CREATED && value.event instanceof FileRenameEvent)) {
663
                            suspendedRemoves.put(entry.getKey(), value);
664
                            it.remove();
665
                        }
666
                    }
667
                    events = suspendedRemoves;
668
                }
669
            }
670
            processEvents(curEvents.values());
671
        }
672
    }
673
}
(-)a/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/platform/ExternalUpdateListener.java (-255 lines)
Removed Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2012 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.modules.cnd.modelimpl.platform;
43
44
import java.util.Collection;
45
import java.util.HashSet;
46
import java.util.LinkedList;
47
import java.util.Set;
48
import java.util.logging.Level;
49
import java.util.logging.Logger;
50
import org.netbeans.modules.cnd.api.model.CsmFile;
51
import org.netbeans.modules.cnd.api.model.CsmProject;
52
import org.netbeans.modules.cnd.modelimpl.csm.core.FileImpl;
53
import org.netbeans.modules.cnd.modelimpl.csm.core.ModelImpl;
54
import org.netbeans.modules.cnd.modelimpl.csm.core.ProjectBase;
55
import org.netbeans.modules.cnd.modelimpl.debug.TraceFlags;
56
import org.netbeans.modules.cnd.modelutil.CsmUtilities;
57
import org.netbeans.modules.cnd.utils.CndPathUtilities;
58
import org.netbeans.modules.cnd.utils.FSPath;
59
import org.netbeans.modules.cnd.utils.MIMENames;
60
import org.netbeans.modules.dlight.libs.common.InvalidFileObjectSupport;
61
import org.openide.filesystems.FileChangeAdapter;
62
import org.openide.filesystems.FileEvent;
63
import org.openide.filesystems.FileObject;
64
import org.openide.filesystems.FileRenameEvent;
65
import org.openide.filesystems.FileUtil;
66
67
/**
68
 *
69
 * @author Vladimir Voskresensky
70
 */
71
/*package*/final class ExternalUpdateListener extends FileChangeAdapter implements Runnable {
72
    /*package*/static final Logger LOG = Logger.getLogger("ExternalUpdateListener"); // NOI18N
73
    private final ModelSupport modelSupport;
74
    private enum EventKind {
75
        CREATED,
76
        CHANGED,
77
        DELETED
78
    }
79
80
    private static final class Pair {
81
        private final EventKind kind;
82
        private final FileEvent fe;
83
84
        public Pair(EventKind kind, FileEvent fe) {
85
            this.kind = kind;
86
            this.fe = fe;
87
        }
88
89
        @Override
90
        public String toString() {
91
            return "Pair{" + "kind=" + kind + ", fe=" + fe + '}'; // NOI18N
92
        }
93
    }
94
    private volatile LinkedList<Pair> events = new LinkedList<>();
95
    private final Object eventsLock = new Object();
96
    
97
    ExternalUpdateListener(final ModelSupport outer) {
98
        this.modelSupport = outer;
99
    }
100
101
    /** FileChangeListener implementation. Fired when a file is changed. */
102
    @Override
103
    public void fileChanged(FileEvent fe) {
104
        if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
105
            LOG.log(Level.INFO, "External updates: try to register fileChanged {0}", fe);
106
        }
107
        register(fe, EventKind.CHANGED);
108
    }
109
110
    @Override
111
    public void fileDataCreated(FileEvent fe) {
112
        if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
113
            LOG.log(Level.INFO, "External updates: try to register fileDataCreated {0}", fe);
114
        }
115
        register(fe, EventKind.CREATED);
116
    }
117
118
    @Override
119
    public void fileRenamed(FileRenameEvent fe) {
120
        if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
121
            LOG.log(Level.INFO, "External updates: try to register fileRenamed {0}", fe);
122
        }     
123
        final ModelImpl model = modelSupport.theModel;
124
        if (model != null) {
125
            final FileObject fo = fe.getFile();
126
            if (isCOrCpp(fo)) {
127
                FSPath newPath = FSPath.toFSPath(fo);
128
                String strPrevExt = (fe.getExt() == null || fe.getExt().isEmpty()) ? "" : "." + fe.getExt(); // NOI18N
129
                String strPrevPath = CndPathUtilities.getDirName(newPath.getPath()) + '/' + fe.getName() + strPrevExt; // NOI18N
130
                FSPath prevPath = new FSPath(newPath.getFileSystem(), strPrevPath);        
131
                FileObject removedFO = InvalidFileObjectSupport.getInvalidFileObject(prevPath.getFileSystem(), prevPath.getPath());
132
                FileEvent deleteFE = new FileEvent((FileObject) fe.getSource(), removedFO, fe.isExpected(), fe.getTime());
133
                synchronized (eventsLock) {
134
                    if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
135
                        LOG.log(Level.INFO, "External updates: registered fileRenamed {0}", fe);
136
                    }
137
                    events.addLast(new Pair(EventKind.DELETED, deleteFE));
138
                    events.addLast(new Pair(EventKind.CREATED, fe));
139
                }
140
            }
141
        }
142
    }
143
144
    
145
    @Override
146
    public void fileDeleted(FileEvent fe) {
147
        if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
148
            LOG.log(Level.INFO, "External updates: try to register fileDeleted {0}", fe);
149
        }
150
        register(fe, EventKind.DELETED); 
151
    }
152
153
    @Override
154
    public void run() {
155
        if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
156
            LOG.info("External updates: running update task");
157
        }
158
        while (true) {
159
            LinkedList<Pair> curEvents;
160
            synchronized (eventsLock) {
161
                if (events.isEmpty()) {
162
                    if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
163
                        LOG.info("External updates: empty queue");
164
                    }
165
                    return;
166
                }
167
                curEvents = events;
168
                events = new LinkedList<>();
169
            }            
170
            for (Pair pair : curEvents) {
171
                ModelImpl model = modelSupport.theModel;
172
                if (model == null) {
173
                    return;
174
                }
175
                FileObject fo = pair.fe.getFile();
176
                if (fo != null) {
177
                    EventKind curKind = pair.kind;
178
                    if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
179
                        LOG.log(Level.INFO, "External updates: Updating for {0} {1}", new Object[]{curKind, fo});
180
                    }
181
                    CsmFile[] files = model.findFiles(FSPath.toFSPath(fo), false, false);
182
                    Set<ProjectBase> handledProjects = new HashSet<>();
183
                            
184
                    for (int i = 0; i < files.length; ++i) {
185
                        FileImpl file = (FileImpl) files[i];
186
                        ProjectBase project = file.getProjectImpl(true);
187
                        if (project != null) {
188
                            handledProjects.add(project);
189
                            if (curKind == EventKind.DELETED) {
190
                                if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
191
                                    LOG.log(Level.INFO, "External updates: project {0} found for deleted {1}", new Object[]{project, file});
192
                                }
193
                                project.checkForRemoved();
194
                            } else if (curKind == EventKind.CHANGED) {
195
                                if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
196
                                    LOG.log(Level.INFO, "External updates: project {0} found for changed {1}", new Object[]{project, file});
197
                                }
198
                                project.onFileImplExternalChange(file);
199
                            } else {
200
                                if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
201
                                    LOG.log(Level.INFO, "External updates: project {0} found for {1}", new Object[]{project, fo});
202
                                }
203
                                project.onFileObjectExternalCreate(fo);                            
204
                            }
205
                        }
206
                    }                        
207
                    if (curKind == EventKind.CREATED) {
208
                        Collection<CsmProject> ownerCsmProjects = CsmUtilities.getOwnerCsmProjects(fo);
209
                        for (CsmProject prj : ownerCsmProjects) {
210
                            if (prj instanceof ProjectBase) {
211
                                ProjectBase project = (ProjectBase) prj;
212
                                if (!handledProjects.contains(project)) {
213
                                    if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
214
                                        LOG.log(Level.INFO, "External updates: project {0} found for {1}", new Object[]{project, fo});
215
                                    }
216
                                    project.onFileObjectExternalCreate(fo);
217
                                }
218
                            }
219
                        }
220
                        if (TraceFlags.TRACE_EXTERNAL_CHANGES && ownerCsmProjects.isEmpty()) {
221
                            LOG.log(Level.INFO, "External updates: No CsmProject found for {0}", fo);
222
                        }
223
                    }
224
                }
225
            }
226
        }
227
    }
228
229
    private boolean isCOrCpp(FileObject fo) {
230
        String mime = fo.getMIMEType();
231
        if (mime == null) {
232
            mime = FileUtil.getMIMEType(fo);
233
            if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
234
                LOG.log(Level.INFO, "External updates: MIME resolved: {0}", mime);
235
            }
236
        }
237
        return MIMENames.isFortranOrHeaderOrCppOrC(mime);
238
    }
239
240
    private void register(FileEvent fe, EventKind kind) {
241
        final ModelImpl model = modelSupport.theModel;
242
        if (model != null) {
243
            final FileObject fo = fe.getFile();
244
            if (!fo.isValid() || isCOrCpp(fo)) {
245
                synchronized (eventsLock) {
246
                    if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
247
                        LOG.log(Level.INFO, "External updates: registered {0} {1}", new Object[]{kind, fe});
248
                    }                    
249
                    events.addLast(new Pair(kind, fe));
250
                }
251
                model.enqueueModelTask(this, "External File Updater"); // NOI18N
252
            }
253
        }
254
    }
255
}
(-)a/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/platform/ModelSupport.java (-28 / +6 lines)
Lines 76-82 Link Here
76
import org.netbeans.modules.cnd.utils.FSPath;
76
import org.netbeans.modules.cnd.utils.FSPath;
77
import org.netbeans.modules.cnd.utils.MIMENames;
77
import org.netbeans.modules.cnd.utils.MIMENames;
78
import org.netbeans.modules.cnd.utils.NamedRunnable;
78
import org.netbeans.modules.cnd.utils.NamedRunnable;
79
import org.netbeans.modules.cnd.utils.SuspendableFileChangeListener;
80
import org.netbeans.modules.cnd.utils.cache.CndFileUtils;
79
import org.netbeans.modules.cnd.utils.cache.CndFileUtils;
81
import org.netbeans.modules.dlight.libs.common.InvalidFileObjectSupport;
80
import org.netbeans.modules.dlight.libs.common.InvalidFileObjectSupport;
82
import org.openide.cookies.EditorCookie;
81
import org.openide.cookies.EditorCookie;
Lines 102-111 Link Here
102
101
103
    private static final AtomicBoolean hasOpenedProjects = new AtomicBoolean(false);
102
    private static final AtomicBoolean hasOpenedProjects = new AtomicBoolean(false);
104
    private static final ModelSupport instance = new ModelSupport();
103
    private static final ModelSupport instance = new ModelSupport();
105
    /*package*/volatile ModelImpl theModel;
104
    private volatile ModelImpl theModel;
106
    private final Set<Lookup.Provider> openedProjects = new HashSet<>();
105
    private final Set<Lookup.Provider> openedProjects = new HashSet<>();
107
    final ModifiedObjectsChangeListener modifiedListener = TraceFlags.USE_PARSER_API ? null : new ModifiedObjectsChangeListener();
106
    final ModifiedObjectsChangeListener modifiedListener = TraceFlags.USE_PARSER_API ? null : new ModifiedObjectsChangeListener();
108
    private SuspendableFileChangeListener fileChangeListener;
109
    private static final boolean TRACE_STARTUP = Boolean.getBoolean("cnd.modelsupport.startup.trace");// NOI18N
107
    private static final boolean TRACE_STARTUP = Boolean.getBoolean("cnd.modelsupport.startup.trace");// NOI18N
110
    private volatile boolean postponeParse = false;
108
    private volatile boolean postponeParse = false;
111
    private final RequestProcessor.Task openProjectsTask = 
109
    private final RequestProcessor.Task openProjectsTask = 
Lines 135-150 Link Here
135
    public void setModel(ModelImpl model) {
133
    public void setModel(ModelImpl model) {
136
        this.theModel = model;
134
        this.theModel = model;
137
        synchronized (this) {
135
        synchronized (this) {
138
            if (fileChangeListener != null) {
136
            if (model == null) {
139
                CndFileSystemProvider.removeFileChangeListener(fileChangeListener);
137
                CsmEventDispatcher.getInstance().shutdown();
140
                fileChangeListener = null;
138
            } else {
141
            }
139
                CsmEventDispatcher.getInstance().startup();
142
            if (model != null && !CndTraceFlags.USE_INDEXING_API) {
143
                fileChangeListener = new SuspendableFileChangeListener(new ExternalUpdateListener(this));
144
                CndFileSystemProvider.addFileChangeListener(fileChangeListener);
145
            }
140
            }
146
        }
141
        }
147
    }
142
    }
143
148
    /** copy pasted version from CndUtils to prevent load of CndUtils during startup */
144
    /** copy pasted version from CndUtils to prevent load of CndUtils during startup */
149
    private static boolean getBoolean(String name, boolean result) {
145
    private static boolean getBoolean(String name, boolean result) {
150
        String text = System.getProperty(name);
146
        String text = System.getProperty(name);
Lines 731-752 Link Here
731
        }
727
        }
732
        Diagnostic.unindent();
728
        Diagnostic.unindent();
733
    }
729
    }
734
735
    public void suspendDeleteEvents() {
736
        if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
737
            ExternalUpdateListener.LOG.info("External updates: suspendDeleteEvents");
738
        }        
739
        if (fileChangeListener != null) {
740
            fileChangeListener.suspendRemoves();
741
        }
742
    }
743
744
    public void resumeDeleteEvents() {
745
        if (TraceFlags.TRACE_EXTERNAL_CHANGES) {
746
            ExternalUpdateListener.LOG.info("External updates: resumeDeleteEvents");
747
        }
748
        if (fileChangeListener != null) {
749
            fileChangeListener.resumeRemoves();
750
        }
751
    }
752
}
730
}
(-)a/cnd.modelimpl/src/org/netbeans/modules/cnd/modelimpl/trace/TraceModelBase.java (-1 / +1 lines)
Lines 70-76 Link Here
70
        openideLogger.setLevel(Level.SEVERE);
70
        openideLogger.setLevel(Level.SEVERE);
71
        Logger.getLogger("org.openide.filesystems.FileUtil").setLevel(Level.OFF); // NOI18N
71
        Logger.getLogger("org.openide.filesystems.FileUtil").setLevel(Level.OFF); // NOI18N
72
        model = createModel();
72
        model = createModel();
73
        model.startup();
73
        model.startup(); // 2-nd time? it was already called from ModelImpl ctor
74
        if (clearCache) {
74
        if (clearCache) {
75
            RepositoryTestUtils.deleteDefaultCacheLocation();
75
            RepositoryTestUtils.deleteDefaultCacheLocation();
76
        }
76
        }

Return to bug 243650