/* * 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.editors.locale; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Vector; import net.rim.ejde.internal.core.ContextManager; import net.rim.ejde.internal.util.ImportUtils; import net.rim.ejde.internal.util.Messages; import net.rim.ejde.internal.util.PackageUtils; import net.rim.sdk.resourceutil.RIMResourceLocale; import net.rim.sdk.resourceutil.ResourceCollection; import net.rim.sdk.resourceutil.ResourceCollectionFactory; import net.rim.sdk.resourceutil.ResourceCollectionListener; 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.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceDescription; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.IPartListener; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.part.MultiPageEditorPart; /** * The multipage editor for blackberry resources * * @author jkeshavarzi * */ public class ResourceEditor extends MultiPageEditorPart { // vector to keep track of the open pages private Vector< ResourceEditorPage > _pages; // this variable keeps track of the resourceCollection. It is used to get locales of the file. private ResourceCollection _resources; private boolean _wasDirty; private ResourceEditorListener _resourceEditorListener; private static final String ROOT = "Root"; // this variable keeps track if resourceChangeListener has already been added to the workspace. This variable was introduced // as a fix to SDR185428 to load pages dynamically in the resource Editor. private static boolean resourceChangeListenerAdded = false; private static final Logger _logger = Logger.getLogger( ResourceEditor.class ); // array of references to open editors in this WorkbenchPage private static IEditorReference[] _openEditorReferences = null; // filename of .rrh/.rrc file that was opened (i.e. double-clicked) by user private String _resourceFilename; // The resource header file for the resource collection private File rrhFile; // The package of the resource when it was opened in the resource editor private String _originalPackage = null; // vector of resource IFiles to be potentially checked out (i.e. opened for edit in Perforce). all IFiles in this vector // correspond to all resource files from all resource bundles opened by user private static Vector< IFile > _checkoutFiles = new Vector< IFile >( 0 ); // vector of ResourceEditorPage objects (used by ResourceEditorOptionsDialog class to activate versioning highlighting) private static Vector< ResourceEditorPage > _resourceEditorPages = new Vector< ResourceEditorPage >( 0 ); private boolean _callByResourceListener = false; // return EditorReferences from all the pages in eclipse public IEditorReference[] getOpenEditorReferences() { Vector< IEditorReference > openEditorReferences = new Vector< IEditorReference >( 0 ); IWorkbenchPage[] workbenchPage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getPages(); int workbenchPageCount = workbenchPage.length; for( int i = 0; i < workbenchPageCount; i++ ) { Collection< IEditorReference > editorReferences = Arrays.asList( workbenchPage[ i ] .getEditorReferences() ); openEditorReferences.addAll( editorReferences ); } return openEditorReferences.toArray( new IEditorReference[ 1 ] ); } private File getRRCFile( File s ) { String[] splitFiles = s.getName().split( "\\." ); String extension = ""; if( splitFiles[ 1 ].toLowerCase().equals( "rrh" ) ) { extension = ".rrc"; } else { extension = ".rrh"; } return new File( ( s.getPath().substring( 0, s.getPath().lastIndexOf( File.separator ) ) + File.separator + splitFiles[ 0 ] + extension ) ); } private class ResourceEditorListener implements IPartListener { private boolean _allowOpen = true; private boolean _openTextEditor = false; private IEditorSite _site; private IEditorInput _input; public ResourceEditorListener( IEditorSite site, IEditorInput input ) { this._site = site; this._input = input; } public void setAllowOpen( boolean allowOpen ) { this._allowOpen = allowOpen; } public void setOpenTextEditor( boolean openTextEditor ) { this._openTextEditor = openTextEditor; } public void partActivated( IWorkbenchPart part ) { } public void partBroughtToTop( IWorkbenchPart part ) { } public void partClosed( IWorkbenchPart part ) { } public void partDeactivated( IWorkbenchPart part ) { } public void partOpened( IWorkbenchPart part ) { if( !( part instanceof ResourceEditor ) ) { return; } if( !_allowOpen ) { part.getSite().getWorkbenchWindow().getActivePage().closeEditor( (IEditorPart) part, false ); if( _openTextEditor ) { try { IDE.openEditor( _site.getWorkbenchWindow().getActivePage(), _input, EditorsUI.DEFAULT_TEXT_EDITOR_ID ); } catch( PartInitException e ) { _logger.error( "Error occurred during Opening the Text Editor for" + _input.getName(), e ); //$NON-NLS-1$ } } } IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); window.getPartService().removePartListener( this ); } } /** * This function adds resourceChangeListener to the workspace to detect the addition of new locales to the exisiting .rrc * files and dynamically add them in the .rrc file if the ResourceEditor is already open The addition of resourceEditor was a * fix to SDR185428. */ public ResourceEditor() { // when ResourceEditor is first initialized _wasdirty is false. ResourceEditor is not dirty. Dirty bit is used in the // doSave function. _wasDirty = false; // if resource change listener is not already added to the workspace add it to the workspace. if( !resourceChangeListenerAdded ) { // set the resourceChangeListener flag to true. when this flag is set to true the editor is not closed in the // createPages() method resourceChangeListenerAdded = true; // add Resource Change Listener to listen to addition of locales so that they can be added dynamically ResourcesPlugin.getWorkspace().addResourceChangeListener( new IResourceChangeListener() { // @Override public void resourceChanged( IResourceChangeEvent event ) { IResourceDelta delta = event.getDelta(); try { delta.accept( new IResourceDeltaVisitor() { // @Override /** * We are interested in checking if the file added was an RRH or a RRC file. */ public boolean visit( IResourceDelta resourceDelta ) throws CoreException { IResource resource = resourceDelta.getResource(); int type = resource.getType(); int kind = resourceDelta.getKind(); // check to see if the resource added is a file if( type == IResource.FILE ) { // check to see if the resource is of the kind added if( kind == IResourceDelta.ADDED ) { // check to see if the resource ends with .rrc or .rrh extension (these are resource file // extensions) if( resource.toString().endsWith( ResourceConstants.RRH_SUFFIX ) || resource.getName().toString().endsWith( ResourceConstants.RRC_SUFFIX ) ) { // store the resource as final so that it can be used in the run method run method can // not refer to external non final variables final IResource runResource = resource; // Display thread was introduced as a 'blog' suggestion because changed to // ResourceEditor could not be done in the non-UI thread. Display.getDefault().asyncExec( new Runnable() { public void run() { // your stuff here ... try { // get a reference to open editors. // _openEditorReferences = // PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getEditorReferences(); _openEditorReferences = getOpenEditorReferences(); // addPage(new EditorPart(), new FileEditorInput((IFile)resource)); // ResourceEditor.getInstance().createPages(); // createPages(); // System.out.println("Hello"); // check through all the open editors to see if any of the editors that we // want to add the locale to is opened. // Example : say if a.rrh and a.rrc already exist. Then if we add // a_en.rrc ( english locale ) we want to browse through all the // _openEditroReferences to see if a.rrh or a.rrc is opened. for( int i = 0; i < _openEditorReferences.length; i++ ) { // Check to see if the referenced editor is the instance of // ResourceEditor if( _openEditorReferences[ i ].getEditor( true ) instanceof ResourceEditor ) { ResourceEditor editor = (ResourceEditor) _openEditorReferences[ i ] .getEditor( true ); // get the name of the Input Editor name from the // _openEditorReferences. Usually it is a.rrh file as set in the // init function. However it can be a.rrc file in cases where the // editor has no .rrh file. String existingEditorFilename = _openEditorReferences[ i ] .getEditor( true ).getEditorInput().getName(); // get the name of the .rrh file or .rrc file that we just added String thisEditorFilename = runResource.getName(); // store the trimmed name for existing editor String existingEditorFilenameTrim; // store the name for the editor of the file that is added String thisEditorFilenameTrim; // store the path of the parent of the resource String resourcePath = runResource.getParent().getLocation() .toOSString(); // store the path of the parent of the editor String editorPath = ( (FileEditorInput) ( editor.getEditorInput() ) ) .getFile().getParent().getLocation().toOSString(); // strip off both the existingEditor file name and thisEditor // filename of its .rrc and .rrh extension and the locale name. if( existingEditorFilename .endsWith( ResourceConstants.RRH_SUFFIX ) || existingEditorFilename .endsWith( ResourceConstants.RRC_SUFFIX ) ) { if( existingEditorFilename.contains( "_" ) ) { //$NON-NLS-1$ existingEditorFilenameTrim = existingEditorFilename .substring( 0, existingEditorFilename.indexOf( "_" ) ); //$NON-NLS-1$ } else { existingEditorFilenameTrim = existingEditorFilename .substring( 0, existingEditorFilename.indexOf( "." ) ); //$NON-NLS-1$ } if( thisEditorFilename.contains( "_" ) ) { //$NON-NLS-1$ thisEditorFilenameTrim = thisEditorFilename.substring( 0, thisEditorFilename.indexOf( "_" ) ); //$NON-NLS-1$ } else { thisEditorFilenameTrim = thisEditorFilename.substring( 0, thisEditorFilename.indexOf( "." ) ); //$NON-NLS-1$ } // if the thisEditorFileNameTrim is equal to the // existingEditorFilenameTrim and the project of this editor // is equal to the project of the resource then only add the // dynamically added locale if( thisEditorFilenameTrim .equals( existingEditorFilenameTrim ) && resourcePath.equals( editorPath ) ) { // existing editor on WorkbenchPage and this editor belong // to the same ResourceCollection // save previous changes in the editor editor.doSave( new NullProgressMonitor() ); String locale = thisEditorFilename.substring( thisEditorFilename.indexOf( "_" ) + 1, //$NON-NLS-1$ thisEditorFilename.indexOf( "." ) ); //$NON-NLS-1$ // editor . _wasDirty = false; // if the locale is already a part of the editor do not // add if( editor._resources.getLocale( locale ) != null ) { break; } // set callByResourceListener to true so that in // createPages function the editor. Close is not called editor._callByResourceListener = true; // dispose the existing pages of the editor editor.dispose(); // reinitialize the editor again editor.init( _openEditorReferences[ i ].getEditor( true ) .getEditorSite(), new FileEditorInput( (IFile) runResource ) ); // add Pages to editor editor.createPages(); // set the callByResourceListener to false editor._callByResourceListener = false; } } } } } catch( Exception e ) { } } } ); // new Runnable object ends here } // end of if }// end of if }// end of if // return true to continue visiting the Delta tree. return true; }// visit ends here } );// new ResourceDeltaVisitor ends here } catch( CoreException e ) { // log.error(e.getMessage(), e); e.printStackTrace(); } } } ); // new IResourceChangeListener ends here } } public void doSave( IProgressMonitor monitor ) { try { _resources.save(); // Check if package was changed. String rrhPackage = PackageUtils.getRRHPackageID( rrhFile ); if( !_originalPackage.equals( rrhPackage ) ) { // Attempt to find a non linked rrhIFile IFile files[] = ResourcesPlugin.getWorkspace().getRoot() .findFilesForLocation( new Path( rrhFile.getAbsolutePath() ) ); IFile rrhIFile = null; for( IFile file : files ) { if( !file.isLinked() ) { rrhIFile = file; break; } } if( files.length != 0 && rrhIFile == null ) { rrhIFile = files[ 0 ]; } IJavaElement packageFolder = JavaCore.create( rrhIFile.getParent() ); IPackageFragmentRoot sourceFolder = (IPackageFragmentRoot) packageFolder.getParent(); try { moveResources( rrhIFile, sourceFolder.createPackageFragment( rrhPackage, true, new NullProgressMonitor() ) ); } catch( Exception e ) { _logger.error( "doSave: error moving resources", e ); //$NON-NLS-1$ } } if( _wasDirty ) { _wasDirty = false; firePropertyChange( IEditorPart.PROP_DIRTY ); } // get eclipse workspace final IWorkspace workspace = ResourcesPlugin.getWorkspace(); // get eclipse workspace description final IWorkspaceDescription workspaceDescription = workspace.getDescription(); // get autoBuildFlag final boolean autoBuild = workspaceDescription.isAutoBuilding(); IProject project = ( (FileEditorInput) ( this.getEditorInput() ) ).getFile().getProject(); // if autobuild is checked build eclipse project if( autoBuild ) { try { project.build( IncrementalProjectBuilder.INCREMENTAL_BUILD, null ); } catch( CoreException e ) { e.printStackTrace(); } } // We must refresh the project because we are using a JAR that uses File objects to save, instead of eclipse IFiles. project.refreshLocal( IProject.DEPTH_INFINITE, monitor ); } catch( IOException e ) { TableViewer viewer = getActiveResourceEditorPage().getTableViewer(); Status status = new Status( IStatus.ERROR, ContextManager.PLUGIN_ID, IStatus.OK, "Unable to open file for writing.", e ); ErrorDialog.openError( viewer.getControl().getShell(), "Error - Resource Editor", "Error saving file.", status ); monitor.setCanceled( true ); } catch( CoreException e ) { _logger.error( "doSave: error getting package", e ); //$NON-NLS-1$ } } public void doSaveAs() { // "Save As" not allowed } public void init( IEditorSite site, IEditorInput input ) throws PartInitException { if( !( input instanceof IFileEditorInput ) ) { throw new PartInitException( input.getName() + " is not part of the current project." ); } String messagePrompt = ""; //$NON-NLS-1$ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); _resourceEditorListener = new ResourceEditorListener( site, input ); window.getPartService().addPartListener( _resourceEditorListener ); FileEditorInput fileEditorInput = (FileEditorInput) input; // Check out file corresponding to the locale that is open in this ResourceEditor (Opened for Edit in Perforce) IFile[] checkOutFiles = new IFile[ 1 ]; checkOutFiles[ 0 ] = ( (IFileEditorInput) input ).getFile(); ResourcesPlugin.getWorkspace().validateEdit( checkOutFiles, null ); _openEditorReferences = null; try { // _openEditorReferences = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getEditorReferences(); _openEditorReferences = getOpenEditorReferences(); // array of references to open editors in this WorkbenchPage this will be used to prevent multiple ResourceEditor // instances from being open for the same resource collection } catch( Exception e ) { _logger.error( "init:", e ); //$NON-NLS-1$ } // keeps track of the recently added _resourceFilename for this ResourceEditor. _resourceFilename = fileEditorInput.getName(); // Fix for SDR169264 (eJDE: Resource Editor can show incorrect tab when switching between locales via double-click in // managing views) inputFileAbsolutePath = inputFileAbsolutePath.substring(0, // inputFileAbsolutePath.lastIndexOf(File.separator)); if selected file is .rrc file, we try to get corresponding .rrh // file String tempFilename = _resourceFilename; if( tempFilename.contains( "_" ) ) { //$NON-NLS-1$ tempFilename = tempFilename.substring( 0, tempFilename.indexOf( "_" ) ) + ResourceConstants.RRH_SUFFIX; //$NON-NLS-1$ } else { tempFilename = tempFilename.replace( ResourceConstants.RRC_SUFFIX, ResourceConstants.RRH_SUFFIX ); } rrhFile = new File( ( (Path) fileEditorInput.getPath() ).toFile().getParentFile(), tempFilename ); try { _originalPackage = PackageUtils.getRRHPackageID( rrhFile ); } catch( Exception e ) { _logger.error( "init: error getting original package", e ); //$NON-NLS-1$ } // Check#1: Checks to see if the resource header file exists in the same location as the rrc file. This is a mandatory // check needed to create the resourceCollection in RIA. if( rrhFile.exists() ) { try { _resources = ResourceCollectionFactory.newResourceCollection( rrhFile.getAbsolutePath() ); _resources.addListener( createCollectionListener() ); } catch( Exception e ) { throw new PartInitException( e.getMessage() ); } // Check#2: Checks to see if the corresponding rrh file exists in the workspace. If createResourceFileEditorInput does // not return null, then the corresponding resource was found. We can then call super and return. FileEditorInput rrhFileEditorInput; if( ( rrhFileEditorInput = createResourceFileEditorInput( rrhFile ) ) != null ) { // Check#3: Checks to ensure that the resource collection has locale files. If no locale files exist, RE cannot be // opened. ResourceLocale[] resourceLocales = _resources.getLocales(); IFile rrhIFile = ImportUtils.getProjectBasedFileFromOSBasedFile( rrhFile.getAbsolutePath() ); File rrcFile = getRRCFile( rrhFile ); IFile rrcIFile = ImportUtils.getProjectBasedFileFromOSBasedFile( rrcFile.getAbsolutePath() ); if( resourceLocales.length != 0 ) { // Check#4 Check to make sure at least 1 locale exists in workspace. This is required to create RE pages. for( int i = 0; i < resourceLocales.length; i++ ) { if( StringUtils.isEmpty( resourceLocales[ i ].getLocaleName() ) ) { if( rrcIFile != null && rrcIFile.exists() ) { super.init( site, rrhFileEditorInput ); return; } } else { IFile resourceFile = ImportUtils .getProjectBasedFileFromOSBasedFile( ( (RIMResourceLocale) resourceLocales[ i ] ) .getRrcFileAbsolutePath() ); if( resourceFile != null && resourceFile.getName().equals( ( ( (RIMResourceLocale) resourceLocales[ i ] ).getRrcFilename() ) ) ) { super.init( site, rrhFileEditorInput ); return; } } } MessageDialog.openError( site.getShell(), Messages.NO_LOCALE_ERROR_TITLE, Messages.NO_LOCALE_ERROR_TEXT ); } else { // Prompt user to create root locale. if( MessageDialog.openQuestion( site.getShell(), Messages.MISSING_LOCALE_ERROR_TITLE, Messages.MISSING_LOCALE_ERROR_TEXT ) ) { File rootRrcFile = getRRCFile( rrhFile ); try { if( rootRrcFile.createNewFile() ) { if( rrhIFile.isLinked() ) { IFile newRrcIFile = rrhIFile.getParent().getFile( new Path( rootRrcFile.getName() ) ); newRrcIFile.createLink( new Path( rootRrcFile.getAbsolutePath() ), IResource.NONE, new NullProgressMonitor() ); } else { rrhIFile.getProject().refreshLocal( IProject.DEPTH_INFINITE, new NullProgressMonitor() ); } // recreate the resource collection _resources = ResourceCollectionFactory.newResourceCollection( rrhFile.getAbsolutePath() ); super.init( site, rrhFileEditorInput ); return; } } catch( Exception e ) { _logger.error( "init: error creating new root rrc file", e ); //$NON-NLS-1$ } } } } else { // The .rrh file does not exist in the workspace, prompt to load .rrh file. messagePrompt = NLS.bind( Messages.MESSAGE_BOX_RESOURCE_HEADER_DOES_NOT_EXIST_IN_WORKSPACE, tempFilename, rrhFile.getAbsolutePath() ); if( MessageDialog.openQuestion( site.getShell(), Messages.MESSAGE_BOX_RESOURCE_HEADER_DOES_NOT_EXIST_IN_WORKSPACE_TITLE, messagePrompt ) ) { IFile fileOpened = fileEditorInput.getFile(); IFile newRrhIFile = fileOpened.getParent().getFile( new Path( rrhFile.getName() ) ); try { if( !newRrhIFile.exists() ) { newRrhIFile.createLink( new Path( rrhFile.getAbsolutePath() ), IResource.NONE, new NullProgressMonitor() ); } } catch( CoreException e ) { _logger.error( "init: error creating linking rrh file", e ); //$NON-NLS-1$ } // Check#2: Checks to see if the corresponding rrh file exists in the workspace. If // createResourceFileEditorInput does not return null, then the corresponding resource was found. We can // then call super and return. if( ( rrhFileEditorInput = createResourceFileEditorInput( rrhFile ) ) != null ) { super.init( site, rrhFileEditorInput ); return; } } else { // User selected to not load the .rrh file. Prompt to load .rrc file in text editor. messagePrompt = NLS.bind( Messages.MESSAGE_BOX_OPEN_TEXT_EDITOR_PROMPT, _resourceFilename ); if( MessageDialog.openQuestion( site.getShell(), Messages.MESSAGE_BOX_OPEN_TEXT_EDITOR_PROMPT_TITLE, messagePrompt ) ) { _resourceEditorListener.setOpenTextEditor( true ); } } } } else { // The corresponding .rrh file does not exist in the rrc directory. We cannot create a resourceCollection unless we // enforce this limitation. messagePrompt = NLS.bind( Messages.MESSAGE_BOX_RESOURCE_HEADER_DOES_NOT_EXIST_IN_DIRECTORY, new String[] { tempFilename, rrhFile.getParent(), _resourceFilename } ); MessageDialog.openError( site.getShell(), Messages.MESSAGE_BOX_RESOURCE_HEADER_DOES_NOT_EXIST_IN_DIRECTORY_TITLE, messagePrompt ); } // Dummy call to avoid Part Init exception caused by the site not getting set properly. super.init( site, input ); // Set flag to close editor when its opened. Eclipse requires the editor to open. _resourceEditorListener.setAllowOpen( false ); } public FileEditorInput createResourceFileEditorInput( File rrhFile ) throws PartInitException { // For SDR180459: We should get project based file for the local .rrh file that is represented by underlying OS file // system. IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); IFile rrhIFile = null; for( IProject project : projects ) { if( rrhIFile != null ) { break; } rrhIFile = ImportUtils.getProjectBasedFileFromOSBasedFile( project.getName(), rrhFile.getAbsolutePath() ); } if( rrhIFile != null ) { return new FileEditorInput( rrhIFile ); } else { return null; } } /** * This method will move the given rrhIFile and any of its corresponding locales (if they exist in the workspace) to the * passed in package. * * @param rrhIFile * - The resource header file being moved. * @param newPackage * - The package to move the resources to. */ private void moveResources( IFile rrhIFile, IPackageFragment newPackage ) { IPath oldRrhLocation = rrhIFile.getLocation(); RIMResourceLocale locales[] = (RIMResourceLocale[]) _resources.getLocales(); if( !rrhIFile.isLinked() ) { IPath newDestination = newPackage.getPath(); IContainer sourceFolder = rrhIFile.getParent(); // First we move the rrh file. Then we Check for links to the rrh file. If they exist, they must be recreated in the // proper package and pointing to the new location. IFile resourceFile = rrhIFile; IFile newIFile = moveCopiedFile( resourceFile, newDestination.append( resourceFile.getName() ) ); updateLinksLocationAndPackage( oldRrhLocation, newIFile.getLocation(), newPackage.getElementName() ); // Second we move all the locales (if they exist in the workspace). Then we check for any/all links to the locale // files. If they exist, they must be recreated in the proper package and pointing to the new location. for( RIMResourceLocale locale : locales ) { resourceFile = sourceFolder.getFile( new Path( locale.getRrcFilename() ) ); newIFile = moveCopiedFile( resourceFile, newDestination.append( resourceFile.getName() ) ); updateLinksLocationAndPackage( resourceFile.getLocation(), newIFile.getLocation(), newPackage.getElementName() ); } } else { // First update all links pointing to rrh file. updateLinksLocationAndPackage( oldRrhLocation, null, newPackage.getElementName() ); // Second update all links pointing to any locales from this resource collection that exist in the workspace. IPath resourceLocation = null; for( RIMResourceLocale locale : locales ) { resourceLocation = new Path( locale.getRrcFileAbsolutePath() ); updateLinksLocationAndPackage( resourceLocation, null, newPackage.getElementName() ); } } } private IFile moveCopiedFile( IFile resourceFile, IPath newDestination ) { if( resourceFile == null || !resourceFile.exists() || resourceFile.isLinked() ) { throw new IllegalArgumentException( "Error: resourceFile must exist and cannot be null or linked." ); //$NON-NLS-1$ } if( newDestination == null ) { throw new IllegalArgumentException( "Error: newDestination cannot be null." ); //$NON-NLS-1$ } try { resourceFile.move( newDestination, true, new NullProgressMonitor() ); } catch( CoreException e ) { _logger.error( "Error moving resource", e ); //$NON-NLS-1$ } IProject project = resourceFile.getProject(); IPath projectLocation = newDestination.removeFirstSegments( 1 ); IFile newIFile = project.getFile( projectLocation ); return newIFile; } /** * This method will find all links pointing to oldLinkLocation and will point them to the newLinkLocation. The method also * moves the links to a package specified by the passed in packageID. * * @param oldLinkLocation * - The location existing links will be pointing to. * @param newLinkLocation * - The location the new links will be pointing to, null if location doesn't change. * @param packageID * - The package to place the new links. */ private void updateLinksLocationAndPackage( IPath oldLinkLocation, IPath newLinkLocation, String packageID ) { if( newLinkLocation == null ) { // Link location will not change newLinkLocation = oldLinkLocation; } IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocation( oldLinkLocation ); for( IFile file : files ) { if( file.isLinked() ) { IJavaElement packageFolder = JavaCore.create( file.getParent() ); IPackageFragmentRoot sourceFolder = (IPackageFragmentRoot) packageFolder.getParent(); try { IPackageFragment newPackage = sourceFolder.createPackageFragment( packageID, true, new NullProgressMonitor() ); if( newPackage.exists() ) { IContainer parentFolder = ( (IFolder) newPackage.getResource() ); IFile newLocation = parentFolder.getFile( new Path( file.getName() ) ); newLocation.createLink( newLinkLocation, IResource.NONE, new NullProgressMonitor() ); file.delete( true, new NullProgressMonitor() ); } } catch( Exception e ) { _logger.error( "Error updating links", e ); //$NON-NLS-1$ } } } } public boolean isDirty() { if( _resources != null ) { return _resources.isDirty(); } return false; } public boolean isSaveAsAllowed() { return false; } public void setFocus() { getActiveResourceEditorPage().setFocus(); } /** * This function was added as a fix to SDR185428. */ public void dispose() { for( int i = this.getPageCount() - 1; i >= 0; i-- ) { removePage( i ); } } protected void createPages() { // If _resource is null then the .rrh file was not found or if the _allowOpen flag is set to false we must not allow this // editor to open. In these cases we create a dummy page with no content in order to satisfy the page requirements. We // then simply return. if( _resources == null || !_resourceEditorListener._allowOpen ) { addPage( new Composite( this.getContainer(), SWT.BORDER_SOLID ) ); setActivePage( 0 ); return; } // Fix for DPI221808. Only add pages for locales that exist in project ArrayList< ResourceLocale > localeList = new ArrayList< ResourceLocale >(); ResourceLocale[] resourceLocales = _resources.getLocales(); for( int i = 0; i < resourceLocales.length; i++ ) { // Special case for root locale file. The getProjectBasedFileFromOSBasedFile method can't find linked root locales. if( StringUtils.isEmpty( resourceLocales[ i ].getLocaleName() ) ) { File rrcFile = getRRCFile( rrhFile ); IFile rrcIFile = ImportUtils.getProjectBasedFileFromOSBasedFile( rrcFile.getAbsolutePath() ); if( rrcIFile != null && rrcIFile.exists() ) { localeList.add( resourceLocales[ i ] ); } } else { IFile resourceFile = ImportUtils.getProjectBasedFileFromOSBasedFile( ( (RIMResourceLocale) resourceLocales[ i ] ) .getRrcFileAbsolutePath() ); if( resourceFile != null && resourceFile.getName().equals( ( ( (RIMResourceLocale) resourceLocales[ i ] ).getRrcFilename() ) ) ) { localeList.add( resourceLocales[ i ] ); } } } ResourceLocale[] locales = localeList.toArray( new ResourceLocale[ localeList.size() ] ); _pages = new Vector< ResourceEditorPage >( locales.length ); // locale corresponding to .rrh/.rrc file that was opened from package explorer (i.e. "en", "fr") String currentLocaleName = ""; //$NON-NLS-1$ // open first page (i.e. tab for root locale) of ResourceEditor by default int setActivePageIndex = 0; for( int i = 0; i < locales.length; ++i ) { ResourceEditorPage page = new ResourceEditorPage( getContainer(), locales[ i ] ); int index = addPage( page.getControl() ); String localeName = locales[ i ].getLocaleName(); setPageText( index, localeName == ResourceConstants.ROOT_LOCALE ? ROOT : localeName ); page.createContextMenu( getSite() ); _pages.add( i, page ); if( _resourceFilename.endsWith( ResourceConstants.RRC_SUFFIX ) ) { currentLocaleName = _resourceFilename.substring( _resourceFilename.indexOf( "_" ) + 1, _resourceFilename //$NON-NLS-1$ .lastIndexOf( ResourceConstants.RRC_SUFFIX ) ); } else { currentLocaleName = _resourceFilename.substring( _resourceFilename.indexOf( "_" ) + 1, _resourceFilename //$NON-NLS-1$ .lastIndexOf( ResourceConstants.RRH_SUFFIX ) ); } if( currentLocaleName.equals( localeName ) ) { setActivePage( i ); // keep track of which locale tab to open in ResourceEditor setActivePageIndex = i; } else { setActivePage( 0 ); } } // flag used to determine if the resource collection is already open in an existing Resource Editor instance boolean resourceCollectionAlreadyOpen = false; try { if( _openEditorReferences.length > 1 ) { for( int i = 0; i < _openEditorReferences.length; i++ ) { if( _openEditorReferences[ i ].getEditor( false ) instanceof ResourceEditor ) { String existingEditorFilename = _openEditorReferences[ i ].getEditor( false ).getEditorInput().getName(); String thisEditorFilename = this.getEditorInput().getName(); String existingEditorPath = ( (FileEditorInput) ( _openEditorReferences[ i ].getEditor( true ) .getEditorInput() ) ).getFile().getParent().getLocation().toOSString(); String thisEditorPath = ( (FileEditorInput) ( this.getEditorInput() ) ).getFile().getParent() .getLocation().toOSString(); if( existingEditorFilename.endsWith( ResourceConstants.RRH_SUFFIX ) || existingEditorFilename.endsWith( ResourceConstants.RRC_SUFFIX ) ) { if( existingEditorFilename.contains( "_" ) ) { //$NON-NLS-1$ existingEditorFilename = existingEditorFilename.substring( 0, existingEditorFilename.indexOf( "_" ) ); //$NON-NLS-1$ } else { existingEditorFilename = existingEditorFilename.substring( 0, existingEditorFilename.indexOf( "." ) ); //$NON-NLS-1$ } if( thisEditorFilename.contains( "_" ) ) { //$NON-NLS-1$ thisEditorFilename = thisEditorFilename.substring( 0, thisEditorFilename.indexOf( "_" ) ); //$NON-NLS-1$ } else { thisEditorFilename = thisEditorFilename.substring( 0, thisEditorFilename.indexOf( "." ) ); //$NON-NLS-1$ } // existing editor on WorkbenchPage and this editor belong to the same ResourceCollection if( thisEditorFilename.equals( existingEditorFilename ) && existingEditorPath.equals( thisEditorPath ) ) { if( _callByResourceListener == false ) { // do not open duplicate editor for resources under the same ResourceCollection PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() .closeEditor( this, false ); } ( (ResourceEditor) _openEditorReferences[ i ].getEditor( true ) ) .setActivePage( setActivePageIndex ); // set focus to the editor containing resources for this PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() .activate( _openEditorReferences[ i ].getEditor( true ) ); resourceCollectionAlreadyOpen = true; } } } } } } catch( Exception e ) { } if( !resourceCollectionAlreadyOpen ) { // Update _resourceEditorPages<ResourceEditorPage> vector with newly opened resource files (used by // ResourceEditorOptionsDialog class for versioning highlighting) for( int i = 0; i < _pages.size(); i++ ) { for( int j = 0; j < _resourceEditorPages.size(); j++ ) { // remove old existing ResourceEditorPage objects if( _resourceEditorPages.get( j ).getRrcFile().getAbsolutePath() .equals( _pages.get( i ).getRrcFile().getAbsolutePath() ) ) { _resourceEditorPages.remove( j ); // System.out.println("removed: " + _pages.get(i).getRrcFile().getAbsolutePath()); } } _resourceEditorPages.add( _pages.get( i ) ); super.setActivePage( setActivePageIndex ); } // Activate Versioning Highlighting when resource file is opened in Resource Editor (if turned on) if( _pages.size() > 0 ) { String rrhPath = getRRCFile( _pages.get( 0 ).getRrcFile() ).getAbsolutePath(); // first page (index 0) is always root locale File rrhFile = new File( rrhPath ); String originalLocale = ResourceEditorOptionsDialog.getOriginalLocaleString( rrhFile ); if( originalLocale != null ) { ResourceEditorOptionsDialog.updateVersioningForResourceEditor( true, _resources.getLocale( "" ) ); //$NON-NLS-1$ } } _pages.get( setActivePageIndex ).setFocus(); } } protected void pageChange( int newPageIndex ) { updateTitle( newPageIndex ); super.pageChange( newPageIndex ); } private ResourceCollectionListener createCollectionListener() { return new ResourceCollectionListener() { public void commentChanged( String key ) { markDirty(); } public void keyAdded( ResourceElement element ) { if( localeExists( element.getLocale().getLocaleName() ) ) { getResourceEditorPage( element ).refresh(); } markDirty(); } public void keyChanged( ResourceElement element ) { if( localeExists( element.getLocale().getLocaleName() ) ) { getResourceEditorPage( element ).update( element, new String[] { ResourceEditorPage.KEY_COLUMN_ID } ); } markDirty(); } public void keyDeleted( ResourceElement element ) { if( localeExists( element.getLocale().getLocaleName() ) ) { getResourceEditorPage( element ).refresh(); } markDirty(); } public void valueChanged( ResourceElement element ) { getResourceEditorPage( element ).update( element, new String[] { ResourceEditorPage.VALUE_COLUMN_ID } ); markDirty(); } }; } private ResourceEditorPage getActiveResourceEditorPage() { return _pages.elementAt( getActivePage() ); } private boolean localeExists( String localeName ) { for( int i = 0; i < _pages.size(); ++i ) { String currentPageLocale = _pages.elementAt( i ).getLocale().getLocaleName(); if( currentPageLocale.equals( localeName ) ) { return true; } } return false; } private ResourceEditorPage getResourceEditorPage( ResourceElement element ) { String localeName = element.getLocale().getLocaleName(); if( localeName == ResourceConstants.ROOT_LOCALE ) { localeName = ROOT; } // TODO: make this a more efficient search for( int i = 0; i < _pages.size(); ++i ) { String pageName = getPageText( i ); if( pageName.equals( localeName ) ) { return _pages.elementAt( i ); } } throw new IllegalArgumentException(); } private void markDirty() { if( !_wasDirty && _resources.isDirty() ) { _wasDirty = true; firePropertyChange( IEditorPart.PROP_DIRTY ); } } private void updateTitle( int index ) { String editorFileName = _resourceFilename; if( editorFileName.contains( "_" ) ) { //$NON-NLS-1$ editorFileName = editorFileName.substring( 0, editorFileName.indexOf( "_" ) ); //$NON-NLS-1$ } else { editorFileName = editorFileName.substring( 0, editorFileName.indexOf( "." ) ); //$NON-NLS-1$ } setPartName( "Resource Editor - " + editorFileName + "-" + getPageText( index ) + " locale" ); } /** * Helper method returns vector of IFile objects to be checked out * * @return */ protected static Vector< IFile > getCheckoutFiles() { return _checkoutFiles; } /** * Helper method returns vector of all ResourceEditorPage objects belonging to all resource collections that were ever open in * the Resource Editor. (used for versioning highlighting) * * @return */ protected static Vector< ResourceEditorPage > getResourceEditorPages() { return _resourceEditorPages; } }