net.rim.ejde.internal.ui.editors.locale.ResourceEditorPage.java Source code

Java tutorial

Introduction

Here is the source code for net.rim.ejde.internal.ui.editors.locale.ResourceEditorPage.java

Source

/*
* 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.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import net.rim.ejde.internal.ui.consoles.ConsoleUtils;
import net.rim.ejde.internal.ui.consoles.PackagingConsole;
import net.rim.ejde.internal.ui.consoles.PackagingConsoleFactory;
import net.rim.ejde.internal.util.Messages;
import net.rim.ejde.internal.util.ProjectUtils;
import net.rim.sdk.resourceutil.RIMResourceElement;
import net.rim.sdk.resourceutil.RIMResourceLocale;
import net.rim.sdk.resourceutil.ResourceConstants;
import net.rim.sdk.resourceutil.ResourceElement;
import net.rim.sdk.resourceutil.ResourceLocale;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.console.MessageConsoleStream;

/**
 * A page used in the resource editor.
 *
 * @author jkeshavarzi
 *
 */
public class ResourceEditorPage {
    static final int KEY_COLUMN_INDEX = 0;
    static final int VALUE_COLUMN_INDEX = 1;
    static final String KEY_COLUMN_ID = "Key";
    static final String VALUE_COLUMN_ID = "Value";

    private static final int NUM_COLUMNS = 2;

    private ResourceCellEditorUIFactory _uiFactory;
    private Composite _composite;
    private IInputValidator _newKeyValidator;
    private TableViewer _viewer;

    private static ResourceContentProvider _contentProvider = new ResourceContentProvider();
    private static ResourceLabelProvider _labelProvider = new ResourceLabelProvider();
    private static String[] _columnProperties;
    private static Vector<Comparator<ResourceElement>> _comparators = new Vector<Comparator<ResourceElement>>(
            NUM_COLUMNS);

    // underlying .rrc file associated with then locale represented by this ResourceEditorPage (if applicable)
    private File _rrcFile = null;

    // ResourceLocale object associated with the locale represented by this ResourceEditorPage (if applicable)
    private ResourceLocale _locale;

    // stores reference to "Validate" button (used for translator mode in ResourceEditorOptionsDialog)
    private Button _validateButton = null;

    // stores reference to "Mark all correct" button (used for translator mode in ResourceEditorOptionsDialog)
    private Button _markAllCorrectButton = null;

    // used by "Validate" button
    private static Hashtable _resourceKeysInJavaFilesTable = new Hashtable();

    static {
        _columnProperties = new String[NUM_COLUMNS];
        _columnProperties[KEY_COLUMN_INDEX] = KEY_COLUMN_ID;
        _columnProperties[VALUE_COLUMN_INDEX] = VALUE_COLUMN_ID;

        _comparators.add(KEY_COLUMN_INDEX, new Comparator<ResourceElement>() {
            public int compare(ResourceElement e1, ResourceElement e2) {
                return e1.getKey().compareToIgnoreCase(e2.getKey());
            }
        });

        _comparators.add(VALUE_COLUMN_INDEX, new Comparator<ResourceElement>() {
            public int compare(ResourceElement e1, ResourceElement e2) {
                String value1 = e1.getValueAsString();
                String value2 = e2.getValueAsString();
                if (value1.length() == 0 && value2.length() != 0) {
                    return 1;
                }
                if (value1.length() != 0 && value2.length() == 0) {
                    return -1;
                }
                return value1.compareToIgnoreCase(value2);
            }
        });
    }

    public ResourceEditorPage(Composite container, ResourceLocale locale) {
        _composite = createComposite(container);
        Button addButton = createAddButton(locale);
        _viewer = createTableViewer(addButton, locale);
        _uiFactory = new ResourceCellEditorUIFactory(_viewer.getTable());
        _newKeyValidator = new ResourceKeyValidator(locale.getCollection(), false);

        if (locale instanceof RIMResourceLocale) {
            _rrcFile = new File(((RIMResourceLocale) locale).getRrcFileAbsolutePath());
        }
        _locale = locale;

        // Preserve Versioning Highlighting if user sorts resource key column in Resource Editor
        Table table = _viewer.getTable();
        TableColumn keyColumn = table.getColumn(KEY_COLUMN_INDEX);
        keyColumn.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                String originalLocaleString = ((RIMResourceLocale) _locale).getCollection().getOriginalLocaleName();
                ResourceEditorOptionsDialog.updateVersioningForTableViewer(null != originalLocaleString, _viewer,
                        _locale);
            }
        });

        // Preserve Versioning Highlighting if user sorts resource value column in Resource Editor
        TableColumn valueColumn = table.getColumn(VALUE_COLUMN_INDEX);
        valueColumn.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                String originalLocaleString = ((RIMResourceLocale) _locale).getCollection().getOriginalLocaleName();
                ResourceEditorOptionsDialog.updateVersioningForTableViewer(null != originalLocaleString, _viewer,
                        _locale);
            }
        });
    }

    void createContextMenu(IWorkbenchPartSite site) {
        MenuManager menuManager = new MenuManager("#PopupMenu");
        menuManager.setRemoveAllWhenShown(true);
        menuManager.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager m) {
                ResourceEditorPage.this.fillContextMenu(m);
            }
        });
        Table table = _viewer.getTable();
        Menu menu = menuManager.createContextMenu(table);
        table.setMenu(menu);
        // commented out to remove non essential default actions in context menu
        // site.registerContextMenu( menuManager, _viewer );
    }

    void fillContextMenu(IMenuManager menuManager) {
        IStructuredSelection selection = (IStructuredSelection) _viewer.getSelection();
        if (!selection.isEmpty()) {
            ResourceElement element = (ResourceElement) selection.getFirstElement();

            menuManager.add(new PropertiesAction(_uiFactory, element));
            menuManager.add(new Separator());

            menuManager.add(new ConvertToMultipleValuesAction(element, _composite.getShell()));
            menuManager.add(new ConvertToSingleValueAction(element, _composite.getShell()));
            menuManager.add(new Separator());

            menuManager.add(new DeleteValueAction(element, _composite.getShell()));
            menuManager.add(new Separator());

            menuManager.add(new DeleteValueFromAllAction(element, _composite.getShell()));
            menuManager.add(new Separator());

            menuManager.add(new MarkTranslationCorrectAction(element));
            menuManager.add(new MarkTranslationIncorrectAction(element));
            menuManager.add(new Separator());
        }
        menuManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
    }

    Control getControl() {
        return _composite;
    }

    TableViewer getTableViewer() {
        return _viewer;
    }

    void refresh() {
        _viewer.refresh();
    }

    void setFocus() {
        _viewer.getTable().setFocus();
    }

    void update(Object element, String[] properties) {
        _viewer.update(element, properties);
    }

    private Button createAddButton(final ResourceLocale locale) {
        FormData data = new FormData();
        data.left = new FormAttachment(0, 0);
        data.top = new FormAttachment(0, 0);

        Button addButton = new Button(_composite, SWT.PUSH | SWT.CENTER);
        addButton.setText(Messages.AddButton_text);
        addButton.setLayoutData(data);
        addButton.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                InputDialog dialog = new InputDialog(_composite.getShell(), Messages.AddButton_text,
                        Messages.InputDialog_message, null, _newKeyValidator);
                if (dialog.open() == Window.OK) {
                    // flag used to determine whether to proceed with adding resource key (i.e. if file is read-only, user will be
                    // prompted to set file writable prior to being able to add key)
                    boolean proceedToAddKey = false;
                    if (locale instanceof RIMResourceLocale) {
                        // .rrc file currently read-only
                        if (((RIMResourceLocale) locale).isRrcFileWritable() == false) {
                            if (MessageDialog.openQuestion(null, Messages.MessageDialog_title,
                                    ((RIMResourceLocale) locale).getRrcFilename()
                                            + " is read-only.\nDo you want to mark it read-write?")) {
                                // User decides to set file writable, proceed with adding key
                                ((RIMResourceLocale) locale).setRrcFileWritable();
                                ((RIMResourceLocale) locale).getCollection().setHeaderFileWritable();
                                proceedToAddKey = true;
                            } else {
                                // User decides not to set file writable, Add Key action aborted
                                MessageDialog.openInformation(null, Messages.MessageDialog_title,
                                        "You will not be able to save changes to "
                                                + ((RIMResourceLocale) locale).getRrcFilename() + ".");
                                proceedToAddKey = false;
                            }
                        } else {
                            // File already writable, proceed with adding key
                            proceedToAddKey = true;
                        }
                    } else {
                        // locale is not an instance of RIMResourceLocale (used for .res files later on)
                        proceedToAddKey = true;
                    }

                    if (proceedToAddKey) {
                        // Fix for DPI221924
                        String userInput = dialog.getValue().trim();
                        if (!userInput.matches("[\\w]+")) {
                            MessageDialog.openError(null, Messages.MessageDialog_title,
                                    Messages.MessageDialog_ResourceNameEmpty);
                            return;
                        }

                        locale.getCollection().addKey(userInput);

                        // Refresh Versioning Highlighting after adding key
                        if (locale instanceof RIMResourceLocale) {
                            String originalLocaleString = ((RIMResourceLocale) locale).getCollection()
                                    .getOriginalLocaleName();
                            ResourceEditorOptionsDialog
                                    .updateVersioningForResourceEditor(null != originalLocaleString, locale);
                        }
                    }
                }
            }
        });

        /**
         * Options Button (activates Resource Editor Options Dialog)
         */
        data = new FormData();
        data.left = new FormAttachment(addButton);
        data.top = new FormAttachment(0, 0);
        Button optionsButton = new Button(_composite, SWT.PUSH | SWT.CENTER);
        optionsButton.setText("Options");
        optionsButton.setLayoutData(data);
        optionsButton.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {
                if (locale instanceof RIMResourceLocale) {
                    ResourceEditorOptionsDialog optionsDialog = new ResourceEditorOptionsDialog(
                            (RIMResourceLocale) locale);
                    optionsDialog.open();
                }
            }
        });

        /**
         * Validate button
         */
        data = new FormData();
        data.left = new FormAttachment(optionsButton);
        data.top = new FormAttachment(0, 0);
        Button validateButton = new Button(_composite, SWT.PUSH | SWT.CENTER);
        validateButton.setLayoutData(data);
        validateButton.setText("Validate");
        validateButton.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {
                if (locale instanceof RIMResourceLocale) {
                    boolean proceed = MessageDialog.openQuestion(null, "Resource Editor",
                            "This will search for uses of these keys in java files.\nThis may take a few minutes.\nAre you sure?");
                    if (!proceed) {
                        return;
                    }

                    // index of project that this ResourceEditorPage belongs to
                    int indexOfCurrentProject = -1;
                    Vector<File> javaFiles = new Vector<File>(0); // vector
                    // of .java files in project
                    Vector<String> keysFound = new Vector<String>(0); // vector
                    // of Strings used to determine which resource keys were found in .java files for project
                    keysFound.clear();

                    // Check if strict mode is enabled (i.e. Match resource bundle when validating resources (strict) has been
                    // activated)
                    boolean isStrictMode = ResourceEditorOptionsDialog.getStrictMode();

                    // Populate javaFiles vector with .java files of current project traversed in for loop
                    IProject projects[] = ResourcesPlugin.getWorkspace().getRoot().getProjects();
                    for (int i = 0; i < projects.length && -1 == indexOfCurrentProject; i++) {
                        javaFiles.clear();
                        IFile files[] = ProjectUtils.getProjectFiles(projects[i]);
                        for (IFile file : files) {
                            File currentFile = file.getLocation().toFile();
                            String filePath = currentFile.getAbsolutePath();

                            if (filePath.equals(getRrcFile().getAbsolutePath())) {
                                // currently traversed project corresponds to the project that this ResourceEditorPage belongs to
                                indexOfCurrentProject = i;
                            }
                            if (filePath.endsWith(".java")) {
                                javaFiles.add(currentFile);
                            }
                        }
                    }

                    // Traverse javaFiles vector and search for resource keys in
                    // .java files
                    RIMResourceElement[] elements = ((RIMResourceLocale) locale).getResourceElements();

                    for (int i = 0; i < javaFiles.size(); i++) {
                        String currentJavaFilePath = javaFiles.get(i).getAbsolutePath();

                        if (!_resourceKeysInJavaFilesTable.containsKey(currentJavaFilePath)) {
                            // current .java file has not been searched before for instances of resource keys, so we need to
                            // search the file System.out.println("=====" + currentJavaFilePath + " was NEVER searched before.");
                            keysFound = searchAndRetrieveKeysFound(elements, javaFiles.get(i), keysFound);
                        } else {
                            // current .java file has been searched before for instances of resource keys
                            // System.out.println("=====" + currentJavaFilePath + " WAS searched before");

                            boolean searchCurrentJavaFile = true; // flag
                            // determines whether we will need to search currently traversed .java file
                            long currentJavaFileLastModified = javaFiles.get(i).lastModified();

                            if (_resourceKeysInJavaFilesTable.get(currentJavaFilePath).getClass().toString()
                                    .endsWith("Long")) {
                                // current .java file did not contain any resource keys in previous search

                                if (!isStrictMode) {
                                    searchCurrentJavaFile = true;
                                    // Handles case where if no resource keys (in strict mode) are found, there may still be
                                    // resource keys (w/o strict mode) present
                                } else {
                                    Long searchedJavaFileLastModified = (Long) _resourceKeysInJavaFilesTable
                                            .get(currentJavaFilePath);
                                    if (currentJavaFileLastModified == searchedJavaFileLastModified.longValue()) {
                                        searchCurrentJavaFile = false;
                                    }
                                }
                            } else {
                                Hashtable resourceKeysAndTimestampsTable = (Hashtable) _resourceKeysInJavaFilesTable
                                        .get(currentJavaFilePath);
                                // Check if current .java file has been modified since last search of resource keys

                                for (int j = 0; j < elements.length; j++) {
                                    String resourceKey = "";
                                    if (isStrictMode) {
                                        resourceKey = getResourceBundleName() + "Resource." + elements[j].getKey();
                                    } else {
                                        resourceKey = elements[j].getKey();
                                    }

                                    if (resourceKeysAndTimestampsTable.containsKey(resourceKey)) {
                                        Long keyLastModified = (Long) resourceKeysAndTimestampsTable
                                                .get(resourceKey);

                                        if (keyLastModified.longValue() == currentJavaFileLastModified) {
                                            searchCurrentJavaFile = false;
                                            if (!keysFound.contains(elements[j].getKey())) { // avoid
                                                // adding duplicate keys in keysFound vector
                                                keysFound.add(elements[j].getKey());
                                            }
                                        }
                                    }
                                }
                            }
                            // System.out.println( "===== Do we need to search .java file? -> " + searchCurrentJavaFile );

                            if (searchCurrentJavaFile) {
                                // current .java file was modified since last search for resource keys, so search it again
                                keysFound = searchAndRetrieveKeysFound(elements, javaFiles.get(i), keysFound);
                            }
                        }
                    }

                    // Output to console which keys were not found
                    // Fix for DPI221973
                    PackagingConsoleFactory consoleFactory = new PackagingConsoleFactory();
                    PackagingConsole rapcConsole = consoleFactory.getConsole();
                    MessageConsoleStream out = rapcConsole.newMessageStream();

                    ConsoleUtils.openConsole(rapcConsole);
                    consoleFactory.showConsole();

                    String resourceBundleName = getResourceBundleName();

                    if (elements.length == keysFound.size()) {
                        out.println("All resources in " + resourceBundleName + " are in use.");
                    } else {
                        out.println("Strings not found from " + resourceBundleName + ":");
                        for (int i = 0; i < elements.length; i++) {
                            if (!keysFound.contains(elements[i].getKey())) {
                                if (isStrictMode) {
                                    out.println(resourceBundleName + "Resource." + elements[i].getKey());
                                } else {
                                    out.println(elements[i].getKey());
                                }
                            }
                        }
                    }
                    out.println("");
                }
            }
        });
        _validateButton = validateButton;

        /**
         * Mark all correct button
         */
        data = new FormData();
        data.left = new FormAttachment(optionsButton);
        data.top = new FormAttachment(0, 0);
        Button markAllCorrectButton = new Button(_composite, SWT.PUSH | SWT.CENTER);
        markAllCorrectButton.setLayoutData(data);
        markAllCorrectButton.setText("Mark all correct");
        markAllCorrectButton.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {
                if (locale instanceof RIMResourceLocale) {

                    boolean proceed = MessageDialog.openQuestion(null, "Resource Editor",
                            "This will mark all lines as being translated.\nAre you sure?");
                    if (proceed) {
                        String originalLocaleString = ((RIMResourceLocale) locale).getCollection()
                                .getOriginalLocaleName();

                        if (((RIMResourceLocale) locale).getLocaleName().equals("")
                                && ResourceEditorOptionsDialog.ROOT.equals(originalLocaleString)) {
                            // Case #1: Do nothing if user selected locale and original locale are both root (root is a special
                            // case)
                        } else if (((RIMResourceLocale) locale).getLocaleName().equals(originalLocaleString)) {
                            // Case #2: Do nothing if user selected locale is the original locale but both are non-root similar to
                            // Case #1
                        } else if (null != originalLocaleString) {
                            ResourceEditorOptionsDialog.generateOriginalLocaleHashtable(locale);
                            for (Enumeration e = ResourceEditorOptionsDialog.getOriginalLocaleHashtable().keys(); e
                                    .hasMoreElements();) {
                                String resourceKey = e.nextElement().toString();
                                RIMResourceElement currentElement = ((RIMResourceLocale) locale)
                                        .getResourceElement(resourceKey);
                                String checksumHexValue = ResourceEditorOptionsDialog.getOriginalLocaleHashtable()
                                        .get(resourceKey).toString();

                                if (checksumHexValue.startsWith(ResourceEditorOptionsDialog.HEX_PREFIX)) {
                                    checksumHexValue = checksumHexValue.substring(2); // remove
                                    // "0x" hex prefix
                                }
                                long checksumLongValue = Long.parseLong(checksumHexValue.trim(), 16);
                                currentElement.setHash(checksumLongValue);
                                ResourceEditorOptionsDialog.updateVersioningForResourceElementOnly(false,
                                        currentElement);
                            }
                        }
                    }
                }
            }
        });
        _markAllCorrectButton = markAllCorrectButton;

        // Decide whether to show the Validate button or Mark all correct button (depending on whether "Set in translator mode"
        // has been activated from the Resource Editor options dialog
        if (ResourceEditorOptionsDialog.getTranslatorMode()) {
            markAllCorrectButton.setVisible(true);
            validateButton.setVisible(false);
        } else {
            validateButton.setVisible(true);
            markAllCorrectButton.setVisible(false);
        }

        return addButton;

        /*
         * data = new FormData(); data.left = new FormAttachment( _addButton ); data.top = new FormAttachment( 0, 0 ); Button
         * deleteButton = new Button( _composite, SWT.PUSH | SWT.CENTER ); deleteButton.setText( "Delete Key(s)" );
         * deleteButton.setLayoutData( data );
         */
    }

    private static Composite createComposite(Composite container) {
        FormLayout layout = new FormLayout();
        layout.marginHeight = 5;
        layout.marginWidth = 5;
        layout.spacing = 5;

        Composite composite = new Composite(container, SWT.NONE);
        composite.setLayout(layout);

        return composite;
    }

    private Table createTable(Control topAttachControl) {
        FormData data = new FormData();
        data.bottom = new FormAttachment(100, 0);
        data.left = new FormAttachment(0, 0);
        data.right = new FormAttachment(100, 0);
        data.top = new FormAttachment(topAttachControl);

        final Table table = new Table(_composite,
                SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION | SWT.HIDE_SELECTION);
        table.setHeaderVisible(true);
        table.setLinesVisible(true);
        table.setLayout(new TableLayout());
        table.setLayoutData(data);

        table.addMouseListener(new MouseAdapter() {
            public void mouseDoubleClick(MouseEvent e) {
                Point selectionPoint = new Point(e.x, e.y);
                int columnIndex = getColumnIndex(selectionPoint.x);
                TableItem item = table.getItem(selectionPoint);

                if (columnIndex != -1 && item != null) {
                    ResourceElement element = (ResourceElement) item.getData();
                    if (element instanceof RIMResourceElement) {
                        RIMResourceLocale locale = (RIMResourceLocale) element.getLocale();
                        if (locale.isRrcFileWritable() == false) {
                            if (MessageDialog.openQuestion(null, "Resource Editor", locale.getRrcFilename()
                                    + " is read-only.\nDo you want to mark it read-write?")) {
                                locale.setRrcFileWritable();
                                locale.getCollection().setHeaderFileWritable();
                                _uiFactory.createCellEditorUI(element, columnIndex).display();
                            } else {
                                MessageDialog.openInformation(null, "Resource Editor",
                                        "You will not be able to save changes to " + locale.getRrcFilename() + ".");
                                return;
                            }
                        } else {
                            _uiFactory.createCellEditorUI(element, columnIndex).display();
                        }
                    } else {
                        _uiFactory.createCellEditorUI(element, columnIndex).display();
                    }
                }
            }

            public void mouseDown(MouseEvent e) {
                Point selectionPoint = new Point(e.x, e.y);
                int columnIndex = getColumnIndex(selectionPoint.x);
                TableItem item = table.getItem(selectionPoint);
                if (columnIndex == -1 || item == null) {
                    table.deselectAll();
                }
            }
        });

        FontData unicodeFontData = new FontData("Arial Unicode MS", 12, SWT.NORMAL);
        Font unicodeFont = new Font(table.getDisplay(), unicodeFontData);
        table.setFont(unicodeFont);

        TableColumn keyColumn = new TableColumn(table, SWT.NONE);
        keyColumn.setText("Keys");
        ((TableLayout) table.getLayout()).addColumnData(new ColumnWeightData(50));

        TableColumn valueColumn = new TableColumn(table, SWT.NONE);
        valueColumn.setText("Values");
        ((TableLayout) table.getLayout()).addColumnData(new ColumnWeightData(50));

        return table;
    }

    private TableViewer createTableViewer(Control topAttachControl, ResourceLocale locale) {
        Table table = createTable(topAttachControl);
        TableViewer viewer = new TableViewer(table);
        viewer.setColumnProperties(_columnProperties);
        viewer.setContentProvider(_contentProvider);
        viewer.setLabelProvider(_labelProvider);
        viewer.setSorter(new ResourceSorter(viewer, _comparators));
        viewer.setInput(locale);

        return viewer;
    }

    private int getColumnIndex(int x) {
        int gridLineWidth = _viewer.getTable().getGridLineWidth();
        TableColumn[] columns = _viewer.getTable().getColumns();
        for (int i = 0; i < columns.length; ++i) {
            if (x < columns[i].getWidth() + gridLineWidth) {
                return i;
            }
            x -= columns[i].getWidth() + gridLineWidth;
        }
        return -1;
    }

    /**
     * Returns underlying .rrc file associated with locale represented by this ResourceEditorPage. Returns null if not applicable.
     *
     * @return
     */
    protected File getRrcFile() {
        return _rrcFile;
    }

    /**
     * Helper method used to show/hide "Validate" and "Mark all correct" buttons according to whether "Set in translator mode" in
     * the Resource Editor options dialog has been activated.
     */
    protected void updateModeForValidateButton() {
        if (ResourceEditorOptionsDialog.getTranslatorMode()) {
            // "Set in translator mode" in Resource Editor options dialog has been activated, so hide "Validate" button and show
            // "Mark all correct" button
            _markAllCorrectButton.setVisible(true);
            _validateButton.setVisible(false);
        } else {
            _validateButton.setVisible(true);
            _markAllCorrectButton.setVisible(false);
        }
    }

    /**
     * Returns ResourceLocale object associated with locale represented by this ResourceEditorPage
     *
     * @return
     */
    protected ResourceLocale getLocale() {
        return _locale;
    }

    /**
     * Searches for resource keys from elements in .java file represented by javaFile. Returns a vector of Strings representing
     * resource keys that were found in the .java file.
     *
     * @param elements
     *            RIMResourceElements whose keys are to be searched for in javaFile
     * @param javaFile
     *            .java file to search in
     * @param keysFound
     *            Vector of key strings that have been found in other .java files so far
     * @return
     */
    private Vector<String> searchAndRetrieveKeysFound(RIMResourceElement[] elements, File javaFile,
            Vector<String> keysFound) {
        // Check if strict mode is enabled (i.e. Match resource bundle when validating resources (strict) has been activated)
        boolean isStrictMode = ResourceEditorOptionsDialog.getStrictMode();

        Hashtable resourceKeysAndTimestampsTable = new Hashtable();
        try {
            resourceKeysAndTimestampsTable.clear();
            BufferedReader bufferedReader = new BufferedReader(new FileReader(javaFile));
            String currentLine = bufferedReader.readLine();
            String resourceBundleName = getResourceBundleName();

            while (currentLine != null) {
                if (currentLine.contains("//")) {
                    currentLine = currentLine.substring(0, currentLine.indexOf("//"));
                    // ignore everything after single-line // comments
                }

                if (currentLine.contains("/*")) {
                    currentLine = currentLine.substring(0, currentLine.indexOf("/*"));
                    // ignore everything after muli-line /* comments
                }

                for (int j = 0; j < elements.length; j++) {
                    String resourceKey = elements[j].getKey();
                    String resourceKeyInStrictMode = resourceBundleName + "Resource." + resourceKey;
                    if (currentLine.contains(resourceKey)) {
                        boolean resourceKeyFound = false;
                        if (isStrictMode) {
                            if (currentLine.contains(resourceKeyInStrictMode)) {
                                resourceKeyFound = true; // resource key found in current line
                            } else {
                                resourceKeyFound = false;
                            }
                        } else {
                            resourceKeyFound = true;
                        }

                        if (resourceKeyFound) {
                            if (!keysFound.contains(resourceKey)) { // avoid adding duplicate keys in keysFound vector
                                keysFound.add(resourceKey);
                            }

                            if (resourceKeysAndTimestampsTable.containsKey(resourceKey)) {
                                resourceKeysAndTimestampsTable.remove(resourceKey); // avoid duplicate keys in hash table
                            }

                            if (isStrictMode) {
                                resourceKeysAndTimestampsTable.put(resourceKeyInStrictMode,
                                        new Long(javaFile.lastModified()));
                            } else {
                                resourceKeysAndTimestampsTable.put(resourceKey, new Long(javaFile.lastModified()));
                            }
                        }
                    }
                }
                currentLine = bufferedReader.readLine();
            }
            bufferedReader.close();
        } catch (Exception e) {
        }

        if (_resourceKeysInJavaFilesTable.containsKey(javaFile.getAbsolutePath())) {
            _resourceKeysInJavaFilesTable.remove(javaFile.getAbsolutePath()); // avoid duplicate keys in hash table
        }

        if (0 == resourceKeysAndTimestampsTable.size()) {
            // no resource keys found in javaFile, hence save last modified timestamp of javaFile
            _resourceKeysInJavaFilesTable.put(javaFile.getAbsolutePath(), Long.valueOf(javaFile.lastModified()));
        } else {
            _resourceKeysInJavaFilesTable.put(javaFile.getAbsolutePath(), resourceKeysAndTimestampsTable);
        }
        return keysFound;
    }

    /**
     * Helper method returns resource bundle name to which this ResourceEditorPage belongs to. (e.g. if this ResourceEditorPage
     * represents contents of HelloWorld_en.rrc, this method will return "HelloWorld"). Used by the Validate button.
     *
     * @return
     */
    private String getResourceBundleName() {
        String resourceBundleName = getRrcFile().getName();
        if (resourceBundleName.contains("_")) {
            resourceBundleName = resourceBundleName.substring(0, resourceBundleName.indexOf("_"));
        } else {
            resourceBundleName = resourceBundleName.substring(0,
                    resourceBundleName.lastIndexOf(ResourceConstants.RRC_SUFFIX));
        }
        return resourceBundleName;
    }

}