001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.refactoring.spi;
043:
044: import java.io.IOException;
045: import java.util.*;
046: import javax.swing.text.Position;
047: import org.netbeans.api.editor.guards.GuardedSection;
048: import org.netbeans.api.editor.guards.GuardedSectionManager;
049: import org.netbeans.modules.refactoring.api.impl.APIAccessor;
050: import org.netbeans.modules.refactoring.api.impl.SPIAccessor;
051: import org.netbeans.modules.refactoring.api.*;
052: import org.openide.cookies.EditorCookie;
053: import org.openide.filesystems.FileObject;
054: import org.openide.loaders.DataObject;
055: import org.openide.loaders.DataObjectNotFoundException;
056:
057: /**
058: * Container holding RefactoringElements
059: * @author Jan Becicka
060: */
061: public final class RefactoringElementsBag {
062: ArrayList<Transaction> commits;
063: ArrayList<RefactoringElementImplementation> fileChanges;
064:
065: static {
066: SPIAccessor.DEFAULT = new AccessorImpl();
067: }
068:
069: private final List<RefactoringElementImplementation> delegate;
070: private final RefactoringSession session;
071: private Collection<FileObject> readOnlyFiles = new HashSet<FileObject>();
072:
073: /**
074: * Creates an instance of RefactoringElementsBag
075: */
076: RefactoringElementsBag(RefactoringSession session,
077: List<RefactoringElementImplementation> delegate) {
078: this .session = session;
079: this .delegate = delegate;
080: this .commits = new ArrayList<Transaction>();
081: this .fileChanges = new ArrayList<RefactoringElementImplementation>();
082: }
083:
084: /**
085: * Adds RefactoringElementImplementation to this bag.
086: * If RefactoringElementImplementation is in read-only file - status of this element is
087: * changes to RefactoringElement.READ_ONLY
088: * If RefactoringElementImplementation is in guarded block, all registered GuardedBlockHandler
089: * are asked, if they can replace given RefactoringElementImplementation by it's own
090: * RefactoringElementImplementation. If there is no suitable replacement found,
091: * given element is added and it's status is set to RefactringElement.GUARDED
092: *
093: * @param refactoring refactoring, which adds this RefactoringElementImplementation
094: * @param el element to add
095: * @return instance of Problem or null
096: */
097: public Problem add(AbstractRefactoring refactoring,
098: RefactoringElementImplementation el) {
099: Problem p = null;
100: //isQuery should be used
101: if (isReadOnly(el) && !(refactoring instanceof WhereUsedQuery)) {
102: FileObject file = el.getParentFile();
103: readOnlyFiles.add(file);
104: el.setEnabled(false);
105: el.setStatus(el.READ_ONLY);
106: delegate.add(el);
107: //isQuery should be used
108: } else if (isGuarded(el)
109: && !(refactoring instanceof WhereUsedQuery)) {
110: ArrayList<RefactoringElementImplementation> proposedChanges = new ArrayList<RefactoringElementImplementation>();
111: ArrayList<Transaction> transactions = new ArrayList<Transaction>();
112: for (GuardedBlockHandler gbHandler : APIAccessor.DEFAULT
113: .getGBHandlers(refactoring)) {
114: el.setEnabled(false);
115: p = APIAccessor.DEFAULT.chainProblems(
116: gbHandler.handleChange(el, proposedChanges,
117: transactions), p);
118:
119: if (p != null && p.isFatal())
120: return p;
121:
122: delegate.addAll(proposedChanges);
123:
124: for (Transaction transaction : transactions) {
125: registerTransaction(transaction);
126: }
127:
128: if (!proposedChanges.isEmpty()
129: || !transactions.isEmpty())
130: return p;
131:
132: }
133: el.setEnabled(false);
134: el.setStatus(el.GUARDED);
135: delegate.add(el);
136: } else {
137: delegate.add(el);
138: }
139: return p;
140: }
141:
142: /**
143: * Adds all RefactringElements from given Collection using #add method
144: * @param refactoring refactoring, which adds this RefactoringElement
145: * @param elements Collection of RefactoringElements
146: * @return instance of Problem or null
147: */
148: public Problem addAll(AbstractRefactoring refactoring,
149: Collection<RefactoringElementImplementation> elements) {
150: Problem p = null;
151: for (RefactoringElementImplementation rei : elements) {
152: p = APIAccessor.DEFAULT.chainProblems(p, add(refactoring,
153: rei));
154: if (p != null && p.isFatal())
155: return p;
156: }
157: return p;
158: }
159:
160: /**
161: *
162: * @return RefactoringSession associated with this RefactoringElementsBag
163: */
164: public RefactoringSession getSession() {
165: return session;
166: }
167:
168: Collection<FileObject> getReadOnlyFiles() {
169: return readOnlyFiles;
170: }
171:
172: /**
173: * commits are called after all changes are performed
174: * @param commit Transaction to commit
175: * @see Transaction
176: * @see BackupFacilty
177: */
178: public void registerTransaction(Transaction commit) {
179: if (APIAccessor.DEFAULT.isCommit(session))
180: if (!commits.contains(commit))
181: commits.add(commit);
182: }
183:
184: /**
185: * fileChanges are performed after all element changes
186: * @param changes changes to be performed
187: * @see Transaction
188: * @see BackupFacilty
189: */
190: public Problem addFileChange(AbstractRefactoring refactoring,
191: RefactoringElementImplementation el) {
192: if (APIAccessor.DEFAULT.isCommit(session))
193: fileChanges.add(el);
194: return null;
195: }
196:
197: private boolean isReadOnly(RefactoringElementImplementation rei) {
198: return !rei.getParentFile().canWrite();
199: }
200:
201: /**
202: * TODO: GuardedQuery is still missing
203: * this solution has performance issues.
204: */
205: private boolean isGuarded(RefactoringElementImplementation el) {
206: if (el.getPosition() == null)
207: return false;
208: try {
209: DataObject dob = DataObject.find(el.getParentFile());
210: EditorCookie e = dob.getCookie(EditorCookie.class);
211: if (e != null) {
212: GuardedSectionManager manager = GuardedSectionManager
213: .getInstance(e.openDocument());
214: if (manager != null) {
215: Position elementStart = el.getPosition().getBegin()
216: .getPosition();
217: Position elementEnd = el.getPosition().getEnd()
218: .getPosition();
219: for (GuardedSection section : manager
220: .getGuardedSections()) {
221: if (section.contains(elementStart, true)
222: || section.contains(elementEnd, true)) {
223: return true;
224: }
225: }
226: }
227: }
228: } catch (DataObjectNotFoundException ex) {
229: java.util.logging.Logger.getLogger("global").log(
230: java.util.logging.Level.SEVERE, // NOI18N
231: ex.getMessage(), ex);
232: } catch (IOException ex) {
233: java.util.logging.Logger.getLogger("global").log(
234: java.util.logging.Level.SEVERE, // NOI18N
235: ex.getMessage(), ex);
236: }
237: return false;
238: }
239: }
|