Java tutorial
/* * 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; } }