com.nokia.cdt.internal.debug.launch.ui.FilesBlock.java Source code

Java tutorial

Introduction

Here is the source code for com.nokia.cdt.internal.debug.launch.ui.FilesBlock.java

Source

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/
package com.nokia.cdt.internal.debug.launch.ui;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;

import com.nokia.cdt.internal.debug.launch.LaunchPlugin;
import com.nokia.cpp.internal.api.utils.core.Pair;

/**
 * A composite that displays files in a table. Files can be 
 * added, removed, and edited..
 */
public class FilesBlock {

    FileTransferTab fLaunchTab;
    /**
     * This block's control
     */
    private Composite fControl;

    /**
     * Files being displayed
     */
    private List<FileToTransfer> fFiles = new ArrayList<FileToTransfer>();

    /**
     * The main list control
     */
    private CheckboxTableViewer fFileList;

    // Action buttons
    private Button fAddButton;
    private Button fRemoveButton;
    private Button fEditButton;
    private Button fSelectAllButton;
    private Button fDeSelectAllButton;

    // column weights
    private float fWeight1 = .1F;
    private float fWeight2 = .45F;

    // ignore column re-sizing when the table is being resized
    private boolean fResizingTable = false;

    // index of column used for sorting
    private int fSortColumn = 1;

    // cache of file info: we expect this to remain relatively static while
    // any UI using FilesBlock is up.
    private static Map<File, Pair<Long, Boolean>> fFileInfoCache = new LinkedHashMap<File, Pair<Long, Boolean>>();
    private static long fFileInfoCacheFlushTime = 0;
    private static final int CACHE_CHECK_QUANTUM = 60 * 1000;

    /** 
     * Content provider to show a list of files to be transferred
     */
    class FilesContentProvider implements IStructuredContentProvider {

        public Object[] getElements(Object input) {
            return fFiles.toArray();
        }

        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
        }

        public void dispose() {
        }

    }

    /**
     * Label provider for files to transfer table.
     */
    class FilesLabelProvider extends LabelProvider implements ITableLabelProvider {

        /**
         * @see ITableLabelProvider#getColumnText(Object, int)
         */
        public String getColumnText(Object element, int columnIndex) {
            if (element instanceof FileToTransfer) {
                FileToTransfer file = (FileToTransfer) element;
                switch (columnIndex) {
                case 0:
                    return ""; //$NON-NLS-1$
                case 1:
                    return file.getHostPath();
                case 2:
                    return file.getTargetPath();
                }
            }
            return element.toString();
        }

        /**
         * @see ITableLabelProvider#getColumnImage(Object, int)
         */
        public Image getColumnImage(Object element, int columnIndex) {
            if (columnIndex == 1 && element instanceof FileToTransfer) {
                // add warning icon for any host files that don't exist
                FileToTransfer file = (FileToTransfer) element;
                File hostFile = new Path(file.getHostPath()).toFile();
                if (!fileExists(hostFile)) {
                    return LaunchPlugin.getImageDescriptor("icons/warning_obj.gif").createImage();
                }
            }
            return null;
        }

    }

    FilesBlock(FileTransferTab launchTab) {
        fLaunchTab = launchTab;
        fFileInfoCacheFlushTime = System.currentTimeMillis();
    }

    /**
     * Creates this block's control in the given control.
     * 
     * @param ancestor containing control
     */
    public void createControl(Composite ancestor) {

        Composite parent = new Composite(ancestor, SWT.NULL);
        GridLayout layout = new GridLayout();
        layout.numColumns = 2;
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        parent.setLayout(layout);
        Font font = ancestor.getFont();
        parent.setFont(font);
        fControl = parent;

        GridData data;

        Table table = new Table(parent, SWT.CHECK | SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
        data = new GridData(GridData.FILL_BOTH);
        table.setLayoutData(data);
        table.setFont(font);

        table.setHeaderVisible(true);
        table.setLinesVisible(true);

        TableLayout tableLayout = new TableLayout();
        table.setLayout(tableLayout);

        TableColumn column1 = new TableColumn(table, SWT.NULL);
        column1.setText(Messages.getString("FileTransferTab.2")); //$NON-NLS-1$
        column1.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                sortByEnabled();
            }
        });

        TableColumn column2 = new TableColumn(table, SWT.NULL);
        column2.setText(Messages.getString("FileTransferTab.3")); //$NON-NLS-1$
        column2.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                sortByHostPath();
            }
        });

        TableColumn column3 = new TableColumn(table, SWT.NULL);
        column3.setText(Messages.getString("FileTransferTab.4")); //$NON-NLS-1$
        column3.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                sortByTargetPath();
            }
        });

        fFileList = new CheckboxTableViewer(table);
        fFileList.setLabelProvider(new FilesLabelProvider());
        fFileList.setContentProvider(new FilesContentProvider());

        fFileList.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent evt) {
                enableButtons();
            }
        });

        fFileList.addDoubleClickListener(new IDoubleClickListener() {
            public void doubleClick(DoubleClickEvent e) {
                if (!fFileList.getSelection().isEmpty()) {
                    editFile();
                }
            }
        });

        fFileList.addCheckStateListener(new ICheckStateListener() {
            public void checkStateChanged(CheckStateChangedEvent e) {
                FileToTransfer file = (FileToTransfer) e.getElement();
                file.setEnabled(e.getChecked());
                fLaunchTab.dataChanged();
            }
        });

        table.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent event) {
                if (event.character == SWT.DEL && event.stateMask == 0) {
                    removeFiles();
                }
            }
        });

        Composite buttons = new Composite(parent, SWT.NULL);
        buttons.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
        layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        buttons.setLayout(layout);
        buttons.setFont(font);

        fAddButton = createPushButton(buttons, Messages.getString("FileTransferTab.5")); //$NON-NLS-1$
        fAddButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event evt) {
                addFile();
            }
        });

        fEditButton = createPushButton(buttons, Messages.getString("FileTransferTab.6")); //$NON-NLS-1$
        fEditButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event evt) {
                editFile();
            }
        });

        fRemoveButton = createPushButton(buttons, Messages.getString("FileTransferTab.7")); //$NON-NLS-1$
        fRemoveButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event evt) {
                removeFiles();
            }
        });

        fSelectAllButton = createPushButton(buttons, Messages.getString("FileTransferTab.10")); //$NON-NLS-1$
        fSelectAllButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event evt) {
                for (int i = 0; i < fFiles.size(); i++) {
                    FileToTransfer file = (FileToTransfer) fFiles.get(i);
                    file.setEnabled(true);
                    fFileList.setChecked(file, true);
                }
                fLaunchTab.dataChanged();
            }
        });

        fDeSelectAllButton = createPushButton(buttons, Messages.getString("FileTransferTab.11")); //$NON-NLS-1$
        fDeSelectAllButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event evt) {
                for (int i = 0; i < fFiles.size(); i++) {
                    FileToTransfer file = (FileToTransfer) fFiles.get(i);
                    file.setEnabled(false);
                    fFileList.setChecked(file, false);
                }
                fLaunchTab.dataChanged();
            }
        });

        configureTableResizing(parent, buttons, table, column1, column2, column3);

        enableButtons();
        fAddButton.setEnabled(true);
    }

    /**
     * Sorts by enabled.
     */
    private void sortByEnabled() {
        fFileList.setSorter(new ViewerSorter() {
            public int compare(Viewer viewer, Object e1, Object e2) {
                if ((e1 instanceof FileToTransfer) && (e2 instanceof FileToTransfer)) {
                    FileToTransfer left = (FileToTransfer) e1;
                    FileToTransfer right = (FileToTransfer) e2;
                    if (left.getEnabled() == right.getEnabled()) {
                        return 0;
                    } else if (left.getEnabled()) {
                        return 1;
                    } else
                        return -1;
                }
                return super.compare(viewer, e1, e2);
            }

            public boolean isSorterProperty(Object element, String property) {
                return true;
            }
        });
        fSortColumn = 1;
    }

    /**
     * Sorts by host path.
     */
    private void sortByHostPath() {
        fFileList.setSorter(new ViewerSorter() {
            public int compare(Viewer viewer, Object e1, Object e2) {
                if ((e1 instanceof FileToTransfer) && (e2 instanceof FileToTransfer)) {
                    FileToTransfer left = (FileToTransfer) e1;
                    FileToTransfer right = (FileToTransfer) e2;
                    return left.getHostPath().compareToIgnoreCase(right.getHostPath());
                }
                return super.compare(viewer, e1, e2);
            }

            public boolean isSorterProperty(Object element, String property) {
                return true;
            }
        });
        fSortColumn = 3;
    }

    /**
     * Sorts by target path.
     */
    private void sortByTargetPath() {
        fFileList.setSorter(new ViewerSorter() {
            public int compare(Viewer viewer, Object e1, Object e2) {
                if ((e1 instanceof FileToTransfer) && (e2 instanceof FileToTransfer)) {
                    FileToTransfer left = (FileToTransfer) e1;
                    FileToTransfer right = (FileToTransfer) e2;
                    return left.getTargetPath().compareToIgnoreCase(right.getTargetPath());
                }
                return super.compare(viewer, e1, e2);
            }

            public boolean isSorterProperty(Object element, String property) {
                return true;
            }
        });
        fSortColumn = 2;
    }

    private void enableButtons() {
        int selectionCount = ((IStructuredSelection) fFileList.getSelection()).size();
        fEditButton.setEnabled(selectionCount == 1);
        fRemoveButton.setEnabled(selectionCount > 0);
    }

    protected Button createPushButton(Composite parent, String label) {
        Button button = new Button(parent, SWT.PUSH);
        button.setFont(parent.getFont());
        if (label != null) {
            button.setText(label);
        }
        GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
        button.setLayoutData(gd);
        return button;
    }

    /**
     * Correctly resizes the table so no phantom columns appear
     */
    protected void configureTableResizing(final Composite parent, final Composite buttons, final Table table,
            final TableColumn column1, final TableColumn column2, final TableColumn column3) {
        parent.addControlListener(new ControlAdapter() {
            public void controlResized(ControlEvent e) {
                resizeTable(parent, buttons, table, column1, column2, column3);
            }
        });
        table.addListener(SWT.Paint, new Listener() {
            public void handleEvent(Event event) {
                table.removeListener(SWT.Paint, this);
                resizeTable(parent, buttons, table, column1, column2, column3);
            }
        });
        column1.addControlListener(new ControlAdapter() {
            public void controlResized(ControlEvent e) {
                if (column1.getWidth() > 0 && !fResizingTable) {
                    fWeight1 = getColumnWeight(0);
                }
            }
        });
        column2.addControlListener(new ControlAdapter() {
            public void controlResized(ControlEvent e) {
                if (column2.getWidth() > 0 && !fResizingTable) {
                    fWeight2 = getColumnWeight(1);
                }
            }
        });
    }

    private void resizeTable(Composite parent, Composite buttons, Table table, TableColumn column1,
            TableColumn column2, TableColumn column3) {
        fResizingTable = true;
        int parentWidth = -1;
        int parentHeight = -1;
        if (parent.isVisible()) {
            Rectangle area = parent.getClientArea();
            parentWidth = area.width;
            parentHeight = area.height;
        } else {
            Point parentSize = parent.computeSize(SWT.DEFAULT, SWT.DEFAULT);
            parentWidth = parentSize.x;
            parentHeight = parentSize.y;
        }
        Point preferredSize = table.computeSize(SWT.DEFAULT, SWT.DEFAULT);
        int width = parentWidth - 2 * table.getBorderWidth();
        if (preferredSize.y > parentHeight) {
            // Subtract the scrollbar width from the total column width
            // if a vertical scrollbar will be required
            Point vBarSize = table.getVerticalBar().getSize();
            width -= vBarSize.x;
        }
        width -= buttons.getSize().x;
        Point oldSize = table.getSize();
        if (oldSize.x > width) {
            // table is getting smaller so make the columns
            // smaller first and then resize the table to
            // match the client area width
            column1.setWidth(Math.round(width * fWeight1));
            column2.setWidth(Math.round(width * fWeight2));
            column3.setWidth(width - (column1.getWidth() + column2.getWidth()));
            table.setSize(width, parentHeight);
        } else {
            // table is getting bigger so make the table
            // bigger first and then make the columns wider
            // to match the client area width
            table.setSize(width, parentHeight);
            column1.setWidth(Math.round(width * fWeight1));
            column2.setWidth(Math.round(width * fWeight2));
            column3.setWidth(width - (column1.getWidth() + column2.getWidth()));
        }
        fResizingTable = false;
    }

    /**
     * Returns this block's control
     * 
     * @return control
     */
    public Control getControl() {
        return fControl;
    }

    /**
     * Sets the files to be displayed in this block
     * 
     * @param files files to be displayed
     */
    protected void setFiles(List<FileToTransfer> files) {
        fFiles.clear();
        for (int i = 0; i < files.size(); i++) {
            FileToTransfer file = (FileToTransfer) files.get(i);
            fFiles.add(file);
        }
        fFileList.setInput(fFiles);
        fFileList.refresh();

        for (int i = 0; i < fFiles.size(); i++) {
            FileToTransfer file = (FileToTransfer) fFiles.get(i);
            fFileList.setChecked(file, file.getEnabled());
        }
    }

    /**
     * Returns the files currently being displayed in this block
     * 
     * @return files currently being displayed in this block
     */
    public FileToTransfer[] getFiles() {
        return (FileToTransfer[]) fFiles.toArray(new FileToTransfer[fFiles.size()]);
    }

    /**
     * Bring up a dialog that lets the user create a new file to transfer.
     */
    private void addFile() {
        FileToTransfer file = new FileToTransfer();
        AddEditFileToTransferDialog dialog = new AddEditFileToTransferDialog(getShell(), file);
        dialog.setTitle(Messages.getString("FileTransferTab.8")); //$NON-NLS-1$
        if (dialog.open() != Window.OK) {
            return;
        }
        fFiles.add(file);
        fFileList.refresh();
        fFileList.setChecked(file, file.getEnabled());
        fLaunchTab.dataChanged();
    }

    private void editFile() {
        IStructuredSelection selection = (IStructuredSelection) fFileList.getSelection();
        FileToTransfer file = (FileToTransfer) selection.getFirstElement();
        if (file == null) {
            return;
        }
        AddEditFileToTransferDialog dialog = new AddEditFileToTransferDialog(getShell(), file);
        dialog.setTitle(Messages.getString("FileTransferTab.9")); //$NON-NLS-1$
        if (dialog.open() != Window.OK) {
            return;
        }
        fFileList.refresh(file);
        fLaunchTab.dataChanged();
    }

    private void removeFiles() {
        IStructuredSelection selection = (IStructuredSelection) fFileList.getSelection();
        FileToTransfer[] files = new FileToTransfer[selection.size()];
        Iterator<?> iter = selection.iterator();
        int i = 0;
        while (iter.hasNext()) {
            files[i] = (FileToTransfer) iter.next();
            i++;
        }
        removeFiles(files);
    }

    /**
     * Removes the given files from the table.
     * 
     * @param files
     */
    public void removeFiles(FileToTransfer[] files) {
        for (int i = 0; i < files.length; i++) {
            fFiles.remove(files[i]);
        }
        fFileList.refresh();
        fLaunchTab.dataChanged();
    }

    protected Shell getShell() {
        return getControl().getShell();
    }

    /**
     * Persist table settings into the give dialog store, prefixed
     * with the given key.
     * 
     * @param settings dialog store
     * @param qualifier key qualifier
     */
    public void saveColumnSettings(IDialogSettings settings, String qualifier) {
        for (int i = 0; i < 2; i++) {
            //persist the first 2 column weights
            settings.put(qualifier + ".column" + i, getColumnWeight(i)); //$NON-NLS-1$
        }
        settings.put(qualifier + ".sortColumn", fSortColumn); //$NON-NLS-1$
    }

    private float getColumnWeight(int col) {
        Table table = fFileList.getTable();
        int tableWidth = table.getSize().x;
        int columnWidth = table.getColumn(col).getWidth();
        if (tableWidth > columnWidth) {
            return ((float) columnWidth) / tableWidth;
        }
        return 1 / 3F;
    }

    /**
     * Restore table settings from the given dialog store using the
     * given key.
     * 
     * @param settings dialog settings store
     * @param qualifier key to restore settings from
     */
    public void restoreColumnSettings(IDialogSettings settings, String qualifier) {
        fWeight1 = restoreColumnWeight(settings, qualifier, 0);
        fWeight2 = restoreColumnWeight(settings, qualifier, 1);
        fFileList.getTable().layout(true);
        try {
            fSortColumn = settings.getInt(qualifier + ".sortColumn"); //$NON-NLS-1$
        } catch (NumberFormatException e) {
            fSortColumn = 1;
        }
        switch (fSortColumn) {
        case 1:
            sortByEnabled();
            break;
        case 2:
            sortByHostPath();
            break;
        case 3:
            sortByTargetPath();
            break;
        }
    }

    private float restoreColumnWeight(IDialogSettings settings, String qualifier, int col) {
        try {
            return settings.getFloat(qualifier + ".column" + col); //$NON-NLS-1$
        } catch (NumberFormatException e) {
            return 1 / 3F;
        }

    }

    Viewer getViewer() {
        return fFileList;
    }

    boolean fileExists(File file) {
        Pair<Long, Boolean> entry = fFileInfoCache.get(file);

        // recheck the status occasionally, either after time passes or
        // whenever the UI is recreated (as in constructor)
        if (System.currentTimeMillis() >= fFileInfoCacheFlushTime) {
            // remove entries not checked at all in a while
            long deadLine = System.currentTimeMillis() - CACHE_CHECK_QUANTUM;
            Iterator<Pair<Long, Boolean>> iter = fFileInfoCache.values().iterator();
            while (iter.hasNext()) {
                Pair<Long, Boolean> ientry = iter.next();
                if (ientry.first < deadLine) {
                    iter.remove();
                }
            }
            fFileInfoCacheFlushTime = System.currentTimeMillis() + CACHE_CHECK_QUANTUM;
        }

        if (entry == null) {
            //System.out.println("Checking " + file);
            entry = new Pair<Long, Boolean>(System.currentTimeMillis(), file.exists());
            fFileInfoCache.put(file, entry);
        } else {
            //System.out.println("Not checking " + file);
        }
        return entry.second;
    }
}