~ubuntu-branches/ubuntu/trusty/netbeans/trusty

« back to all changes in this revision

Viewing changes to form/src/org/netbeans/modules/form/GuardedBlockHandlerFactoryImpl.java

  • Committer: Bazaar Package Importer
  • Author(s): Marek Slama
  • Date: 2008-01-29 14:11:22 UTC
  • Revision ID: james.westby@ubuntu.com-20080129141122-fnzjbo11ntghxfu7
Tags: upstream-6.0.1
ImportĀ upstreamĀ versionĀ 6.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
3
 *
 
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 
5
 *
 
6
 * The contents of this file are subject to the terms of either the GNU
 
7
 * General Public License Version 2 only ("GPL") or the Common
 
8
 * Development and Distribution License("CDDL") (collectively, the
 
9
 * "License"). You may not use this file except in compliance with the
 
10
 * License. You can obtain a copy of the License at
 
11
 * http://www.netbeans.org/cddl-gplv2.html
 
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 
13
 * specific language governing permissions and limitations under the
 
14
 * License.  When distributing the software, include this License Header
 
15
 * Notice in each file and include the License file at
 
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 
17
 * particular file as subject to the "Classpath" exception as provided
 
18
 * by Sun in the GPL Version 2 section of the License file that
 
19
 * accompanied this code. If applicable, add the following below the
 
20
 * License Header, with the fields enclosed by brackets [] replaced by
 
21
 * your own identifying information:
 
22
 * "Portions Copyrighted [year] [name of copyright owner]"
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * The Original Software is NetBeans. The Initial Developer of the Original
 
27
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
 
28
 * Microsystems, Inc. All Rights Reserved.
 
29
 *
 
30
 * If you wish your version of this file to be governed by only the CDDL
 
31
 * or only the GPL Version 2, indicate your decision by adding
 
32
 * "[Contributor] elects to include this software in this distribution
 
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 
34
 * single choice of license, a recipient has the option to distribute
 
35
 * your version of this file under either the CDDL, the GPL Version 2 or
 
36
 * to extend the choice of license to its licensees as provided above.
 
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 
38
 * Version 2 license, then the option applies only if the new code is
 
39
 * made subject to such option by the copyright holder.
 
40
 */
 
41
 
 
42
package org.netbeans.modules.form;
 
43
 
 
44
import java.util.ArrayList;
 
45
import java.util.Collection;
 
46
import java.util.HashMap;
 
47
import java.util.List;
 
48
import java.util.Map;
 
49
import java.util.Set;
 
50
import java.util.TreeSet;
 
51
import org.netbeans.api.editor.guards.SimpleSection;
 
52
import org.netbeans.api.java.source.ModificationResult;
 
53
import org.netbeans.modules.refactoring.api.AbstractRefactoring;
 
54
import org.netbeans.modules.refactoring.api.Problem;
 
55
import org.netbeans.modules.refactoring.spi.GuardedBlockHandler;
 
56
import org.netbeans.modules.refactoring.spi.GuardedBlockHandlerFactory;
 
57
import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation;
 
58
import org.netbeans.modules.refactoring.spi.Transaction;
 
59
import org.openide.filesystems.FileObject;
 
60
 
 
61
/**
 
62
 * Used by java refactoring to delegate changes in guarded blocks. Registered
 
63
 * in META-INF/services. Creates one GuardedBlockHandlerImpl instance per
 
64
 * refactoring (so it can handle more forms).
 
65
 * 
 
66
 * @author Tomas Pavek
 
67
 */
 
68
public class GuardedBlockHandlerFactoryImpl implements GuardedBlockHandlerFactory {
 
69
    
 
70
    public GuardedBlockHandlerFactoryImpl() {
 
71
    }
 
72
    
 
73
    public GuardedBlockHandler createInstance(AbstractRefactoring refactoring) {
 
74
        RefactoringInfo refInfo = refactoring.getContext().lookup(RefactoringInfo.class);
 
75
        return new GuardedBlockHandlerImpl(refInfo);
 
76
    }
 
77
 
 
78
    // -----
 
79
    
 
80
    private static class GuardedBlockHandlerImpl implements GuardedBlockHandler {
 
81
        private RefactoringInfo refInfo;
 
82
        private Map<FileObject, GuardedBlockUpdate> guardedUpdates;
 
83
 
 
84
        private boolean first = true;
 
85
 
 
86
        public GuardedBlockHandlerImpl(RefactoringInfo refInfo) {
 
87
            this.refInfo = refInfo;
 
88
        }
 
89
 
 
90
        public Problem handleChange(RefactoringElementImplementation proposedChange,
 
91
                                    Collection<RefactoringElementImplementation> replacements,
 
92
                                    Collection<Transaction> transactions) {
 
93
            if (refInfo == null) {
 
94
                return null; // unsupported
 
95
            }
 
96
 
 
97
            FileObject changedFile = proposedChange.getParentFile();
 
98
            FormRefactoringUpdate update = refInfo.getUpdateForFile(changedFile);
 
99
            update.setGaurdedCodeChanging(true);
 
100
 
 
101
            boolean preloadForm = false;
 
102
            boolean canRegenerate = false;
 
103
 
 
104
            if (refInfo.getPrimaryFile().equals(changedFile) && refInfo.isForm()) {
 
105
                // the change started in this form
 
106
                switch (refInfo.getChangeType()) {
 
107
                case VARIABLE_RENAME: // renaming field or local variable of initComponents
 
108
                case CLASS_RENAME: // renaming form class, need to regenarate use of MyForm.this
 
109
                case EVENT_HANDLER_RENAME: // renaming event handler - change the method and calls
 
110
                    preloadForm = true;
 
111
                    canRegenerate = true;
 
112
                    break;
 
113
                case CLASS_MOVE:
 
114
                    // can't preload the form - it must be loaded and
 
115
                    // regenareted *after* moved to the new location
 
116
                    canRegenerate = true;
 
117
                }
 
118
            } else { // change originated in another class
 
119
                if (first) {
 
120
                    // add the preview element for the overall guarded block change
 
121
                    // (for direct form change it was added by our plugin)
 
122
                    replacements.add(update.getPreviewElement());
 
123
                    first = false;
 
124
                }
 
125
                // other changes may render the form unloadable (missing component
 
126
                // classes), will change the .form file directly...
 
127
            }
 
128
 
 
129
            // load the form in advance to be sure it can be loaded
 
130
            if (preloadForm && !update.prepareForm(true)) {
 
131
                return new Problem(true, "Error loading form. Cannot update generated code.");
 
132
            }
 
133
 
 
134
            if (!canRegenerate) { // guarded block gets changed but it is not safe to load the form
 
135
                // remember the change and modify the guarded block directly later
 
136
                ModificationResult.Difference diff = proposedChange.getLookup().lookup(ModificationResult.Difference.class);
 
137
                if (diff != null) {
 
138
                    GuardedBlockUpdate gbUpdate;
 
139
                    if (guardedUpdates == null) {
 
140
                        guardedUpdates = new HashMap<FileObject, GuardedBlockUpdate>();
 
141
                        gbUpdate = null;
 
142
                    } else {
 
143
                        gbUpdate = guardedUpdates.get(changedFile);
 
144
                    }
 
145
                    if (gbUpdate == null) {
 
146
                        gbUpdate = new GuardedBlockUpdate(
 
147
                                update.getFormDataObject().getFormEditorSupport());
 
148
                        guardedUpdates.put(changedFile, gbUpdate);
 
149
                    }
 
150
                    gbUpdate.addChange(diff);
 
151
                    transactions.add(gbUpdate);
 
152
                }
 
153
            }
 
154
 
 
155
            // we must add some transaction or element (even if it can be redundant)
 
156
            // so it looks like we care about this guarded block change...
 
157
            transactions.add(update);
 
158
 
 
159
            return null;
 
160
        }
 
161
    }
 
162
 
 
163
    // -----
 
164
 
 
165
    /**
 
166
     * A transaction for updating guarded blocks directly with changes that came
 
167
     * from java refactoring. I.e. no regenerating by form editor.
 
168
     */
 
169
    private static class GuardedBlockUpdate implements Transaction {
 
170
        private FormEditorSupport formEditorSupport;
 
171
        private List<GuardedBlockInfo> guardedInfos; // there can be multiple guarded blocks affected
 
172
 
 
173
        GuardedBlockUpdate(FormEditorSupport fes) {
 
174
            this.formEditorSupport = fes;
 
175
            guardedInfos = new ArrayList<GuardedBlockInfo>(2);
 
176
            guardedInfos.add(new GuardedBlockInfo(fes.getInitComponentSection()));
 
177
            guardedInfos.add(new GuardedBlockInfo(fes.getVariablesSection()));
 
178
        }
 
179
 
 
180
        void addChange(ModificationResult.Difference diff) {
 
181
            for (GuardedBlockInfo block : guardedInfos) {
 
182
                if (block.containsPosition(diff)) {
 
183
                    block.addChange(diff);
 
184
                    break;
 
185
                }
 
186
            }
 
187
        }
 
188
 
 
189
        public void commit() {
 
190
            for (GuardedBlockInfo block : guardedInfos) {
 
191
                String newText = block.getNewSectionText();
 
192
                if (newText != null) {
 
193
                    formEditorSupport.getGuardedSectionManager()
 
194
                        .findSimpleSection(block.getName())
 
195
                            .setText(newText);
 
196
                }
 
197
            }
 
198
        }
 
199
 
 
200
        public void rollback() {
 
201
            // rollback not needed - should be reverted by java refactoring as a whole file
 
202
/*            for (GuardedBlockInfo block : guardedInfos) {
 
203
                formEditorSupport.getGuardedSectionManager()
 
204
                    .findSimpleSection(block.getName())
 
205
                        .setText(block.originalText);
 
206
            } */
 
207
        }
 
208
    }
 
209
 
 
210
    /**
 
211
     * Collects all changes for one guarded block.
 
212
     */
 
213
    private static class GuardedBlockInfo {
 
214
        private String blockName;
 
215
        private int originalPosition;
 
216
        private String originalText;
 
217
 
 
218
        /**
 
219
         * Represents one change in the guarded block.
 
220
         */
 
221
        private static class ChangeInfo implements Comparable<ChangeInfo> {
 
222
            private int startPos;
 
223
            private int length;
 
224
            private String newText;
 
225
            ChangeInfo(int startPos, int len, String newText) {
 
226
                this.startPos = startPos;
 
227
                this.length = len;
 
228
                this.newText = newText;
 
229
            }
 
230
 
 
231
            public int compareTo(ChangeInfo ch) {
 
232
                return startPos - ch.startPos;
 
233
            }
 
234
        }
 
235
 
 
236
        private Set<ChangeInfo> changes = new TreeSet<ChangeInfo>();
 
237
 
 
238
        GuardedBlockInfo(SimpleSection section) {
 
239
            blockName = section.getName();
 
240
            originalPosition = section.getStartPosition().getOffset();
 
241
            originalText = section.getText();
 
242
        }
 
243
 
 
244
        boolean containsPosition(ModificationResult.Difference diff) {
 
245
            int pos = diff.getStartPosition().getOffset();
 
246
            return pos >= originalPosition && pos < originalPosition + originalText.length();
 
247
        }
 
248
 
 
249
        void addChange(ModificationResult.Difference diff) {
 
250
            changes.add(new ChangeInfo(
 
251
                    diff.getStartPosition().getOffset() - originalPosition,
 
252
                    diff.getOldText() != null ? diff.getOldText().length() : 0,
 
253
                    diff.getNewText()));
 
254
        }
 
255
 
 
256
        String getName() {
 
257
            return blockName;
 
258
        }
 
259
 
 
260
        String getNewSectionText() {
 
261
            if (changes.size() > 0) {
 
262
                StringBuilder buf = new StringBuilder();
 
263
                int lastOrigPos = 0;
 
264
                for (ChangeInfo change : changes) {
 
265
                    buf.append(originalText.substring(lastOrigPos, change.startPos));
 
266
                    buf.append(change.newText);
 
267
                    lastOrigPos = change.startPos + change.length;
 
268
                }
 
269
                buf.append(originalText.substring(lastOrigPos));
 
270
                return buf.toString();
 
271
            } else {
 
272
                return null;
 
273
            }
 
274
        }
 
275
    }
 
276
 
 
277
}