/*******************************************************************************
* Copyright (c) 2015 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.qt.ui.resources;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.internal.qt.ui.Activator;
import org.eclipse.cdt.internal.qt.ui.editor.QtProjectFileKeyword;
import org.eclipse.cdt.internal.qt.ui.pro.parser.QtProjectFileModifier;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
/**
* Job that calls the <code>QtProjectFileModifier</code> after changes to resources found in Qt Projects in order to update their
* <code>SOURCES</code> variable.
*/
public class QtProjectFileUpdateJob extends Job {
private List<IResourceDelta> deltaList;
public QtProjectFileUpdateJob(List<IResourceDelta> deltas) {
super("Update Qt Project File(s)"); //$NON-NLS-1$
this.deltaList = deltas;
}
private IFile findQtProjectFile(IProject project) throws CoreException {
for (IResource member : project.members()) {
if (member.getType() == IResource.FILE
&& member.getFileExtension().equals("pro")) { //$NON-NLS-1$
return (IFile) member;
}
}
return null;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
// Cache the project files so we don't continuously open them
Map<IProject, QtProjectFileModifier> modifierMap = new HashMap<>();
Map<IProject, IFile> projectFileMap = new HashMap<>();
for (IResourceDelta delta : deltaList) {
IResource resource = delta.getResource();
IProject project = resource.getProject();
QtProjectFileModifier modifier = modifierMap.get(project);
if (modifier == null) {
IFile proFile = null;
try {
proFile = findQtProjectFile(project);
} catch (CoreException e) {
Activator.log("Unable to find Qt Project File", e); //$NON-NLS-1$
}
// We can't update a project file if it doesn't exist
if (proFile == null) {
continue;
}
// Cache the project file under its containing project and read its contents into a Document.
projectFileMap.put(project, proFile);
StringBuilder sb = new StringBuilder();
try (InputStream is = proFile.getContents()) {
int read = -1;
while ((read = is.read()) > 0) {
sb.append((char) read);
}
IDocument document = new Document(sb.toString());
modifier = new QtProjectFileModifier(document);
modifierMap.put(project, modifier);
} catch (IOException e) {
Activator.log(e);
break;
} catch (CoreException e) {
Activator.log(e);
break;
}
}
// Determine from the file extension where we should add this resource
String variableKeyword = null;
if ("cpp".equals(resource.getFileExtension())) { //$NON-NLS-1$
variableKeyword = QtProjectFileKeyword.VAR_SOURCES.getKeyword();
} else if ("h".equals(resource.getFileExtension())) { //$NON-NLS-1$
variableKeyword = QtProjectFileKeyword.VAR_HEADERS.getKeyword();
}
if ((delta.getFlags() & IResourceDelta.MOVED_FROM) > 0) {
// Resource was moved from another location.
if (project.getFullPath().isPrefixOf(delta.getMovedFromPath())) {
String oldValue = delta.getMovedFromPath().makeRelativeTo(project.getFullPath()).toString();
String newValue = resource.getProjectRelativePath().toString();
if (modifier.replaceVariableValue(variableKeyword, oldValue, newValue)) {
// If we successfully replaced the variable, continue. If this line is not executed it means we failed to
// replace and the file will be added in the subsequent code for the ADDED case.
continue;
}
}
} else if ((delta.getFlags() & IResourceDelta.MOVED_TO) > 0) {
// Somewhat edge-case where a file from one Qt Project was moved to a different Qt Project.
if (project.getFullPath().isPrefixOf(delta.getMovedToPath())) {
// Getting here means that the replace was taken care of by the previous code. Otherwise, it will be removed in
// the subsequent code for the REMOVED case.
continue;
}
}
if ((delta.getKind() & IResourceDelta.ADDED) > 0) {
String value = resource.getProjectRelativePath().toString();
if (value != null) {
modifier.addVariableValue(variableKeyword, value);
}
} else if ((delta.getKind() & IResourceDelta.REMOVED) > 0) {
String value = resource.getProjectRelativePath().toString();
if (value != null) {
modifier.removeVariableValue(variableKeyword, value);
}
}
}
// Write all documents to their respective files
for (IProject project : projectFileMap.keySet()) {
IFile file = projectFileMap.get(project);
IDocument document = modifierMap.get(project).getDocument();
try {
file.setContents(new ByteArrayInputStream(document.get().getBytes()), 0, null);
} catch (CoreException e) {
Activator.log(e);
}
}
return Status.OK_STATUS;
}
}