| /******************************************************************************* |
| * Copyright (c) 2004, 2011 Jeff Pound and others. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * https://www.eclipse.org/legal/epl-2.0 |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Jeff Pound - initial API and implementation |
| * Tasktop Technologies - improvement |
| *******************************************************************************/ |
| |
| package org.eclipse.mylyn.internal.tasks.ui.wizards; |
| |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.lang.reflect.InvocationTargetException; |
| import java.text.MessageFormat; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.dialogs.IDialogSettings; |
| import org.eclipse.jface.layout.GridDataFactory; |
| import org.eclipse.jface.layout.GridLayoutFactory; |
| import org.eclipse.jface.operation.IRunnableWithProgress; |
| import org.eclipse.jface.wizard.WizardPage; |
| import org.eclipse.mylyn.commons.core.StatusHandler; |
| import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; |
| import org.eclipse.mylyn.tasks.core.data.TaskAttachmentMapper; |
| import org.eclipse.mylyn.tasks.core.data.TaskAttachmentModel; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.ScrolledComposite; |
| import org.eclipse.swt.events.ControlAdapter; |
| import org.eclipse.swt.events.ControlEvent; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.PaintEvent; |
| import org.eclipse.swt.events.PaintListener; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Image; |
| 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.Canvas; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.ScrollBar; |
| import org.eclipse.swt.widgets.Text; |
| |
| /** |
| * Shows a preview of an attachment. |
| * |
| * @author Jeff Pound |
| * @author Steffen Pingel |
| */ |
| public class AttachmentPreviewPage extends WizardPage { |
| |
| private static final String DIALOG_SETTING_RUN_IN_BACKGROUND = "run-in-background"; //$NON-NLS-1$ |
| |
| private static final String DIALOG_SETTINGS_SECTION_ATTACHMENTS_WIZARD = "attachments-wizard"; //$NON-NLS-1$ |
| |
| protected static final int MAX_TEXT_SIZE = 50000; |
| |
| private static final String PAGE_NAME = "PreviewAttachmentPage"; //$NON-NLS-1$ |
| |
| private final Set<String> imageTypes; |
| |
| private final TaskAttachmentModel model; |
| |
| private Button runInBackgroundButton; |
| |
| private ScrolledComposite scrolledComposite; |
| |
| private final Set<String> textTypes; |
| |
| private Composite contentComposite; |
| |
| public AttachmentPreviewPage(TaskAttachmentModel model) { |
| super(PAGE_NAME); |
| this.model = model; |
| setTitle(Messages.AttachmentPreviewPage_Attachment_Preview); |
| setDescription(Messages.AttachmentPreviewPage_Review_the_attachment_before_submitting); |
| |
| textTypes = new HashSet<String>(); |
| textTypes.add("text/plain"); //$NON-NLS-1$ |
| textTypes.add("text/html"); //$NON-NLS-1$ |
| textTypes.add("application/xml"); //$NON-NLS-1$ |
| |
| imageTypes = new HashSet<String>(); |
| imageTypes.add("image/jpeg"); //$NON-NLS-1$ |
| imageTypes.add("image/gif"); //$NON-NLS-1$ |
| imageTypes.add("image/png"); //$NON-NLS-1$ |
| imageTypes.add("image/tiff"); //$NON-NLS-1$ |
| } |
| |
| private void adjustScrollbars(Rectangle imgSize) { |
| Rectangle clientArea = scrolledComposite.getClientArea(); |
| |
| ScrollBar hBar = scrolledComposite.getHorizontalBar(); |
| hBar.setMinimum(0); |
| hBar.setMaximum(imgSize.width - 1); |
| hBar.setPageIncrement(clientArea.width); |
| hBar.setIncrement(10); |
| |
| ScrollBar vBar = scrolledComposite.getVerticalBar(); |
| vBar.setMinimum(0); |
| vBar.setMaximum(imgSize.height - 1); |
| vBar.setPageIncrement(clientArea.height); |
| vBar.setIncrement(10); |
| } |
| |
| public void createControl(Composite parent) { |
| final Composite composite = new Composite(parent, SWT.NONE); |
| composite.setLayout(new GridLayout()); |
| setControl(composite); |
| |
| contentComposite = new Composite(composite, SWT.NONE); |
| contentComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| contentComposite.setLayout(new GridLayout()); |
| |
| runInBackgroundButton = new Button(composite, SWT.CHECK); |
| runInBackgroundButton.setText(Messages.AttachmentPreviewPage_Run_in_background); |
| |
| IDialogSettings settings = TasksUiPlugin.getDefault().getDialogSettings(); |
| IDialogSettings attachmentsSettings = settings.getSection(DIALOG_SETTINGS_SECTION_ATTACHMENTS_WIZARD); |
| if (attachmentsSettings != null) { |
| runInBackgroundButton.setSelection(attachmentsSettings.getBoolean(DIALOG_SETTING_RUN_IN_BACKGROUND)); |
| } |
| |
| Dialog.applyDialogFont(composite); |
| } |
| |
| @Override |
| public void dispose() { |
| IDialogSettings settings = TasksUiPlugin.getDefault().getDialogSettings(); |
| IDialogSettings attachmentsSettings = settings.getSection(DIALOG_SETTINGS_SECTION_ATTACHMENTS_WIZARD); |
| if (attachmentsSettings == null) { |
| attachmentsSettings = settings.addNewSection(DIALOG_SETTINGS_SECTION_ATTACHMENTS_WIZARD); |
| } |
| attachmentsSettings.put(DIALOG_SETTING_RUN_IN_BACKGROUND, runInBackgroundButton.getSelection()); |
| super.dispose(); |
| } |
| |
| @Override |
| public void setVisible(boolean visible) { |
| if (visible) { |
| Control[] children = contentComposite.getChildren(); |
| for (Control control : children) { |
| control.dispose(); |
| } |
| if (isTextAttachment() || isImageAttachment()) { |
| Object content = getContent(contentComposite); |
| if (content instanceof String) { |
| createTextPreview(contentComposite, (String) content); |
| } else if (content instanceof Image) { |
| createImagePreview(contentComposite, (Image) content); |
| } |
| } else { |
| createGenericPreview(contentComposite); |
| } |
| contentComposite.layout(true, true); |
| } |
| Dialog.applyDialogFont(contentComposite); |
| super.setVisible(visible); |
| } |
| |
| private void createErrorPreview(Composite composite, String message) { |
| Label label = new Label(composite, SWT.NONE); |
| label.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| label.setText(message); |
| } |
| |
| private void createGenericPreview(Composite composite) { |
| Label label = new Label(composite, SWT.NONE); |
| label.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| // TODO 3.5 put filename on model |
| String name = model.getSource().getName(); |
| TaskAttachmentMapper taskAttachment = TaskAttachmentMapper.createFrom(model.getAttribute()); |
| if (taskAttachment.getFileName() != null) { |
| name = taskAttachment.getFileName(); |
| } |
| label.setText(MessageFormat.format( |
| Messages.AttachmentPreviewPage_A_preview_the_type_X_is_currently_not_available, name, |
| model.getContentType())); |
| } |
| |
| private void createImagePreview(Composite composite, final Image bufferedImage) { |
| scrolledComposite = new ScrolledComposite(composite, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); |
| scrolledComposite.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create()); |
| scrolledComposite.setExpandHorizontal(true); |
| scrolledComposite.setExpandVertical(true); |
| |
| Composite canvasComposite = new Composite(scrolledComposite, SWT.NONE); |
| canvasComposite.setLayout(GridLayoutFactory.fillDefaults().create()); |
| Canvas canvas = new Canvas(canvasComposite, SWT.NO_BACKGROUND); |
| final Rectangle imgSize = bufferedImage.getBounds(); |
| canvas.setLayoutData(GridDataFactory.fillDefaults() |
| .align(SWT.CENTER, SWT.CENTER) |
| .grab(true, true) |
| .hint(imgSize.width, imgSize.height) |
| .create()); |
| canvas.addPaintListener(new PaintListener() { |
| public void paintControl(PaintEvent event) { |
| event.gc.drawImage(bufferedImage, 0, 0); |
| } |
| }); |
| canvas.addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent event) { |
| bufferedImage.dispose(); |
| } |
| }); |
| canvas.setSize(imgSize.width, imgSize.height); |
| scrolledComposite.setMinSize(imgSize.width, imgSize.height); |
| scrolledComposite.setContent(canvasComposite); |
| scrolledComposite.addControlListener(new ControlAdapter() { |
| @Override |
| public void controlResized(ControlEvent event) { |
| adjustScrollbars(imgSize); |
| } |
| |
| }); |
| adjustScrollbars(imgSize); |
| } |
| |
| private void createTextPreview(Composite composite, String contents) { |
| Text text = new Text(composite, SWT.MULTI | SWT.READ_ONLY | SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER); |
| GridData gd = new GridData(GridData.FILL_BOTH); |
| gd.heightHint = composite.getBounds().y; |
| gd.widthHint = composite.getBounds().x; |
| text.setLayoutData(gd); |
| text.setText(contents); |
| } |
| |
| private Object getContent(final Composite composite) { |
| final Object result[] = new Object[1]; |
| try { |
| getContainer().run(true, false, new IRunnableWithProgress() { |
| public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { |
| try { |
| monitor.beginTask(Messages.AttachmentPreviewPage_Preparing_preview, IProgressMonitor.UNKNOWN); |
| final InputStream in = model.getSource().createInputStream(monitor); |
| try { |
| if (isTextAttachment()) { |
| StringBuilder content = new StringBuilder(); |
| BufferedReader reader = new BufferedReader(new InputStreamReader(in)); |
| String line; |
| while ((line = reader.readLine()) != null && content.length() < MAX_TEXT_SIZE |
| && !monitor.isCanceled()) { |
| content.append(line); |
| content.append("\n"); //$NON-NLS-1$ |
| } |
| result[0] = content.toString(); |
| } else if (isImageAttachment()) { |
| Display.getDefault().syncExec(new Runnable() { |
| public void run() { |
| // Uses double buffering to paint the image; there was a weird behavior |
| // with transparent images and flicker with large images |
| Image originalImage = new Image(getShell().getDisplay(), in); |
| final Image bufferedImage = new Image(getShell().getDisplay(), |
| originalImage.getBounds()); |
| GC gc = new GC(bufferedImage); |
| gc.setBackground(composite.getBackground()); |
| gc.fillRectangle(originalImage.getBounds()); |
| gc.drawImage(originalImage, 0, 0); |
| gc.dispose(); |
| originalImage.dispose(); |
| result[0] = bufferedImage; |
| } |
| }); |
| } |
| } catch (IOException e) { |
| throw new InvocationTargetException(e); |
| } finally { |
| try { |
| in.close(); |
| } catch (IOException e) { |
| StatusHandler.log(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, |
| "Failed to close file", e)); //$NON-NLS-1$ |
| } |
| } |
| } catch (CoreException e) { |
| throw new InvocationTargetException(e); |
| } finally { |
| monitor.done(); |
| } |
| } |
| }); |
| } catch (InvocationTargetException e) { |
| StatusHandler.log(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Error generating preview", e)); //$NON-NLS-1$ |
| createErrorPreview(composite, Messages.AttachmentPreviewPage_Could_not_create_preview); |
| return null; |
| } catch (InterruptedException e) { |
| return null; |
| } |
| return result[0]; |
| } |
| |
| private boolean isImageAttachment() { |
| return imageTypes.contains(model.getContentType()); |
| } |
| |
| private boolean isTextAttachment() { |
| return textTypes.contains(model.getContentType()); |
| } |
| |
| public boolean runInBackground() { |
| return runInBackgroundButton.getSelection(); |
| } |
| |
| } |