1 /*******************************************************************************
2  * Copyright (c) 2011 BestSolution.at and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  * Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation
13  * Wim Jongman <wim.jongman@remainsoftware.com> Bug 432892: Eclipse 4 Application does not work after renaming the
14  * project name
15  ******************************************************************************/
16 package org.eclipse.e4.tools.emf.editor3x.refactorparticipants;
17 
18 import java.util.HashMap;
19 import java.util.Map;
20 
21 import org.eclipse.core.resources.IFile;
22 import org.eclipse.core.resources.IProject;
23 import org.eclipse.core.runtime.CoreException;
24 import org.eclipse.core.runtime.IPath;
25 import org.eclipse.core.runtime.IProgressMonitor;
26 import org.eclipse.core.runtime.OperationCanceledException;
27 import org.eclipse.e4.tools.emf.editor3x.RefactorModel;
28 import org.eclipse.ltk.core.refactoring.CompositeChange;
29 import org.eclipse.ltk.core.refactoring.TextChange;
30 import org.eclipse.ltk.core.refactoring.TextFileChange;
31 import org.eclipse.pde.internal.ui.refactoring.MovedTextFileChange;
32 import org.eclipse.search.core.text.TextSearchEngine;
33 import org.eclipse.search.core.text.TextSearchMatchAccess;
34 import org.eclipse.search.core.text.TextSearchRequestor;
35 import org.eclipse.search.ui.text.FileTextSearchScope;
36 import org.eclipse.text.edits.MultiTextEdit;
37 import org.eclipse.text.edits.ReplaceEdit;
38 import org.eclipse.text.edits.TextEditGroup;
39 
40 @SuppressWarnings("restriction")
41 class RefactorParticipantDelegate {
42 
43 	private static final String E4_MODEL_CHANGES = "Eclipse 4 Application Model Changes"; //$NON-NLS-1$
44 
45 	/**
46 	 * Creates a set of changes and returns a new {@link CompositeChange} or
47 	 * adds the changes to the passed {@link CompositeChange}.
48 	 *
49 	 * @param pProgressMonitor
50 	 * @param pModel
51 	 *
52 	 * @return a set of changes in a {@link CompositeChange}
53 	 * @throws CoreException
54 	 * @throws OperationCanceledException
55 	 */
createChange(IProgressMonitor pProgressMonitor, final RefactorModel pModel)56 	public static CompositeChange createChange(IProgressMonitor pProgressMonitor, final RefactorModel pModel)
57 			throws CoreException, OperationCanceledException {
58 
59 		final String[] filenames = { "*.e4xmi" }; //$NON-NLS-1$
60 		final FileTextSearchScope scope = FileTextSearchScope.newWorkspaceScope(filenames, false);
61 
62 		final Map<IFile, TextFileChange> changes = new HashMap<>();
63 		final TextSearchRequestor searchRequestor = new TextSearchRequestor() {
64 
65 			@Override
66 			public boolean acceptPatternMatch(TextSearchMatchAccess matchAccess) throws CoreException {
67 				final IFile file = matchAccess.getFile();
68 				TextFileChange change = changes.get(file);
69 
70 				if (change == null) {
71 					final TextChange textChange = pModel.getTextChange(file);
72 					if (textChange != null) {
73 						return false;
74 					}
75 
76 					if (pModel.isProjectRename()
77 							&& file.getProject().equals(pModel.getOldProject())) {
78 						// The project/resources get refactored before the
79 						// TextChange is applied, therefore we need their
80 						// future locations
81 						final IProject newProject = pModel.getNewProject();
82 
83 						// If the model is in a non-standard location the
84 						// new project will keep that location, only the project
85 						// will be changed
86 						final IPath oldFile = file.getFullPath().removeFirstSegments(
87 								1);
88 						final IFile newFile = newProject.getFile(oldFile);
89 
90 						change = new MovedTextFileChange(file.getName(),
91 								newFile, file);
92 						change.setEdit(new MultiTextEdit());
93 						changes.put(file, change);
94 
95 					} else {
96 						change = new TextFileChange(file.getName(), file);
97 						change.setEdit(new MultiTextEdit());
98 						changes.put(file, change);
99 					}
100 				}
101 
102 				final ReplaceEdit edit = new ReplaceEdit(
103 						matchAccess.getMatchOffset(),
104 						matchAccess.getMatchLength(),
105 						pModel.getNewTextCurrentIndex());
106 				change.addEdit(edit);
107 				change.addTextEditGroup(new TextEditGroup(E4_MODEL_CHANGES,
108 						edit));
109 				return true;
110 			}
111 		};
112 
113 		CompositeChange result;
114 		final TextSearchEngine searchEngine = TextSearchEngine.create();
115 		int count = pModel.getRenameCount();
116 		while (count > 0) {
117 			pModel.setIndex(count - 1);
118 			searchEngine.search(
119 					scope,
120 					searchRequestor,
121 					TextSearchEngine.createPattern(
122 							pModel.getOldTextCurrentIndex(), true, false),
123 					pProgressMonitor);
124 			count--;
125 		}
126 
127 		if (changes.isEmpty()) {
128 			return null;
129 		}
130 
131 		result = new CompositeChange(E4_MODEL_CHANGES);
132 		for (final TextFileChange c : changes.values()) {
133 			result.add(c);
134 		}
135 		return result;
136 	}
137 }
138