blob: cf24a572fd03b812c108a84a83f558baa77d0c7a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2014 Tasktop Technologies 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:
* Tasktop Technologies - initial API and implementation
* Jeff Pound - attachment support
* Frank Becker - improvements for bug 204051
*******************************************************************************/
package org.eclipse.mylyn.internal.tasks.ui.editors;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.LegacyActionTools;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.mylyn.commons.core.CoreUtil;
import org.eclipse.mylyn.commons.ui.CommonImages;
import org.eclipse.mylyn.commons.ui.ConfigurableColumnTableViewerSupport;
import org.eclipse.mylyn.commons.ui.TableColumnDescriptor;
import org.eclipse.mylyn.commons.workbench.forms.CommonFormUtil;
import org.eclipse.mylyn.internal.tasks.core.TaskAttachment;
import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
import org.eclipse.mylyn.internal.tasks.ui.commands.OpenTaskAttachmentHandler;
import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiMenus;
import org.eclipse.mylyn.internal.tasks.ui.views.TaskKeyComparator;
import org.eclipse.mylyn.internal.tasks.ui.wizards.TaskAttachmentWizard.Mode;
import org.eclipse.mylyn.tasks.core.ITaskAttachment;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.ui.TasksUiImages;
import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPart;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.events.ExpansionAdapter;
import org.eclipse.ui.forms.events.ExpansionEvent;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.forms.widgets.Section;
/**
* @author Mik Kersten
* @author Rob Elves
* @author Steffen Pingel
*/
public class TaskEditorAttachmentPart extends AbstractTaskEditorPart {
private class AttachmentTableViewerComparator extends ViewerComparator {
private int propertyIndex;
private static final int DESCENDING = 1;
private int direction = DESCENDING;
public AttachmentTableViewerComparator() {
this.propertyIndex = 0;
direction = DESCENDING;
}
public void setColumn(int column) {
if (column == this.propertyIndex) {
// Same column as last sort; toggle the direction
direction = 1 - direction;
} else {
// New column; do an ascending sort
this.propertyIndex = column;
direction = DESCENDING;
}
}
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
ITaskAttachment attachment1 = (ITaskAttachment) e1;
ITaskAttachment attachment2 = (ITaskAttachment) e2;
int rc;
rc = compareColumn(attachment1, attachment2, propertyIndex);
// If descending order, flip the direction
if (direction == DESCENDING) {
rc = -rc;
}
return rc;
}
}
private class AttachmentTableFilter extends ViewerFilter {
private boolean filterDeprecatedEnabled;
public boolean isFilterDeprecatedEnabled() {
return filterDeprecatedEnabled;
}
public void setFilterDeprecatedEnabled(boolean filterDeprecatedEnabled) {
this.filterDeprecatedEnabled = filterDeprecatedEnabled;
}
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (filterDeprecatedEnabled) {
if (element instanceof ITaskAttachment) {
return !((ITaskAttachment) element).isDeprecated();
}
}
return true;
}
}
private static final String PREF_FILTER_DEPRECATED = "org.eclipse.mylyn.tasks.ui.editor.attachments.filter.deprecated"; //$NON-NLS-1$
private static final String ID_POPUP_MENU = "org.eclipse.mylyn.tasks.ui.editor.menu.attachments"; //$NON-NLS-1$
private List<TaskAttribute> attachmentAttributes;
private boolean hasIncoming;
private MenuManager menuManager;
private Composite attachmentsComposite;
private Table attachmentsTable;
private AttachmentTableFilter tableFilter;
private TableViewer attachmentsViewer;
private List<ITaskAttachment> attachmentList;
private Section section;
private int nonDeprecatedCount;
private Action filterDeprecatedAttachmentsAction;
TaskKeyComparator keyComparator = new TaskKeyComparator();
private AttachmentTableViewerComparator comparator;
public TaskEditorAttachmentPart() {
setPartName(Messages.TaskEditorAttachmentPart_Attachments);
}
protected TableColumnDescriptor[] createColumnDescriptors() {
TableColumnDescriptor[] descriptors = new TableColumnDescriptor[6];
descriptors[0] = new TableColumnDescriptor(130, Messages.TaskEditorAttachmentPart_Name, SWT.LEFT, false,
SWT.None, false);
descriptors[1] = new TableColumnDescriptor(150, Messages.TaskEditorAttachmentPart_Description, SWT.LEFT, false,
SWT.None, false);
descriptors[2] = new TableColumnDescriptor(70, Messages.TaskEditorAttachmentPart_Size, SWT.RIGHT, false,
SWT.None, false);
descriptors[3] = new TableColumnDescriptor(100, Messages.TaskEditorAttachmentPart_Creator, SWT.LEFT, false,
SWT.None, true);
descriptors[4] = new TableColumnDescriptor(100, Messages.TaskEditorAttachmentPart_Created, SWT.LEFT, true,
SWT.DOWN, false);
descriptors[5] = new TableColumnDescriptor(0, Messages.TaskEditorAttachmentPart_ID, SWT.LEFT, false, SWT.None,
false);
return descriptors;
}
private void createAttachmentTable(FormToolkit toolkit, final Composite attachmentsComposite) {
attachmentsTable = toolkit.createTable(attachmentsComposite, SWT.MULTI | SWT.FULL_SELECTION);
attachmentsTable.setLinesVisible(true);
attachmentsTable.setHeaderVisible(true);
attachmentsTable.setLayout(new GridLayout());
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, false).hint(500, SWT.DEFAULT).applyTo(
attachmentsTable);
attachmentsTable.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER);
TableColumnDescriptor[] columnDescriptorArray = createColumnDescriptors();
String[] localAttachmentsColumns = new String[columnDescriptorArray.length];
for (int i = 0; i < columnDescriptorArray.length; i++) {
int index = i;
localAttachmentsColumns[i] = columnDescriptorArray[i].getName();
TableColumn column = new TableColumn(attachmentsTable, columnDescriptorArray[i].getAlignment(), index);
column.setText(columnDescriptorArray[i].getName());
column.setWidth(columnDescriptorArray[i].getWidth());
column.setMoveable(true);
column.setData(TableColumnDescriptor.TABLE_COLUMN_DESCRIPTOR_KEY, columnDescriptorArray[i]);
if (columnDescriptorArray[i].isDefaultSortColumn()) {
attachmentsTable.setSortColumn(column);
attachmentsTable.setSortDirection(columnDescriptorArray[i].getSortDirection());
}
column.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
comparator.setColumn(index);
}
});
}
attachmentsViewer = new TableViewer(attachmentsTable);
attachmentsViewer.setUseHashlookup(true);
attachmentsViewer.setColumnProperties(localAttachmentsColumns);
ColumnViewerToolTipSupport.enableFor(attachmentsViewer, ToolTip.NO_RECREATE);
comparator = createComparator();
attachmentsViewer.setComparator(comparator);
attachmentsViewer.setContentProvider(ArrayContentProvider.getInstance());
attachmentsViewer.setLabelProvider(createTableProvider());
attachmentsViewer.addOpenListener(new IOpenListener() {
public void open(OpenEvent event) {
openAttachments(event);
}
});
attachmentsViewer.addSelectionChangedListener(getTaskEditorPage());
attachmentsViewer.setInput(attachmentList.toArray());
menuManager = new MenuManager();
menuManager.setRemoveAllWhenShown(true);
menuManager.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
TasksUiMenus.fillTaskAttachmentMenu(manager);
}
});
getTaskEditorPage().getEditorSite().registerContextMenu(ID_POPUP_MENU, menuManager, attachmentsViewer, true);
Menu menu = menuManager.createContextMenu(attachmentsTable);
attachmentsTable.setMenu(menu);
attachmentsViewer.addFilter(tableFilter);
new ConfigurableColumnTableViewerSupport(attachmentsViewer, columnDescriptorArray, getStateFile());
}
private File getStateFile() {
IPath stateLocation = Platform.getStateLocation(TasksUiPlugin.getDefault().getBundle());
return stateLocation.append("TaskEditorAttachmentPart.xml").toFile(); //$NON-NLS-1$
}
private void createButtons(Composite attachmentsComposite, FormToolkit toolkit) {
final Composite attachmentControlsComposite = toolkit.createComposite(attachmentsComposite);
attachmentControlsComposite.setLayout(new GridLayout(2, false));
attachmentControlsComposite.setLayoutData(new GridData(GridData.BEGINNING));
Button attachFileButton = toolkit.createButton(attachmentControlsComposite,
Messages.TaskEditorAttachmentPart_Attach_, SWT.PUSH);
attachFileButton.setImage(CommonImages.getImage(CommonImages.FILE_PLAIN));
attachFileButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
EditorUtil.openNewAttachmentWizard(getTaskEditorPage(), Mode.DEFAULT, null);
}
});
getTaskEditorPage().registerDefaultDropListener(attachFileButton);
Button attachScreenshotButton = toolkit.createButton(attachmentControlsComposite,
Messages.TaskEditorAttachmentPart_Attach__Screenshot, SWT.PUSH);
attachScreenshotButton.setImage(CommonImages.getImage(CommonImages.IMAGE_CAPTURE));
attachScreenshotButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
EditorUtil.openNewAttachmentWizard(getTaskEditorPage(), Mode.SCREENSHOT, null);
}
});
getTaskEditorPage().registerDefaultDropListener(attachScreenshotButton);
}
@Override
public void createControl(Composite parent, final FormToolkit toolkit) {
initialize();
section = createSection(parent, toolkit, hasIncoming);
updateSectionTitle();
if (hasIncoming) {
expandSection(toolkit, section);
} else {
section.addExpansionListener(new ExpansionAdapter() {
@Override
public void expansionStateChanged(ExpansionEvent event) {
if (attachmentsComposite == null) {
expandSection(toolkit, section);
getTaskEditorPage().reflow();
}
}
});
}
setSection(toolkit, section);
}
private void expandSection(FormToolkit toolkit, Section section) {
attachmentsComposite = toolkit.createComposite(section);
attachmentsComposite.setLayout(EditorUtil.createSectionClientLayout());
attachmentsComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
getTaskEditorPage().registerDefaultDropListener(section);
if (attachmentAttributes.size() > 0) {
createAttachmentTable(toolkit, attachmentsComposite);
} else {
Label label = toolkit.createLabel(attachmentsComposite, Messages.TaskEditorAttachmentPart_No_attachments);
getTaskEditorPage().registerDefaultDropListener(label);
}
createButtons(attachmentsComposite, toolkit);
toolkit.paintBordersFor(attachmentsComposite);
section.setClient(attachmentsComposite);
}
@Override
public void dispose() {
if (menuManager != null) {
menuManager.dispose();
}
super.dispose();
}
private void initialize() {
attachmentAttributes = getTaskData().getAttributeMapper().getAttributesByType(getTaskData(),
TaskAttribute.TYPE_ATTACHMENT);
attachmentList = new ArrayList<ITaskAttachment>(attachmentAttributes.size());
for (TaskAttribute attribute : attachmentAttributes) {
if (getModel().hasIncomingChanges(attribute)) {
hasIncoming = true;
}
TaskAttachment taskAttachment = new TaskAttachment(getModel().getTaskRepository(), getModel().getTask(),
attribute);
getTaskData().getAttributeMapper().updateTaskAttachment(taskAttachment, attribute);
attachmentList.add(taskAttachment);
if (!taskAttachment.isDeprecated()) {
nonDeprecatedCount++;
}
}
tableFilter = new AttachmentTableFilter();
}
@Override
protected void fillToolBar(ToolBarManager toolBarManager) {
filterDeprecatedAttachmentsAction = new Action("", IAction.AS_CHECK_BOX) { //$NON-NLS-1$
@Override
public void run() {
TasksUiPlugin.getDefault().getPreferenceStore().setValue(PREF_FILTER_DEPRECATED, isChecked());
filterDeprecated(isChecked());
}
};
filterDeprecatedAttachmentsAction.setImageDescriptor(TasksUiImages.FILTER_OBSOLETE_SMALL);
filterDeprecatedAttachmentsAction.setToolTipText(Messages.TaskEditorAttachmentPart_Hide_Obsolete_Tooltip);
if (nonDeprecatedCount > 0 && nonDeprecatedCount < attachmentAttributes.size()) {
filterDeprecated(TasksUiPlugin.getDefault().getPreferenceStore().getBoolean(PREF_FILTER_DEPRECATED));
} else {
// do not allow filtering if it would cause the table to be empty or no change
filterDeprecatedAttachmentsAction.setEnabled(false);
}
toolBarManager.add(filterDeprecatedAttachmentsAction);
Action attachFileAction = new Action() {
@Override
public void run() {
EditorUtil.openNewAttachmentWizard(getTaskEditorPage(), Mode.DEFAULT, null);
}
};
attachFileAction.setToolTipText(Messages.TaskEditorAttachmentPart_Attach_);
attachFileAction.setImageDescriptor(TasksUiImages.FILE_NEW_SMALL);
toolBarManager.add(attachFileAction);
Action attachScreenshotAction = new Action() {
@Override
public void run() {
EditorUtil.openNewAttachmentWizard(getTaskEditorPage(), Mode.SCREENSHOT, null);
}
};
attachScreenshotAction.setToolTipText(Messages.TaskEditorAttachmentPart_Attach__Screenshot);
attachScreenshotAction.setImageDescriptor(TasksUiImages.IMAGE_CAPTURE_SMALL);
toolBarManager.add(attachScreenshotAction);
}
private void updateSectionTitle() {
if (tableFilter.isFilterDeprecatedEnabled()) {
section.setText(NLS.bind(Messages.TaskEditorAttachmentPart_Attachment_Section_Title_X_of_Y,
new Object[] { LegacyActionTools.escapeMnemonics(getPartName()), nonDeprecatedCount,
attachmentAttributes.size() }));
} else {
section.setText(NLS.bind(Messages.TaskEditorAttachmentPart_Attachment_Section_Title_X,
LegacyActionTools.escapeMnemonics(getPartName()), attachmentAttributes.size()));
}
}
protected void openAttachments(OpenEvent event) {
List<ITaskAttachment> attachments = new ArrayList<ITaskAttachment>();
StructuredSelection selection = (StructuredSelection) event.getSelection();
List<?> items = selection.toList();
for (Object item : items) {
if (item instanceof ITaskAttachment) {
attachments.add((ITaskAttachment) item);
}
}
if (attachments.isEmpty()) {
return;
}
IWorkbenchPage page = getTaskEditorPage().getSite().getWorkbenchWindow().getActivePage();
try {
OpenTaskAttachmentHandler.openAttachments(page, attachments);
} catch (OperationCanceledException e) {
// canceled
}
}
@Override
public boolean setFormInput(Object input) {
if (input instanceof String) {
String text = (String) input;
if (attachmentAttributes != null) {
for (ITaskAttachment attachment : attachmentList) {
if (text.equals(attachment.getTaskAttribute().getId())) {
CommonFormUtil.setExpanded((ExpandableComposite) getControl(), true);
return selectReveal(attachment);
}
}
}
}
return super.setFormInput(input);
}
private boolean selectReveal(ITaskAttachment attachment) {
if (attachment == null || attachmentsTable == null) {
return false;
}
if (tableFilter.isFilterDeprecatedEnabled() && attachment.isDeprecated()) {
filterDeprecated(false);
}
attachmentsViewer.setSelection(new StructuredSelection(attachment));
IManagedForm mform = getManagedForm();
ScrolledForm form = mform.getForm();
EditorUtil.focusOn(form, attachmentsTable);
return true;
}
void filterDeprecated(boolean filter) {
if (filterDeprecatedAttachmentsAction.isChecked() != filter) {
filterDeprecatedAttachmentsAction.setChecked(filter);
}
tableFilter.setFilterDeprecatedEnabled(filter);
if (attachmentsViewer != null) {
attachmentsViewer.refresh();
getTaskEditorPage().reflow();
}
updateSectionTitle();
}
protected int compareColumn(ITaskAttachment attachment1, ITaskAttachment attachment2, int propertyIndex) {
int rc;
switch (propertyIndex) {
case 0:
rc = CoreUtil.compare(attachment1.getFileName(), attachment2.getFileName());
break;
case 1:
String description1 = attachment1.getDescription();
String description2 = attachment2.getDescription();
rc = CoreUtil.compare(description1, description2);
break;
case 2:
rc = CoreUtil.compare(attachment1.getLength(), attachment2.getLength());
break;
case 3:
String author1 = attachment1.getAuthor() != null ? attachment1.getAuthor().toString() : null;
String author2 = attachment2.getAuthor() != null ? attachment2.getAuthor().toString() : null;
rc = CoreUtil.compare(author1, author2);
break;
case 4:
rc = CoreUtil.compare(attachment1.getCreationDate(), attachment2.getCreationDate());
break;
case 5:
String key1 = AttachmentTableLabelProvider.getAttachmentId(attachment1);
String key2 = AttachmentTableLabelProvider.getAttachmentId(attachment2);
rc = keyComparator.compare2(key1, key2);
break;
default:
rc = 0;
break;
}
return rc;
}
protected AttachmentTableViewerComparator createComparator() {
return new AttachmentTableViewerComparator();
}
protected AttachmentTableLabelProvider createTableProvider() {
return new AttachmentTableLabelProvider();
}
}