/*
* Copyright (c) 2010-2012 Research In Motion Limited. All rights reserved.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License, Version 1.0,
* which accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*
*/
package net.rim.ejde.internal.ui.wizards;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.net.URI;
import net.rim.ejde.internal.core.IConstants;
import net.rim.ejde.internal.util.FileUtils;
import net.rim.ejde.internal.util.ImportUtils;
import net.rim.ejde.internal.util.Messages;
import net.rim.ejde.internal.util.PackageUtils;
import net.rim.ejde.internal.util.ProjectUtils;
import net.rim.sdk.resourceutil.ResourceCollection;
import net.rim.sdk.resourceutil.ResourceCollectionFactory;
import net.rim.sdk.resourceutil.ResourceConstants;
import net.rim.sdk.resourceutil.ResourceElement;
import net.rim.sdk.resourceutil.ResourceLocale;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.dialogs.WizardNewFileCreationPage;
import org.eclipse.ui.internal.ide.dialogs.CreateLinkedResourceGroup;
/**
* This page is used to create and link new resource files.
*
* @author jkeshavarzi
*/
public class NewResourceFileWizardPage extends WizardNewFileCreationPage {
private String _resourcePackageId;
private boolean _validPackage;
private static final Logger logger = Logger.getLogger( NewResourceFileWizardPage.class );
private IPackageFragment _userSelectedPackage;
private IPackageFragmentRoot _userSelectedSourceFolder;
private String _userSelectedProject;
private URI linkFileLocation;
/**
* Constructs a new resource wizard page.
*/
public NewResourceFileWizardPage( IStructuredSelection selection ) {
super( "NewResourceFileWizardPage", selection ); //$NON-NLS-1$
setTitle( Messages.NewResourceFileWizardNewProjectTitle );
setDescription( Messages.NewResourceFileWizardDescription );
}
/**
* This method returns the resource package id.
*
* @return A string containing the package id.
*/
public String getResourcePackageId() {
return _resourcePackageId;
}
/**
* @return the package selected by the user within the new resource dialog
*/
public IPackageFragment getUserSelectedPackage() {
return _userSelectedPackage;
}
/**
* @return the source folder selected by the user within the new resource dialog
*/
public IPackageFragmentRoot getUserSelectedSourceFolder() {
return _userSelectedSourceFolder;
}
/**
* @return the project selected by the user within the new resource dialog
*/
public String getUserSelectedProject() {
return _userSelectedProject;
}
/**
* This method returns whether the package selected is valid.
*
* @return True is the package is valid, false otherwise.
*/
public boolean isValidPackage() {
return _validPackage;
}
@Override
protected boolean validatePage() {
// perform preliminary page validation with
// WizardNewFileCreationPage.validatePage() method
boolean validPage = super.validatePage();
if( validPage ) {
if( !getFileName().matches( "([A-Za-z0-9]+([_][A-Za-z0-9]+){0,2}.rrc)|([A-Za-z0-9]+.rrh)" ) ) {
setErrorMessage( Messages.INVALID_FILE_NAME );
validPage = false;
}
}
if( validPage ) {
/* ensures the user selected a package under an eclipse source directory */
boolean sourceFolderExists = false;
_userSelectedProject = getContainerFullPath().segment( 0 );
String path = getContainerFullPath().toString();
IPackageFragmentRoot sourceRoots[] = ProjectUtils.getProjectSourceFolders( ProjectUtils
.getProject( _userSelectedProject ) );
// Iterate through all source folders
for( IPackageFragmentRoot sourceRoot : sourceRoots ) {
String sourcePath = sourceRoot.getPath().toString() + IPath.SEPARATOR;
if( path.startsWith( sourcePath ) && ( path.length() > sourcePath.length() ) ) {
String selectedPackage = path.substring( sourcePath.length() ).replaceAll( "/", "." ); //$NON-NLS-1$ //$NON-NLS-2$
// Since our current code standard is 1.5 do not use 1.6 methods yet.
if( !StringUtils.isEmpty( selectedPackage ) && sourceRoot.getPackageFragment( selectedPackage ).exists() ) {
sourceFolderExists = true;
_userSelectedPackage = sourceRoot.getPackageFragment( selectedPackage );
_userSelectedSourceFolder = sourceRoot;
break;
}
}
}
if( !sourceFolderExists ) {
setErrorMessage( Messages.INVALID_PARENT_FOLDER_WIZARD_PAGE );
validPage = false;
}
}
if( validPage ) {
try {
/*
* Here we get access to the private field linkedResourceGroup and get the URI information for the linked .rrh
* file. We then parse that file to get its package information
*/
Field field = WizardNewFileCreationPage.class.getDeclaredField( "linkedResourceGroup" ); //$NON-NLS-1$
field.setAccessible( true );
linkFileLocation = ( (CreateLinkedResourceGroup) field.get( this ) ).getLinkTargetURI();
// If file is not linked, skip next code.
if( linkFileLocation == null ) {
_validPackage = true;
} else {
// Initialize the resourcePackageID to properly identify if the package is valid
_resourcePackageId = null;
File linkFile = new File( linkFileLocation );
if( getFileName().endsWith( ResourceConstants.RRH_SUFFIX ) ) {
/*
* Resource file is a rrh file. We must determine if its going in the correct package.
*/
if( linkFile.length() == 0 ) {
setErrorMessage( Messages.RRH_NO_PACKAGE_ERROR );
return false;
}
_resourcePackageId = PackageUtils.getRRHPackageID( linkFile );
} else {
/*
* Resource file is a rrc file. We must determine the correct package with its corresponding rrh file.
*/
String rrhFileName = getFileName();
if( rrhFileName.contains( "_" ) ) { //$NON-NLS-1$
rrhFileName = rrhFileName.substring( 0, rrhFileName.indexOf( "_" ) ) + ResourceConstants.RRH_SUFFIX; //$NON-NLS-1$
} else {
rrhFileName = rrhFileName.replace( ResourceConstants.RRC_SUFFIX, ResourceConstants.RRH_SUFFIX );
}
File rrhFile = new File( linkFile.getParent() + File.separator + rrhFileName );
if( rrhFile.exists() && ( rrhFile.length() != 0 ) ) {
_resourcePackageId = PackageUtils.getRRHPackageID( rrhFile );
}
}
/*
* Get package selected by user within the new resource wizard dialog and ensure it matches the package
* described in the .rrh file.
*/
_userSelectedProject = getContainerFullPath().segment( 0 );
if( _resourcePackageId == null ) {
/*
* Resource header file could not be found or contains no package. Ensuring correct package will have to
* be left to user.
*/
_validPackage = true;
} else if( !_resourcePackageId.equals( _userSelectedPackage.getElementName() ) ) {
setMessage( NLS.bind( Messages.INVALID_PACKAGE_SELECTED, _resourcePackageId ), IMessageProvider.WARNING );
_validPackage = false;
} else {
_validPackage = true;
}
}
} catch( Throwable e ) {
logger.error( "Validation Error", e ); //$NON-NLS-1$
}
}
if( validPage ) {
// Add warning if existing sibling resource exist
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject( _userSelectedProject );
IFile foundSiblingFile = getSiblingFile( getFileName(), project );
if( foundSiblingFile != null ) {
if( foundSiblingFile.isLinked() ) {
setMessage(
NLS.bind( Messages.EXISTING_LINKED_SIBLING_FOUND_WARNING, foundSiblingFile.getName(), getFileName() ),
IMessageProvider.WARNING );
} else {
setMessage(
NLS.bind( Messages.EXISTING_COPIED_SIBLING_FOUND_WARNING, foundSiblingFile.getName(), getFileName() ),
IMessageProvider.WARNING );
}
}
}
return validPage;
}
private IFile getSiblingFile( String fileName, IProject project ) {
String rrhFileName = null;
String rrcRootLocaleFileName = null;
String rrcRootLanguageLocaleFileName = null;
String siblingFileName = null;
String fileNamePrefix = null;
IFile foundSiblingFile = null;
boolean hasCountryCode = ( fileName.indexOf( IConstants.UNDERSCORE_STRING ) != fileName
.lastIndexOf( IConstants.UNDERSCORE_STRING ) );
if( fileName.contains( IConstants.UNDERSCORE_STRING ) ) {
rrhFileName = fileName.substring( 0, fileName.indexOf( IConstants.UNDERSCORE_STRING ) )
+ ResourceConstants.RRH_SUFFIX;
// set root rrc file name
rrcRootLocaleFileName = fileName.substring( 0, fileName.indexOf( IConstants.UNDERSCORE_STRING ) )
+ ResourceConstants.RRC_SUFFIX;
if( hasCountryCode ) {
// set root language rrc file name
rrcRootLanguageLocaleFileName = fileName.substring( 0, fileName.lastIndexOf( IConstants.UNDERSCORE_STRING ) )
+ ResourceConstants.RRC_SUFFIX;
}
} else {
rrhFileName = fileName.substring( 0, fileName.lastIndexOf( IConstants.DOT_MARK ) ) + ResourceConstants.RRH_SUFFIX;
rrcRootLocaleFileName = fileName.substring( 0, fileName.lastIndexOf( IConstants.DOT_MARK ) )
+ ResourceConstants.RRC_SUFFIX;
}
if( fileName.endsWith( ResourceConstants.RRH_SUFFIX ) ) {
siblingFileName = rrcRootLocaleFileName;
foundSiblingFile = ProjectUtils.getProjectIFile( project, siblingFileName, false );
if( foundSiblingFile == null ) {
fileNamePrefix = fileName.substring( 0, fileName.lastIndexOf( IConstants.DOT_MARK ) )
+ IConstants.UNDERSCORE_STRING;
foundSiblingFile = ProjectUtils.getProjectIFile( project, fileNamePrefix, false );
siblingFileName = foundSiblingFile == null ? null : foundSiblingFile.getName();
}
} else {
siblingFileName = rrhFileName;
foundSiblingFile = ProjectUtils.getProjectIFile( project, siblingFileName, false );
if( foundSiblingFile == null ) {
siblingFileName = rrcRootLocaleFileName;
foundSiblingFile = ProjectUtils.getProjectIFile( project, siblingFileName, false );
}
if( foundSiblingFile == null ) {
siblingFileName = rrcRootLanguageLocaleFileName;
foundSiblingFile = ProjectUtils.getProjectIFile( project, siblingFileName, false );
}
if( foundSiblingFile == null ) {
if( fileName.contains( IConstants.UNDERSCORE_STRING ) ) {
fileNamePrefix = fileName.substring( 0, fileName.indexOf( IConstants.UNDERSCORE_STRING ) )
+ IConstants.UNDERSCORE_STRING;
} else {
fileNamePrefix = fileName.substring( 0, fileName.lastIndexOf( IConstants.DOT_MARK ) )
+ IConstants.UNDERSCORE_STRING;
}
foundSiblingFile = ProjectUtils.getProjectIFile( project, fileNamePrefix, false );
siblingFileName = foundSiblingFile == null ? null : foundSiblingFile.getName();
}
}
return foundSiblingFile;
}
// This method was overwritten to provide fix for DPI222448 and some
// new functionality.
@Override
public IFile createNewFile() {
String fileName = this.getFileName();
IFile newResourceFile = null;
IPath resFilePath = null;
IPath resParentPath = null;
String rrcRootLocaleFileName = null;
String rrcRootLanguageLocaleFileName = null;
IFile siblingIFile = null;
String pkgString = null;
boolean hasCountryCode = ( fileName.indexOf( IConstants.UNDERSCORE_STRING ) != fileName
.lastIndexOf( IConstants.UNDERSCORE_STRING ) );
if( fileName.contains( IConstants.UNDERSCORE_STRING ) ) {
// set root rrc file name
rrcRootLocaleFileName = fileName.substring( 0, fileName.indexOf( IConstants.UNDERSCORE_STRING ) )
+ ResourceConstants.RRC_SUFFIX;
if( hasCountryCode ) {
// set root language rrc file name
rrcRootLanguageLocaleFileName = fileName.substring( 0, fileName.lastIndexOf( IConstants.UNDERSCORE_STRING ) )
+ ResourceConstants.RRC_SUFFIX;
}
} else {
rrcRootLocaleFileName = fileName.substring( 0, fileName.lastIndexOf( IConstants.DOT_MARK ) )
+ ResourceConstants.RRC_SUFFIX;
}
IProject iProject = ProjectUtils.getProject( _userSelectedProject );
siblingIFile = getSiblingFile( fileName, iProject );
String userSelectedPackage = null;
try {
if( ( siblingIFile != null ) && siblingIFile.exists() ) {
// sibling file is found in the rim project but not under
// the same directory. Possibly file is linked from another
// place.
resFilePath = siblingIFile.getLocation();
File siblingFile = new File( resFilePath.toOSString() );
resParentPath = resFilePath.removeLastSegments( 1 );
resFilePath = resParentPath.append( fileName );
// even though user selects the improper package
// we will match the right package based on
// sibling file package string
if( siblingIFile.getName().endsWith( ResourceConstants.RRH_SUFFIX ) ) {
pkgString = PackageUtils.getRRHPackageString( siblingFile );
} else {
File rrhFile = PackageUtils.getCorrespondingRRHFile( siblingFile );
// eg:- com.rim.test
userSelectedPackage = _userSelectedPackage.getElementName();
// eg:- com/rim/test
userSelectedPackage = PackageUtils.convertPkgIDToString( userSelectedPackage );
if( !rrhFile.exists() ) {
pkgString = userSelectedPackage;
} else {
try {
pkgString = PackageUtils.getRRCPackageString( siblingFile );
} catch( CoreException e ) {
// we don't need to log the error here - method already logging the error
pkgString = userSelectedPackage;
}
}
}
// special case when user try to link resource
// file with country code
// (Res1_en_CA.rrc) in the linked location
// but rrcRootLocaleFileName and
// rrcRootLanguageLocaleFileName is missing in
// that directory will be an error. So we need
// to create those files and linked them as
// well.
File newRootFile = null;
if( !StringUtils.isBlank( rrcRootLocaleFileName ) ) {
newRootFile = new File( resParentPath.append( rrcRootLocaleFileName ).toOSString() );
if( !newRootFile.exists() ) {
newRootFile.createNewFile();
}
}
File newRootLangLocaleFile = null;
if( !StringUtils.isBlank( rrcRootLanguageLocaleFileName ) ) {
newRootLangLocaleFile = new File( resParentPath.append( rrcRootLanguageLocaleFileName ).toOSString() );
if( !newRootLangLocaleFile.exists() ) {
newRootLangLocaleFile.createNewFile();
}
}
File newFile = resFilePath.toFile();
if( !newFile.exists() ) {
String newFileName = newFile.getName();
newFile = new File( resFilePath.toOSString() );
File existingFile = null;
if( linkFileLocation != null ) {
existingFile = new File( linkFileLocation );
}
if( ( existingFile != null ) && existingFile.exists() ) {
FileUtils.copy( existingFile, newFile );
ResourceCollection collection = ResourceCollectionFactory.newResourceCollection( newFile
.getAbsolutePath() );
if( newFileName.endsWith( ResourceConstants.RRH_SUFFIX ) ) {
ResourceLocale existingLocales[] = collection.getLocales();
for( ResourceLocale locale : existingLocales ) {
addMissingLocaleKeys( collection, locale );
}
} else {
String localeName = newFileName.substring(
newFileName.indexOf( "_" ) + 1, newFileName.lastIndexOf( "." ) ); //$NON-NLS-1$ //$NON-NLS-2$
ResourceLocale newLocale = collection.getLocale( localeName );
if( newLocale != null ) {
addMissingLocaleKeys( collection, newLocale );
}
}
} else {
newFile.createNewFile();
if( newFileName.endsWith( ResourceConstants.RRH_SUFFIX ) ) {
// rrh file must have a package declaration
PrintWriter out = new PrintWriter( new FileWriter( newFile ) );
out.println( "package " + PackageUtils.convertPkgStringToID( pkgString ) + ";" );
out.close();
}
}
}
if( siblingIFile.isLinked() ) {
IPath sourceLocation = _userSelectedSourceFolder.getCorrespondingResource().getProjectRelativePath()
.append( pkgString );
IContainer parentFolder = iProject.getFolder( sourceLocation );
if( newRootFile != null ) {
IFile linkRootFile = parentFolder.getFile( new Path( rrcRootLocaleFileName ) );
if( !linkRootFile.exists() ) {
linkRootFile.createLink( new Path( newRootFile.getAbsolutePath() ), IResource.NONE,
new NullProgressMonitor() );
}
}
if( newRootLangLocaleFile != null ) {
IFile linkRootLangFile = parentFolder.getFile( new Path( rrcRootLanguageLocaleFileName ) );
if( !linkRootLangFile.exists() ) {
linkRootLangFile.createLink( new Path( newRootLangLocaleFile.getAbsolutePath() ), IResource.NONE,
new NullProgressMonitor() );
}
}
IFile linkFile = parentFolder.getFile( new Path( fileName ) );
if( !linkFile.exists() ) {
linkFile.createLink( resFilePath, IResource.NONE, new NullProgressMonitor() );
newResourceFile = linkFile;
}
} else {
iProject.refreshLocal( IProject.DEPTH_INFINITE, new NullProgressMonitor() );
newResourceFile = ImportUtils.getProjectBasedFileFromOSBasedFile( _userSelectedProject,
newFile.getAbsolutePath() );
}
} else {
// Sibling file does not exists in the linked
// location.At this point we have no clue where
// to link, so it is better to create the file
// in eclipse workspace.
}
if( newResourceFile == null ) {
super.setFileName( super.getFileName().trim() );
newResourceFile = super.createNewFile();
}
} catch( Throwable e ) {
logger.error( "createNewFile() error", e ); //$NON-NLS-1$
}
return newResourceFile;
}
/**
* This method will add any keys found in the locale but not in the header file to the header file.
*
* @param collection
* - The collection to add missing keys to.
* @param newLocale
* - The locale to check for keys.
*/
private void addMissingLocaleKeys( ResourceCollection collection, ResourceLocale locale ) {
ResourceElement elements[] = locale.getResourceElements();
String key = null;
for( ResourceElement element : elements ) {
key = element.getKey();
if( !collection.containsKey( key ) ) {
collection.addKey( key );
}
}
try {
collection.save();
} catch( IOException e ) {
logger.error( "addMissingLocaleKeys() error", e ); //$NON-NLS-1$
}
}
}