blob: 8b05e5108c0c0fac4ebf27c8b77fbc1df8856ba3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2008 Tasktop Technologies and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Tasktop Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.internal.tasks.ui.deprecated;
import java.io.File;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
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.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.IJobChangeListener;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ControlContribution;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.ITextListener;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.TextEvent;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.mylyn.internal.provisional.commons.ui.CommonImages;
import org.eclipse.mylyn.internal.provisional.commons.ui.CommonThemes;
import org.eclipse.mylyn.internal.tasks.core.AbstractTask;
import org.eclipse.mylyn.internal.tasks.core.AbstractTaskCategory;
import org.eclipse.mylyn.internal.tasks.core.CommentQuoter;
import org.eclipse.mylyn.internal.tasks.core.ITaskListChangeListener;
import org.eclipse.mylyn.internal.tasks.core.RepositoryQuery;
import org.eclipse.mylyn.internal.tasks.core.TaskContainerDelta;
import org.eclipse.mylyn.internal.tasks.core.deprecated.AbstractLegacyDuplicateDetector;
import org.eclipse.mylyn.internal.tasks.core.deprecated.AbstractLegacyRepositoryConnector;
import org.eclipse.mylyn.internal.tasks.core.deprecated.AbstractTaskDataHandler;
import org.eclipse.mylyn.internal.tasks.core.deprecated.RepositoryAttachment;
import org.eclipse.mylyn.internal.tasks.core.deprecated.RepositoryOperation;
import org.eclipse.mylyn.internal.tasks.core.deprecated.RepositoryTaskAttribute;
import org.eclipse.mylyn.internal.tasks.core.deprecated.RepositoryTaskData;
import org.eclipse.mylyn.internal.tasks.core.deprecated.TaskComment;
import org.eclipse.mylyn.internal.tasks.ui.PersonProposalLabelProvider;
import org.eclipse.mylyn.internal.tasks.ui.PersonProposalProvider;
import org.eclipse.mylyn.internal.tasks.ui.TaskHyperlink;
import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
import org.eclipse.mylyn.internal.tasks.ui.actions.AbstractTaskEditorAction;
import org.eclipse.mylyn.internal.tasks.ui.actions.AttachAction;
import org.eclipse.mylyn.internal.tasks.ui.actions.AttachScreenshotAction;
import org.eclipse.mylyn.internal.tasks.ui.actions.ClearOutgoingAction;
import org.eclipse.mylyn.internal.tasks.ui.actions.NewSubTaskAction;
import org.eclipse.mylyn.internal.tasks.ui.actions.SynchronizeEditorAction;
import org.eclipse.mylyn.internal.tasks.ui.actions.ToggleTaskActivationAction;
import org.eclipse.mylyn.internal.tasks.ui.editors.AttachmentTableLabelProvider;
import org.eclipse.mylyn.internal.tasks.ui.editors.AttachmentsTableContentProvider;
import org.eclipse.mylyn.internal.tasks.ui.editors.ContentOutlineTools;
import org.eclipse.mylyn.internal.tasks.ui.editors.IRepositoryTaskAttributeListener;
import org.eclipse.mylyn.internal.tasks.ui.editors.IRepositoryTaskSelection;
import org.eclipse.mylyn.internal.tasks.ui.editors.RepositoryAttachmentEditorInput;
import org.eclipse.mylyn.internal.tasks.ui.editors.RepositoryTaskEditorDropListener;
import org.eclipse.mylyn.internal.tasks.ui.editors.RepositoryTaskOutlineNode;
import org.eclipse.mylyn.internal.tasks.ui.editors.RepositoryTaskOutlinePage;
import org.eclipse.mylyn.internal.tasks.ui.editors.RepositoryTaskSelection;
import org.eclipse.mylyn.internal.tasks.ui.editors.TaskListChangeAdapter;
import org.eclipse.mylyn.internal.tasks.ui.editors.TaskUrlHyperlink;
import org.eclipse.mylyn.internal.tasks.ui.search.SearchHitCollector;
import org.eclipse.mylyn.internal.tasks.ui.util.AttachmentUtil;
import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal;
import org.eclipse.mylyn.internal.tasks.ui.views.UpdateRepositoryConfigurationAction;
import org.eclipse.mylyn.tasks.core.AbstractDuplicateDetector;
import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
import org.eclipse.mylyn.tasks.core.IRepositoryElement;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.ITaskAttachment;
import org.eclipse.mylyn.tasks.core.RepositoryStatus;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.ITask.SynchronizationState;
import org.eclipse.mylyn.tasks.ui.AbstractRepositoryConnectorUi;
import org.eclipse.mylyn.tasks.ui.TasksUi;
import org.eclipse.mylyn.tasks.ui.TasksUiImages;
import org.eclipse.mylyn.tasks.ui.TasksUiUtil;
import org.eclipse.mylyn.tasks.ui.editors.AbstractRenderingEngine;
import org.eclipse.mylyn.tasks.ui.editors.TaskEditor;
import org.eclipse.osgi.util.NLS;
import org.eclipse.search.ui.NewSearchUI;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.LocationAdapter;
import org.eclipse.swt.browser.LocationEvent;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.VerifyKeyListener;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.FilteredTree;
import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
import org.eclipse.ui.forms.IFormColors;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.events.ExpansionAdapter;
import org.eclipse.ui.forms.events.ExpansionEvent;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.eclipse.ui.forms.widgets.ImageHyperlink;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.internal.ObjectActionContributorManager;
import org.eclipse.ui.internal.WorkbenchImages;
import org.eclipse.ui.keys.IBindingService;
import org.eclipse.ui.themes.IThemeManager;
import org.eclipse.ui.views.contentoutline.ContentOutline;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
/**
* @deprecated Do not use. This class is pending for removal: see bug 237552.
*/
@Deprecated
public abstract class AbstractRepositoryTaskEditor extends TaskFormPage {
private static final String PREF_SORT_ORDER_PREFIX = "org.eclipse.mylyn.editor.comments.sortDirectionUp.";
private static final String ERROR_NOCONNECTIVITY = "Unable to submit at this time. Check connectivity and retry.";
private static final String LABEL_HISTORY = "History";
private static final String LABEL_REPLY = "Reply";
private static final String LABEL_JOB_SUBMIT = "Submitting to repository";
private static final String HEADER_DATE_FORMAT = "yyyy-MM-dd HH:mm";
private static final String ATTACHMENT_DEFAULT_NAME = "attachment";
private static final String CTYPE_ZIP = "zip";
private static final String CTYPE_OCTET_STREAM = "octet-stream";
private static final String CTYPE_TEXT = "text";
private static final String CTYPE_HTML = "html";
private static final String LABEL_BROWSER = "Browser";
private static final String LABEL_DEFAULT_EDITOR = "Default Editor";
private static final String LABEL_TEXT_EDITOR = "Text Editor";
protected static final String CONTEXT_MENU_ID = "#MylynRepositoryEditor";
private FormToolkit toolkit;
private ScrolledForm form;
protected TaskRepository repository;
private static final int RADIO_OPTION_WIDTH = 120;
private static final Font TITLE_FONT = JFaceResources.getBannerFont();
protected static final Font TEXT_FONT = JFaceResources.getDefaultFont();
private static final int DESCRIPTION_WIDTH = 79 * 7; // 500;
private static final int DESCRIPTION_HEIGHT = 10 * 14;
protected static final int SUMMARY_HEIGHT = 20;
private static final String LABEL_BUTTON_SUBMIT = "Submit";
private static final String LABEL_COPY_URL_TO_CLIPBOARD = "Copy &URL";
private static final String LABEL_COPY_TO_CLIPBOARD = "Copy Contents";
private static final String LABEL_SAVE = "Save...";
private static final String LABEL_SEARCH_DUPS = "Search";
private static final String LABEL_SELECT_DETECTOR = "Duplicate Detection";
private RepositoryTaskEditorInput editorInput;
private TaskEditor parentEditor = null;
private RepositoryTaskOutlineNode taskOutlineModel = null;
private boolean expandedStateAttributes = false;
protected Button submitButton;
private Table attachmentsTable;
private boolean refreshEnabled = true;
private TableViewer attachmentsTableViewer;
private final String[] attachmentsColumns = { "Name", "Description", "Type", "Size", "Creator", "Created" };
private final int[] attachmentsColumnWidths = { 140, 160, 100, 70, 100, 100 };
private Composite editorComposite;
protected TextViewer summaryTextViewer;
private ImageHyperlink sortHyperlink;
private boolean commentSortIsUp = true;
private boolean commentSortEnable = false;
private Composite addCommentsComposite;
/**
* WARNING: This is present for backward compatibility only. You can get and set text on this widget but all ui
* related changes to this widget will have no affect as ui is now being presented with a StyledText widget. This
* simply proxies get/setText calls to the StyledText widget.
*/
protected Text summaryText;
private TextViewer newCommentTextViewer;
private org.eclipse.swt.widgets.List ccList;
private Section commentsSection;
private Color colorIncoming;
private boolean hasAttributeChanges = false;
private boolean showAttachments = true;
private boolean attachContextEnabled = true;
protected Button searchForDuplicates;
protected CCombo duplicateDetectorChooser;
protected Label duplicateDetectorLabel;
private boolean ignoreLocationEvents = false;
private boolean refreshing = false;
private TaskComment selectedComment = null;
/**
* @author Raphael Ackermann (bug 195514)
*/
private class TabVerifyKeyListener implements VerifyKeyListener {
public void verifyKey(VerifyEvent event) {
// if there is a tab key, do not "execute" it and instead select the Status control
if (event.keyCode == SWT.TAB) {
event.doit = false;
if (headerInfoComposite != null) {
headerInfoComposite.setFocus();
}
}
}
}
protected enum SECTION_NAME {
ATTRIBTUES_SECTION("Attributes"), ATTACHMENTS_SECTION("Attachments"), DESCRIPTION_SECTION("Description"), COMMENTS_SECTION(
"Comments"), NEWCOMMENT_SECTION("New Comment"), ACTIONS_SECTION("Actions"), PEOPLE_SECTION("People"), RELATEDBUGS_SECTION(
"Related Tasks");
private String prettyName;
public String getPrettyName() {
return prettyName;
}
SECTION_NAME(String prettyName) {
this.prettyName = prettyName;
}
}
private final List<IRepositoryTaskAttributeListener> attributesListeners = new ArrayList<IRepositoryTaskAttributeListener>();
protected RepositoryTaskData taskData;
protected final ISelectionProvider selectionProvider = new ISelectionProvider() {
public void addSelectionChangedListener(ISelectionChangedListener listener) {
selectionChangedListeners.add(listener);
}
public ISelection getSelection() {
RepositoryTaskSelection selection = new RepositoryTaskSelection(taskData.getTaskId(),
taskData.getRepositoryUrl(), taskData.getConnectorKind(), "", selectedComment,
taskData.getSummary());
selection.setIsDescription(true);
return selection;
}
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
selectionChangedListeners.remove(listener);
}
public void setSelection(ISelection selection) {
// No implementation.
}
};
private final ITaskListChangeListener TASKLIST_CHANGE_LISTENER = new TaskListChangeAdapter() {
@Override
public void containersChanged(Set<TaskContainerDelta> containers) {
ITask taskToRefresh = null;
for (TaskContainerDelta taskContainerDelta : containers) {
if (!localChange && repositoryTask != null && repositoryTask.equals(taskContainerDelta.getElement())) {
if (taskContainerDelta.getKind().equals(TaskContainerDelta.Kind.CONTENT)
&& !taskContainerDelta.isTransient() && !refreshing) {
taskToRefresh = (ITask) taskContainerDelta.getElement();
break;
}
}
}
if (taskToRefresh != null) {
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
if (repositoryTask.getSynchronizationState() == SynchronizationState.INCOMING
|| repositoryTask.getSynchronizationState() == SynchronizationState.CONFLICT) {
parentEditor.setMessage("Task has incoming changes", IMessageProvider.WARNING,
new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
refreshEditor();
}
});
setSubmitEnabled(false);
} else {
refreshEditor();
}
}
});
}
}
};
private final List<ISelectionChangedListener> selectionChangedListeners = new ArrayList<ISelectionChangedListener>();
private IRepositoryTaskSelection lastSelected = null;
/**
* Focuses on form widgets when an item in the outline is selected.
*/
private final ISelectionListener selectionListener = new ISelectionListener() {
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
if ((part instanceof ContentOutline) && (selection instanceof StructuredSelection)) {
Object select = ((StructuredSelection) selection).getFirstElement();
if (select instanceof RepositoryTaskOutlineNode) {
RepositoryTaskOutlineNode n = (RepositoryTaskOutlineNode) select;
if (lastSelected != null
&& ContentOutlineTools.getHandle(n).equals(ContentOutlineTools.getHandle(lastSelected))) {
// we don't need to set the selection if it is already
// set
return;
}
lastSelected = n;
boolean highlight = true;
if (n.getKey().equals(RepositoryTaskOutlineNode.LABEL_COMMENTS)) {
highlight = false;
}
Object data = n.getData();
if (n.getKey().equals(RepositoryTaskOutlineNode.LABEL_NEW_COMMENT)) {
selectNewComment();
} else if (n.getKey().equals(RepositoryTaskOutlineNode.LABEL_DESCRIPTION)
&& descriptionTextViewer.isEditable()) {
focusDescription();
} else if (data != null) {
select(data, highlight);
}
}
part.setFocus();
}
}
};
private AbstractTask repositoryTask;
private Set<RepositoryTaskAttribute> changedAttributes;
private Menu menu;
private SynchronizeEditorAction synchronizeEditorAction;
private ToggleTaskActivationAction activateAction;
private Action historyAction;
private Action clearOutgoingAction;
private Action openBrowserAction;
private NewSubTaskAction newSubTaskAction;
private Control lastFocusControl;
private boolean localChange = false;
/**
* Call upon change to attribute value
*
* @param attribute
* changed attribute
*/
protected boolean attributeChanged(RepositoryTaskAttribute attribute) {
if (attribute == null) {
return false;
}
changedAttributes.add(attribute);
markDirty(true);
validateInput();
return true;
}
@Override
public void init(IEditorSite site, IEditorInput input) {
if (!(input instanceof RepositoryTaskEditorInput)) {
return;
}
initTaskEditor(site, (RepositoryTaskEditorInput) input);
if (taskData != null) {
editorInput.setToolTipText(taskData.getLabel());
taskOutlineModel = RepositoryTaskOutlineNode.parseBugReport(taskData);
}
hasAttributeChanges = hasVisibleAttributeChanges();
TasksUiInternal.getTaskList().addChangeListener(TASKLIST_CHANGE_LISTENER);
}
protected void initTaskEditor(IEditorSite site, RepositoryTaskEditorInput input) {
changedAttributes = new HashSet<RepositoryTaskAttribute>();
editorInput = input;
repositoryTask = editorInput.getRepositoryTask();
repository = editorInput.getRepository();
taskData = editorInput.getTaskData();
if (repositoryTask != null) {
TasksUiPlugin.getTaskDataManager().setTaskRead(repositoryTask, true);
}
connector = (AbstractLegacyRepositoryConnector) TasksUi.getRepositoryManager().getRepositoryConnector(
repository.getConnectorKind());
commentSortIsUp = TasksUiPlugin.getDefault().getPreferenceStore().getBoolean(
PREF_SORT_ORDER_PREFIX + repository.getConnectorKind());
setSite(site);
setInput(input);
isDirty = false;
}
public AbstractTask getRepositoryTask() {
return repositoryTask;
}
// @Override
// public void markDirty(boolean dirty) {
// if (repositoryTask != null) {
// repositoryTask.setDirty(dirty);
// }
// super.markDirty(dirty);
// }
// /**
// * Update task state
// */
// protected void updateTask() {
// if (taskData == null)
// return;
// if (repositoryTask != null) {
// TasksUiPlugin.getSynchronizationManager().saveOutgoing(repositoryTask, changedAttributes);
// }
// if (parentEditor != null) {
// parentEditor.notifyTaskChanged();
// }
// markDirty(false);
// }
protected abstract void validateInput();
/**
* Creates a new <code>AbstractTaskEditor</code>.
*/
public AbstractRepositoryTaskEditor(FormEditor editor) {
// set the scroll increments so the editor scrolls normally with the
// scroll wheel
super(editor, "id", "label"); //$NON-NLS-1$ //$NON-NLS-2$
}
protected boolean supportsCommentSort() {
return false;
}
@Override
protected void createFormContent(final IManagedForm managedForm) {
IThemeManager themeManager = getSite().getWorkbenchWindow().getWorkbench().getThemeManager();
colorIncoming = themeManager.getCurrentTheme().getColorRegistry().get(CommonThemes.COLOR_INCOMING_BACKGROUND);
super.createFormContent(managedForm);
form = managedForm.getForm();
form.setRedraw(false);
try {
refreshEnabled = false;
toolkit = managedForm.getToolkit();
registerDropListener(form);
editorComposite = form.getBody();
GridLayout editorLayout = new GridLayout();
editorComposite.setLayout(editorLayout);
editorComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
if (taskData != null) {
createSections();
}
AbstractRepositoryConnectorUi connectorUi = TasksUiPlugin.getConnectorUi(repository.getConnectorKind());
if (connectorUi == null) {
parentEditor.setMessage("The editor may not be fully loaded", IMessageProvider.INFORMATION,
new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
refreshEditor();
}
});
}
updateHeaderControls();
if (summaryTextViewer != null) {
summaryTextViewer.getTextWidget().setFocus();
}
form.setRedraw(true);
} finally {
refreshEnabled = true;
}
form.reflow(true);
}
private void updateHeaderControls() {
if (taskData == null) {
parentEditor.setMessage(
"Task data not available. Press synchronize button (right) to retrieve latest data.",
IMessageProvider.WARNING, new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
if (synchronizeEditorAction != null) {
synchronizeEditorAction.run();
}
}
});
}
getParentEditor().updateHeaderToolBar();
}
/**
* Override for customizing the toolbar.
*
* @since 2.1 (NOTE: likely to change for 3.0)
*/
public void fillToolBar(IToolBarManager toolBarManager) {
ControlContribution repositoryLabelControl = new ControlContribution("Title") { //$NON-NLS-1$
@Override
protected Control createControl(Composite parent) {
Composite composite = toolkit.createComposite(parent);
composite.setLayout(new RowLayout());
composite.setBackground(null);
String label = repository.getRepositoryLabel();
if (label.indexOf("//") != -1) {
label = label.substring((repository.getRepositoryUrl().indexOf("//") + 2));
}
Hyperlink link = new Hyperlink(composite, SWT.NONE);
link.setText(label);
link.setFont(TITLE_FONT);
link.setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
link.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
TasksUiUtil.openEditRepositoryWizard(repository);
}
});
return composite;
}
};
toolBarManager.add(repositoryLabelControl);
if ((taskData != null && !taskData.isNew()) || repositoryTask != null) {
synchronizeEditorAction = new SynchronizeEditorAction();
synchronizeEditorAction.selectionChanged(new StructuredSelection(this));
toolBarManager.add(synchronizeEditorAction);
}
if (taskData != null && !taskData.isNew()) {
if (repositoryTask != null) {
clearOutgoingAction = new ClearOutgoingAction(
Collections.singletonList((IRepositoryElement) repositoryTask));
if (clearOutgoingAction.isEnabled()) {
toolBarManager.add(clearOutgoingAction);
}
newSubTaskAction = new NewSubTaskAction();
newSubTaskAction.selectionChanged(newSubTaskAction, new StructuredSelection(getRepositoryTask()));
if (newSubTaskAction.isEnabled()) {
toolBarManager.add(newSubTaskAction);
}
}
if (getHistoryUrl() != null) {
historyAction = new Action() {
@Override
public void run() {
TasksUiUtil.openUrl(getHistoryUrl());
}
};
historyAction.setImageDescriptor(TasksUiImages.TASK_REPOSITORY_HISTORY);
historyAction.setToolTipText(LABEL_HISTORY);
toolBarManager.add(historyAction);
}
if (connector != null) {
String taskUrl = connector.getTaskUrl(taskData.getRepositoryUrl(), taskData.getTaskKey());
if (taskUrl == null && repositoryTask != null && TasksUiInternal.hasValidUrl(repositoryTask)) {
taskUrl = repositoryTask.getUrl();
}
final String taskUrlToOpen = taskUrl;
if (taskUrlToOpen != null) {
openBrowserAction = new Action() {
@Override
public void run() {
TasksUiUtil.openUrl(taskUrlToOpen);
}
};
openBrowserAction.setImageDescriptor(CommonImages.BROWSER_OPEN_TASK);
openBrowserAction.setToolTipText("Open with Web Browser");
toolBarManager.add(openBrowserAction);
}
}
}
}
private void createSections() {
createSummaryLayout(editorComposite);
Composite attribComp = createAttributeSection();
createAttributeLayout(attribComp);
createCustomAttributeLayout(attribComp);
createRelatedBugsSection(editorComposite);
if (showAttachments) {
createAttachmentLayout(editorComposite);
}
createDescriptionLayout(editorComposite);
createCommentLayout(editorComposite);
createNewCommentLayout(editorComposite);
Composite bottomComposite = toolkit.createComposite(editorComposite);
bottomComposite.setLayout(new GridLayout(2, false));
GridDataFactory.fillDefaults().grab(true, false).applyTo(bottomComposite);
createActionsLayout(bottomComposite);
createPeopleLayout(bottomComposite);
bottomComposite.pack(true);
getSite().getPage().addSelectionListener(selectionListener);
getSite().setSelectionProvider(selectionProvider);
FocusListener listener = new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
lastFocusControl = (Control) e.widget;
}
};
addFocusListener(editorComposite, listener);
}
private void addFocusListener(Composite composite, FocusListener listener) {
Control[] children = composite.getChildren();
for (Control control : children) {
if ((control instanceof Text) || (control instanceof Button) || (control instanceof Combo)
|| (control instanceof CCombo) || (control instanceof Tree) || (control instanceof Table)
|| (control instanceof Spinner) || (control instanceof Link) || (control instanceof List)
|| (control instanceof TabFolder) || (control instanceof CTabFolder)
|| (control instanceof Hyperlink) || (control instanceof FilteredTree)
|| (control instanceof StyledText)) {
control.addFocusListener(listener);
}
if (control instanceof Composite) {
addFocusListener((Composite) control, listener);
}
}
}
private void removeSections() {
menu = editorComposite.getMenu();
setMenu(editorComposite, null);
for (Control control : editorComposite.getChildren()) {
control.dispose();
}
lastFocusControl = null;
}
/**
* @author Raphael Ackermann (modifications) (bug 195514)
*/
protected void createSummaryLayout(Composite composite) {
addSummaryText(composite);
if (summaryTextViewer != null) {
summaryTextViewer.prependVerifyKeyListener(new TabVerifyKeyListener());
}
headerInfoComposite = toolkit.createComposite(composite);
GridLayout headerLayout = new GridLayout(11, false);
headerLayout.verticalSpacing = 1;
headerLayout.marginHeight = 1;
headerLayout.marginHeight = 1;
headerLayout.marginWidth = 1;
headerLayout.horizontalSpacing = 6;
headerInfoComposite.setLayout(headerLayout);
RepositoryTaskAttribute statusAtribute = taskData.getAttribute(RepositoryTaskAttribute.STATUS);
addNameValue(headerInfoComposite, statusAtribute);
toolkit.paintBordersFor(headerInfoComposite);
RepositoryTaskAttribute priorityAttribute = taskData.getAttribute(RepositoryTaskAttribute.PRIORITY);
addNameValue(headerInfoComposite, priorityAttribute);
String idLabel = (repositoryTask != null) ? repositoryTask.getTaskKey() : taskData.getTaskKey();
if (idLabel != null) {
Composite nameValue = toolkit.createComposite(headerInfoComposite);
nameValue.setLayout(new GridLayout(2, false));
Label label = toolkit.createLabel(nameValue, "ID:");// .setFont(TITLE_FONT);
label.setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
// toolkit.createText(nameValue, idLabel, SWT.FLAT | SWT.READ_ONLY);
Text text = new Text(nameValue, SWT.FLAT | SWT.READ_ONLY);
toolkit.adapt(text, true, true);
text.setText(idLabel);
}
String openedDateString = "";
String modifiedDateString = "";
final AbstractTaskDataHandler taskDataManager = connector.getLegacyTaskDataHandler();
if (taskDataManager != null) {
Date created = taskData.getAttributeFactory().getDateForAttributeType(
RepositoryTaskAttribute.DATE_CREATION, taskData.getCreated());
openedDateString = created != null ? new SimpleDateFormat(HEADER_DATE_FORMAT).format(created) : "";
Date modified = taskData.getAttributeFactory().getDateForAttributeType(
RepositoryTaskAttribute.DATE_MODIFIED, taskData.getLastModified());
modifiedDateString = modified != null ? new SimpleDateFormat(HEADER_DATE_FORMAT).format(modified) : "";
}
RepositoryTaskAttribute creationAttribute = taskData.getAttribute(RepositoryTaskAttribute.DATE_CREATION);
if (creationAttribute != null) {
Composite nameValue = toolkit.createComposite(headerInfoComposite);
nameValue.setLayout(new GridLayout(2, false));
createLabel(nameValue, creationAttribute);
// toolkit.createText(nameValue, openedDateString, SWT.FLAT |
// SWT.READ_ONLY);
Text text = new Text(nameValue, SWT.FLAT | SWT.READ_ONLY);
toolkit.adapt(text, true, true);
text.setText(openedDateString);
}
RepositoryTaskAttribute modifiedAttribute = taskData.getAttribute(RepositoryTaskAttribute.DATE_MODIFIED);
if (modifiedAttribute != null) {
Composite nameValue = toolkit.createComposite(headerInfoComposite);
nameValue.setLayout(new GridLayout(2, false));
createLabel(nameValue, modifiedAttribute);
// toolkit.createText(nameValue, modifiedDateString, SWT.FLAT |
// SWT.READ_ONLY);
Text text = new Text(nameValue, SWT.FLAT | SWT.READ_ONLY);
toolkit.adapt(text, true, true);
text.setText(modifiedDateString);
}
}
private void addNameValue(Composite parent, RepositoryTaskAttribute attribute) {
Composite nameValue = toolkit.createComposite(parent);
nameValue.setLayout(new GridLayout(2, false));
if (attribute != null) {
createLabel(nameValue, attribute);
createTextField(nameValue, attribute, SWT.FLAT | SWT.READ_ONLY);
}
}
/**
* Utility method to create text field sets background to TaskListColorsAndFonts.COLOR_ATTRIBUTE_CHANGED if
* attribute has changed.
*
* @param composite
* @param attribute
* @param style
*/
protected Text createTextField(Composite composite, RepositoryTaskAttribute attribute, int style) {
String value;
if (attribute == null || attribute.getValue() == null) {
value = "";
} else {
value = attribute.getValue();
}
final Text text;
if ((SWT.READ_ONLY & style) == SWT.READ_ONLY) {
text = new Text(composite, style);
toolkit.adapt(text, true, true);
text.setData(FormToolkit.KEY_DRAW_BORDER, Boolean.FALSE);
text.setText(value);
} else {
text = toolkit.createText(composite, value, style);
}
if (attribute != null && !attribute.isReadOnly()) {
text.setData(attribute);
text.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
String newValue = text.getText();
RepositoryTaskAttribute attribute = (RepositoryTaskAttribute) text.getData();
attribute.setValue(newValue);
attributeChanged(attribute);
}
});
}
if (hasChanged(attribute)) {
text.setBackground(colorIncoming);
}
return text;
}
protected Label createLabel(Composite composite, RepositoryTaskAttribute attribute) {
Label label;
if (hasOutgoingChange(attribute)) {
label = toolkit.createLabel(composite, "*" + attribute.getName());
} else {
label = toolkit.createLabel(composite, attribute.getName());
}
label.setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(label);
return label;
}
public String getSectionLabel(SECTION_NAME labelName) {
return labelName.getPrettyName();
}
protected Composite createAttributeSection() {
attributesSection = createSection(editorComposite, getSectionLabel(SECTION_NAME.ATTRIBTUES_SECTION),
expandedStateAttributes || hasAttributeChanges);
Composite toolbarComposite = toolkit.createComposite(attributesSection);
toolbarComposite.setBackground(null);
RowLayout rowLayout = new RowLayout();
rowLayout.marginTop = 0;
rowLayout.marginBottom = 0;
toolbarComposite.setLayout(rowLayout);
UpdateRepositoryConfigurationAction repositoryConfigRefresh = new UpdateRepositoryConfigurationAction() {
@Override
public void performUpdate(TaskRepository repository, AbstractRepositoryConnector connector,
IProgressMonitor monitor) {
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
setGlobalBusy(true);
}
});
try {
super.performUpdate(repository, connector, monitor);
if (connector != null) {
TasksUiInternal.synchronizeTask(connector, repositoryTask, true, new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
refreshEditor();
}
});
}
});
}
} catch (Exception e) {
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
refreshEditor();
}
});
}
}
};
repositoryConfigRefresh.setImageDescriptor(TasksUiImages.REPOSITORY_SYNCHRONIZE_SMALL);
repositoryConfigRefresh.selectionChanged(new StructuredSelection(repository));
repositoryConfigRefresh.setToolTipText("Refresh Attributes");
ToolBarManager barManager = new ToolBarManager(SWT.FLAT);
barManager.add(repositoryConfigRefresh);
repositoryConfigRefresh.setEnabled(supportsRefreshAttributes());
barManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
barManager.createControl(toolbarComposite);
attributesSection.setTextClient(toolbarComposite);
// Attributes Composite- this holds all the combo fields and text fields
final Composite attribComp = toolkit.createComposite(attributesSection);
attribComp.addListener(SWT.MouseDown, new Listener() {
public void handleEvent(Event event) {
Control focus = event.display.getFocusControl();
if (focus instanceof Text && ((Text) focus).getEditable() == false) {
form.setFocus();
}
}
});
attributesSection.setClient(attribComp);
GridLayout attributesLayout = new GridLayout();
attributesLayout.numColumns = 4;
attributesLayout.horizontalSpacing = 5;
attributesLayout.verticalSpacing = 4;
attribComp.setLayout(attributesLayout);
GridData attributesData = new GridData(GridData.FILL_BOTH);
attributesData.horizontalSpan = 1;
attributesData.grabExcessVerticalSpace = false;
attribComp.setLayoutData(attributesData);
return attribComp;
}
/**
* @since 2.2
*/
protected boolean supportsRefreshAttributes() {
return true;
}
/**
* Creates the attribute section, which contains most of the basic attributes of the task (some of which are
* editable).
*/
protected void createAttributeLayout(Composite attributesComposite) {
int numColumns = ((GridLayout) attributesComposite.getLayout()).numColumns;
int currentCol = 1;
for (final RepositoryTaskAttribute attribute : taskData.getAttributes()) {
if (attribute.isHidden()) {
continue;
}
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
data.horizontalSpan = 1;
if (attribute.hasOptions() && !attribute.isReadOnly()) {
Label label = createLabel(attributesComposite, attribute);
GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(label);
final CCombo attributeCombo = new CCombo(attributesComposite, SWT.FLAT | SWT.READ_ONLY);
toolkit.adapt(attributeCombo, true, true);
attributeCombo.setFont(TEXT_FONT);
attributeCombo.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);
if (hasChanged(attribute)) {
attributeCombo.setBackground(colorIncoming);
}
attributeCombo.setLayoutData(data);
List<String> values = attribute.getOptions();
if (values != null) {
for (String val : values) {
if (val != null) {
attributeCombo.add(val);
}
}
}
String value = attribute.getValue();
if (value == null) {
value = "";
}
if (attributeCombo.indexOf(value) != -1) {
attributeCombo.select(attributeCombo.indexOf(value));
}
attributeCombo.clearSelection();
attributeCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
if (attributeCombo.getSelectionIndex() > -1) {
String sel = attributeCombo.getItem(attributeCombo.getSelectionIndex());
attribute.setValue(sel);
attributeChanged(attribute);
attributeCombo.clearSelection();
}
}
});
currentCol += 2;
} else {
Label label = createLabel(attributesComposite, attribute);
GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(label);
Composite textFieldComposite = toolkit.createComposite(attributesComposite);
GridLayout textLayout = new GridLayout();
textLayout.marginWidth = 1;
textLayout.marginHeight = 2;
textFieldComposite.setLayout(textLayout);
GridData textData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
textData.horizontalSpan = 1;
textData.widthHint = 135;
if (attribute.isReadOnly()) {
final Text text = createTextField(textFieldComposite, attribute, SWT.FLAT | SWT.READ_ONLY);
text.setLayoutData(textData);
} else {
final Text text = createTextField(textFieldComposite, attribute, SWT.FLAT);
// text.setFont(COMMENT_FONT);
text.setLayoutData(textData);
toolkit.paintBordersFor(textFieldComposite);
text.setData(attribute);
if (hasContentAssist(attribute)) {
ContentAssistCommandAdapter adapter = applyContentAssist(text,
createContentProposalProvider(attribute));
ILabelProvider propsalLabelProvider = createProposalLabelProvider(attribute);
if (propsalLabelProvider != null) {
adapter.setLabelProvider(propsalLabelProvider);
}
adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
}
}
currentCol += 2;
}
if (currentCol > numColumns) {
currentCol -= numColumns;
}
}
// make sure that we are in the first column
if (currentCol > 1) {
while (currentCol <= numColumns) {
toolkit.createLabel(attributesComposite, "");
currentCol++;
}
}
toolkit.paintBordersFor(attributesComposite);
}
/**
* Adds a related bugs section to the bug editor
*/
protected void createRelatedBugsSection(Composite composite) {
// Section relatedBugsSection = createSection(editorComposite, getSectionLabel(SECTION_NAME.RELATEDBUGS_SECTION));
// Composite relatedBugsComposite = toolkit.createComposite(relatedBugsSection);
// relatedBugsComposite.setLayout(new GridLayout(4, false));
// relatedBugsComposite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
// relatedBugsSection.setClient(relatedBugsComposite);
// relatedBugsSection.setExpanded(repositoryTask == null);
//
// List<AbstractDuplicateDetector> allCollectors = new ArrayList<AbstractDuplicateDetector>();
// if (getDuplicateSearchCollectorsList() != null) {
// allCollectors.addAll(getDuplicateSearchCollectorsList());
// }
// if (!allCollectors.isEmpty()) {
// duplicateDetectorLabel = new Label(relatedBugsComposite, SWT.LEFT);
// duplicateDetectorLabel.setText(LABEL_SELECT_DETECTOR);
//
// duplicateDetectorChooser = new CCombo(relatedBugsComposite, SWT.FLAT | SWT.READ_ONLY | SWT.BORDER);
//
// duplicateDetectorChooser.setLayoutData(GridDataFactory.swtDefaults().hint(150, SWT.DEFAULT).create());
// duplicateDetectorChooser.setFont(TEXT_FONT);
//
// Collections.sort(allCollectors, new Comparator<AbstractDuplicateDetector>() {
//
// public int compare(AbstractDuplicateDetector c1, AbstractDuplicateDetector c2) {
// return c1.getName().compareToIgnoreCase(c2.getName());
// }
//
// });
//
// for (AbstractDuplicateDetector detector : allCollectors) {
// duplicateDetectorChooser.add(detector.getName());
// }
//
// duplicateDetectorChooser.select(0);
// duplicateDetectorChooser.setEnabled(true);
// duplicateDetectorChooser.setData(allCollectors);
//
// if (allCollectors.size() > 0) {
//
// searchForDuplicates = toolkit.createButton(relatedBugsComposite, LABEL_SEARCH_DUPS, SWT.NONE);
// GridData searchDuplicatesButtonData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
// searchForDuplicates.setLayoutData(searchDuplicatesButtonData);
// searchForDuplicates.addListener(SWT.Selection, new Listener() {
// public void handleEvent(Event e) {
// searchForDuplicates();
// }
// });
// }
// } else {
// Label label = new Label(relatedBugsComposite, SWT.LEFT);
// label.setText(LABEL_NO_DETECTOR);
// }
}
/**
* @since 3.0
*/
protected AbstractLegacyDuplicateDetector getDuplicateDetector(String name) {
String duplicateDetectorName = name.equals("default") ? "Stack Trace" : name;
Set<AbstractLegacyDuplicateDetector> allDetectors = getDuplicateDetectorList();
for (AbstractLegacyDuplicateDetector detector : allDetectors) {
if (detector.getName().equals(duplicateDetectorName)) {
return detector;
}
}
// didn't find it
return null;
}
/**
* @since 3.0
*/
protected Set<AbstractLegacyDuplicateDetector> getDuplicateDetectorList() {
Set<AbstractLegacyDuplicateDetector> duplicateDetectors = new HashSet<AbstractLegacyDuplicateDetector>();
for (AbstractDuplicateDetector abstractDuplicateDetector : TasksUiPlugin.getDefault()
.getDuplicateSearchCollectorsList()) {
if (abstractDuplicateDetector instanceof AbstractLegacyDuplicateDetector
&& (abstractDuplicateDetector.getConnectorKind() == null || abstractDuplicateDetector.getConnectorKind()
.equals(getConnector().getConnectorKind()))) {
duplicateDetectors.add((AbstractLegacyDuplicateDetector) abstractDuplicateDetector);
}
}
return duplicateDetectors;
}
public boolean searchForDuplicates() {
String duplicateDetectorName = duplicateDetectorChooser.getItem(duplicateDetectorChooser.getSelectionIndex());
AbstractLegacyDuplicateDetector duplicateDetector = getDuplicateDetector(duplicateDetectorName);
if (duplicateDetector != null) {
RepositoryQuery duplicatesQuery = duplicateDetector.getDuplicatesQuery(repository, taskData);
if (duplicatesQuery != null) {
SearchHitCollector collector = new SearchHitCollector(TasksUiInternal.getTaskList(), repository,
duplicatesQuery);
NewSearchUI.runQueryInBackground(collector);
return true;
}
}
return false;
}
/**
* Adds content assist to the given text field.
*
* @param text
* text field to decorate.
* @param proposalProvider
* instance providing content proposals
* @return the ContentAssistCommandAdapter for the field.
*/
protected ContentAssistCommandAdapter applyContentAssist(Text text, IContentProposalProvider proposalProvider) {
ControlDecoration controlDecoration = new ControlDecoration(text, (SWT.TOP | SWT.LEFT));
controlDecoration.setMarginWidth(0);
controlDecoration.setShowHover(true);
controlDecoration.setShowOnlyOnFocus(true);
FieldDecoration contentProposalImage = FieldDecorationRegistry.getDefault().getFieldDecoration(
FieldDecorationRegistry.DEC_CONTENT_PROPOSAL);
controlDecoration.setImage(contentProposalImage.getImage());
TextContentAdapter textContentAdapter = new TextContentAdapter();
ContentAssistCommandAdapter adapter = new ContentAssistCommandAdapter(text, textContentAdapter,
proposalProvider, "org.eclipse.ui.edit.text.contentAssist.proposals", new char[0]);
IBindingService bindingService = (IBindingService) PlatformUI.getWorkbench().getService(IBindingService.class);
controlDecoration.setDescriptionText(NLS.bind("Content Assist Available ({0})",
bindingService.getBestActiveBindingFormattedFor(adapter.getCommandId())));
return adapter;
}
/**
* Creates an IContentProposalProvider to provide content assist proposals for the given attribute.
*
* @param attribute
* attribute for which to provide content assist.
* @return the IContentProposalProvider.
*/
protected IContentProposalProvider createContentProposalProvider(RepositoryTaskAttribute attribute) {
return new PersonProposalProvider(repositoryTask, taskData);
}
/**
* Creates an IContentProposalProvider to provide content assist proposals for the given operation.
*
* @param operation
* operation for which to provide content assist.
* @return the IContentProposalProvider.
*/
protected IContentProposalProvider createContentProposalProvider(RepositoryOperation operation) {
return new PersonProposalProvider(repositoryTask, taskData);
}
protected ILabelProvider createProposalLabelProvider(RepositoryTaskAttribute attribute) {
return new PersonProposalLabelProvider();
}
protected ILabelProvider createProposalLabelProvider(RepositoryOperation operation) {
return new PersonProposalLabelProvider();
}
/**
* Called to check if there's content assist available for the given attribute.
*
* @param attribute
* the attribute
* @return true if content assist is available for the specified attribute.
*/
protected boolean hasContentAssist(RepositoryTaskAttribute attribute) {
return false;
}
/**
* Called to check if there's content assist available for the given operation.
*
* @param operation
* the operation
* @return true if content assist is available for the specified operation.
*/
protected boolean hasContentAssist(RepositoryOperation operation) {
return false;
}
/**
* Adds a text editor with spell checking enabled to display and edit the task's summary.
*
* @author Raphael Ackermann (modifications) (bug 195514)
* @param attributesComposite
* The composite to add the text editor to.
*/
protected void addSummaryText(Composite attributesComposite) {
Composite summaryComposite = toolkit.createComposite(attributesComposite);
GridLayout summaryLayout = new GridLayout(2, false);
summaryLayout.verticalSpacing = 0;
summaryLayout.marginHeight = 2;
summaryComposite.setLayout(summaryLayout);
GridDataFactory.fillDefaults().grab(true, false).applyTo(summaryComposite);
if (taskData != null) {
RepositoryTaskAttribute attribute = taskData.getAttribute(RepositoryTaskAttribute.SUMMARY);
if (attribute == null) {
taskData.setAttributeValue(RepositoryTaskAttribute.SUMMARY, "");
attribute = taskData.getAttribute(RepositoryTaskAttribute.SUMMARY);
}
final RepositoryTaskAttribute summaryAttribute = attribute;
summaryTextViewer = addTextEditor(repository, summaryComposite, attribute.getValue(), true, SWT.FLAT
| SWT.SINGLE);
Composite hiddenComposite = new Composite(summaryComposite, SWT.NONE);
hiddenComposite.setLayout(new GridLayout());
GridData hiddenLayout = new GridData();
hiddenLayout.exclude = true;
hiddenComposite.setLayoutData(hiddenLayout);
// bugg#210695 - work around for 2.0 api breakage
summaryText = new Text(hiddenComposite, SWT.NONE);
summaryText.setText(attribute.getValue());
summaryText.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
if (summaryTextViewer != null && !summaryTextViewer.getTextWidget().isDisposed()) {
String newValue = summaryText.getText();
String oldValue = summaryTextViewer.getTextWidget().getText();
if (!newValue.equals(oldValue)) {
summaryTextViewer.getTextWidget().setText(newValue);
summaryAttribute.setValue(newValue);
attributeChanged(summaryAttribute);
}
}
}
public void keyReleased(KeyEvent e) {
// ignore
}
});
summaryText.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
summaryTextViewer.getTextWidget().setFocus();
}
public void focusLost(FocusEvent e) {
// ignore
}
});
summaryTextViewer.setEditable(true);
summaryTextViewer.getTextWidget().setIndent(2);
GridDataFactory.fillDefaults().grab(true, false).applyTo(summaryTextViewer.getControl());
if (hasChanged(attribute)) {
summaryTextViewer.getTextWidget().setBackground(colorIncoming);
}
summaryTextViewer.getControl().setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);
summaryTextViewer.addTextListener(new ITextListener() {
public void textChanged(TextEvent event) {
String newValue = summaryTextViewer.getTextWidget().getText();
if (!newValue.equals(summaryAttribute.getValue())) {
summaryAttribute.setValue(newValue);
attributeChanged(summaryAttribute);
}
if (summaryText != null && !newValue.equals(summaryText.getText())) {
summaryText.setText(newValue);
}
}
});
}
toolkit.paintBordersFor(summaryComposite);
}
protected boolean supportsAttachmentDelete() {
return false;
}
protected void deleteAttachment(RepositoryAttachment attachment) {
}
protected void createAttachmentLayout(Composite composite) {
// TODO: expand to show new attachments
Section section = createSection(composite, getSectionLabel(SECTION_NAME.ATTACHMENTS_SECTION), false);
section.setText(section.getText() + " (" + taskData.getAttachments().size() + ")");
final Composite attachmentsComposite = toolkit.createComposite(section);
attachmentsComposite.setLayout(new GridLayout(1, false));
attachmentsComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
section.setClient(attachmentsComposite);
if (taskData.getAttachments().size() > 0) {
attachmentsTable = toolkit.createTable(attachmentsComposite, SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION);
attachmentsTable.setLinesVisible(true);
attachmentsTable.setHeaderVisible(true);
attachmentsTable.setLayout(new GridLayout());
GridData tableGridData = new GridData(SWT.FILL, SWT.FILL, true, true);
attachmentsTable.setLayoutData(tableGridData);
for (int i = 0; i < attachmentsColumns.length; i++) {
TableColumn column = new TableColumn(attachmentsTable, SWT.LEFT, i);
column.setText(attachmentsColumns[i]);
column.setWidth(attachmentsColumnWidths[i]);
}
attachmentsTable.getColumn(3).setAlignment(SWT.RIGHT);
attachmentsTableViewer = new TableViewer(attachmentsTable);
attachmentsTableViewer.setUseHashlookup(true);
attachmentsTableViewer.setColumnProperties(attachmentsColumns);
ColumnViewerToolTipSupport.enableFor(attachmentsTableViewer, ToolTip.NO_RECREATE);
final AbstractTaskDataHandler offlineHandler = connector.getLegacyTaskDataHandler();
if (offlineHandler != null) {
attachmentsTableViewer.setSorter(new ViewerSorter() {
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
RepositoryAttachment attachment1 = (RepositoryAttachment) e1;
RepositoryAttachment attachment2 = (RepositoryAttachment) e2;
Date created1 = taskData.getAttributeFactory().getDateForAttributeType(
RepositoryTaskAttribute.ATTACHMENT_DATE, attachment1.getDateCreated());
Date created2 = taskData.getAttributeFactory().getDateForAttributeType(
RepositoryTaskAttribute.ATTACHMENT_DATE, attachment2.getDateCreated());
if (created1 != null && created2 != null) {
return created1.compareTo(created2);
} else if (created1 == null && created2 != null) {
return -1;
} else if (created1 != null && created2 == null) {
return 1;
} else {
return 0;
}
}
});
}
attachmentsTableViewer.setContentProvider(new AttachmentsTableContentProvider(taskData.getAttachments()));
attachmentsTableViewer.setLabelProvider(new AttachmentTableLabelProvider(this, new LabelProvider(),
PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator()));
attachmentsTableViewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
if (!event.getSelection().isEmpty()) {
StructuredSelection selection = (StructuredSelection) event.getSelection();
RepositoryAttachment attachment = (RepositoryAttachment) selection.getFirstElement();
TasksUiUtil.openUrl(attachment.getUrl());
}
}
});
attachmentsTableViewer.setInput(taskData);
final Action openWithBrowserAction = new Action(LABEL_BROWSER) {
@Override
public void run() {
RepositoryAttachment attachment = (RepositoryAttachment) (((StructuredSelection) attachmentsTableViewer.getSelection()).getFirstElement());
if (attachment != null) {
TasksUiUtil.openUrl(attachment.getUrl());
}
}
};
final Action openWithDefaultAction = new Action(LABEL_DEFAULT_EDITOR) {
@Override
public void run() {
// browser shortcut
RepositoryAttachment attachment = (RepositoryAttachment) (((StructuredSelection) attachmentsTableViewer.getSelection()).getFirstElement());
if (attachment == null) {
return;
}
if (attachment.getContentType().endsWith(CTYPE_HTML)) {
TasksUiUtil.openUrl(attachment.getUrl());
return;
}
IStorageEditorInput input = new RepositoryAttachmentEditorInput(repository, attachment);
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
if (page == null) {
return;
}
IEditorDescriptor desc = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(
input.getName());
try {
page.openEditor(input, desc.getId());
} catch (PartInitException e) {
StatusHandler.log(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN,
"Unable to open editor for: " + attachment.getDescription(), e));
}
}
};
final Action openWithTextEditorAction = new Action(LABEL_TEXT_EDITOR) {
@Override
public void run() {
RepositoryAttachment attachment = (RepositoryAttachment) (((StructuredSelection) attachmentsTableViewer.getSelection()).getFirstElement());
IStorageEditorInput input = new RepositoryAttachmentEditorInput(repository, attachment);
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
if (page == null) {
return;
}
try {
page.openEditor(input, "org.eclipse.ui.DefaultTextEditor");
} catch (PartInitException e) {
StatusHandler.log(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN,
"Unable to open editor for: " + attachment.getDescription(), e));
}
}
};
final Action saveAction = new Action(LABEL_SAVE) {
@Override
public void run() {
ITaskAttachment attachment = (ITaskAttachment) (((StructuredSelection) attachmentsTableViewer.getSelection()).getFirstElement());
/* Launch Browser */
FileDialog fileChooser = new FileDialog(attachmentsTable.getShell(), SWT.SAVE);
String fname = attachment.getFileName();
// Default name if none is found
if (fname.equals("")) {
String ctype = attachment.getContentType();
if (ctype.endsWith(CTYPE_HTML)) {
fname = ATTACHMENT_DEFAULT_NAME + ".html";
} else if (ctype.startsWith(CTYPE_TEXT)) {
fname = ATTACHMENT_DEFAULT_NAME + ".txt";
} else if (ctype.endsWith(CTYPE_OCTET_STREAM)) {
fname = ATTACHMENT_DEFAULT_NAME;
} else if (ctype.endsWith(CTYPE_ZIP)) {
fname = ATTACHMENT_DEFAULT_NAME + "." + CTYPE_ZIP;
} else {
fname = ATTACHMENT_DEFAULT_NAME + "." + ctype.substring(ctype.indexOf("/") + 1);
}
}
fileChooser.setFileName(fname);
String filePath = fileChooser.open();
// Check if the dialog was canceled or an error occurred
if (filePath == null) {
return;
}
DownloadAttachmentJob job = new DownloadAttachmentJob(attachment, new File(filePath));
job.setUser(true);
job.schedule();
}
};
final Action copyURLToClipAction = new Action(LABEL_COPY_URL_TO_CLIPBOARD) {
@Override
public void run() {
RepositoryAttachment attachment = (RepositoryAttachment) (((StructuredSelection) attachmentsTableViewer.getSelection()).getFirstElement());
Clipboard clip = new Clipboard(PlatformUI.getWorkbench().getDisplay());
clip.setContents(new Object[] { attachment.getUrl() },
new Transfer[] { TextTransfer.getInstance() });
clip.dispose();
}
};
final Action copyToClipAction = new Action(LABEL_COPY_TO_CLIPBOARD) {
@Override
public void run() {
RepositoryAttachment attachment = (RepositoryAttachment) (((StructuredSelection) attachmentsTableViewer.getSelection()).getFirstElement());
CopyAttachmentToClipboardJob job = new CopyAttachmentToClipboardJob(attachment);
job.setUser(true);
job.schedule();
}
};
final MenuManager popupMenu = new MenuManager();
final Menu menu = popupMenu.createContextMenu(attachmentsTable);
attachmentsTable.setMenu(menu);
final MenuManager openMenu = new MenuManager("Open With");
popupMenu.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
popupMenu.removeAll();
IStructuredSelection selection = (IStructuredSelection) attachmentsTableViewer.getSelection();
if (selection.isEmpty()) {
return;
}
if (selection.size() == 1) {
RepositoryAttachment att = (RepositoryAttachment) ((StructuredSelection) selection).getFirstElement();
// reinitialize open menu
popupMenu.add(openMenu);
openMenu.removeAll();
IStorageEditorInput input = new RepositoryAttachmentEditorInput(repository, att);
IEditorDescriptor desc = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(
input.getName());
if (desc != null) {
openMenu.add(openWithDefaultAction);
}
openMenu.add(openWithBrowserAction);
openMenu.add(openWithTextEditorAction);
popupMenu.add(new Separator());
popupMenu.add(saveAction);
popupMenu.add(copyURLToClipAction);
if (att.getContentType().startsWith(CTYPE_TEXT) || att.getContentType().endsWith("xml")) {
popupMenu.add(copyToClipAction);
}
}
popupMenu.add(new Separator("actions"));
// TODO: use workbench mechanism for this?
ObjectActionContributorManager.getManager().contributeObjectActions(
AbstractRepositoryTaskEditor.this, popupMenu, attachmentsTableViewer);
}
});
} else {
Label label = toolkit.createLabel(attachmentsComposite, "No attachments");
registerDropListener(label);
}
final Composite attachmentControlsComposite = toolkit.createComposite(attachmentsComposite);
attachmentControlsComposite.setLayout(new GridLayout(2, false));
attachmentControlsComposite.setLayoutData(new GridData(GridData.BEGINNING));
Button attachFileButton = toolkit.createButton(attachmentControlsComposite, AttachAction.LABEL, SWT.PUSH);
attachFileButton.setImage(WorkbenchImages.getImage(ISharedImages.IMG_OBJ_FILE));
Button attachScreenshotButton = toolkit.createButton(attachmentControlsComposite, AttachScreenshotAction.LABEL,
SWT.PUSH);
attachScreenshotButton.setImage(CommonImages.getImage(CommonImages.IMAGE_CAPTURE));
final ITask task = TasksUiInternal.getTaskList().getTask(repository.getRepositoryUrl(), taskData.getTaskId());
if (task == null) {
attachFileButton.setEnabled(false);
attachScreenshotButton.setEnabled(false);
}
attachFileButton.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
// ignore
}
public void widgetSelected(SelectionEvent e) {
AbstractTaskEditorAction attachFileAction = new AttachAction();
attachFileAction.selectionChanged(new StructuredSelection(task));
attachFileAction.setEditor(parentEditor);
attachFileAction.run();
}
});
attachScreenshotButton.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
// ignore
}
public void widgetSelected(SelectionEvent e) {
AttachScreenshotAction attachScreenshotAction = new AttachScreenshotAction();
attachScreenshotAction.selectionChanged(new StructuredSelection(task));
attachScreenshotAction.setEditor(parentEditor);
attachScreenshotAction.run();
}
});
Button deleteAttachmentButton = null;
if (supportsAttachmentDelete()) {
deleteAttachmentButton = toolkit.createButton(attachmentControlsComposite, "Delete Attachment...", SWT.PUSH);
deleteAttachmentButton.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
// ignore
}
public void widgetSelected(SelectionEvent e) {
ITask task = TasksUiInternal.getTaskList().getTask(repository.getRepositoryUrl(),
taskData.getTaskId());
if (task == null) {
// Should not happen
return;
}
if (AbstractRepositoryTaskEditor.this.isDirty
|| task.getSynchronizationState().equals(SynchronizationState.OUTGOING)) {
MessageDialog.openInformation(attachmentsComposite.getShell(),
"Task not synchronized or dirty editor",
"Commit edits or synchronize task before deleting attachments.");
return;
} else {
if (attachmentsTableViewer != null
&& attachmentsTableViewer.getSelection() != null
&& ((StructuredSelection) attachmentsTableViewer.getSelection()).getFirstElement() != null) {
RepositoryAttachment attachment = (RepositoryAttachment) (((StructuredSelection) attachmentsTableViewer.getSelection()).getFirstElement());
deleteAttachment(attachment);
submitToRepository();
}
}
}
});
}
registerDropListener(section);
registerDropListener(attachmentsComposite);
registerDropListener(attachFileButton);
if (supportsAttachmentDelete()) {
registerDropListener(deleteAttachmentButton);
}
}
private void registerDropListener(final Control control) {
DropTarget target = new DropTarget(control, DND.DROP_COPY | DND.DROP_DEFAULT);
final TextTransfer textTransfer = TextTransfer.getInstance();
final FileTransfer fileTransfer = FileTransfer.getInstance();
Transfer[] types = new Transfer[] { textTransfer, fileTransfer };
target.setTransfer(types);
// Adapted from eclipse.org DND Article by Veronika Irvine, IBM OTI Labs
// http://www.eclipse.org/articles/Article-SWT-DND/DND-in-SWT.html#_dt10D
target.addDropListener(new RepositoryTaskEditorDropListener(this, repository, taskData, fileTransfer,
textTransfer, control));
}
protected void createDescriptionLayout(Composite composite) {
Section descriptionSection = createSection(composite, getSectionLabel(SECTION_NAME.DESCRIPTION_SECTION));
final Composite sectionComposite = toolkit.createComposite(descriptionSection);
descriptionSection.setClient(sectionComposite);
GridLayout addCommentsLayout = new GridLayout();
addCommentsLayout.numColumns = 1;
sectionComposite.setLayout(addCommentsLayout);
RepositoryTaskAttribute attribute = taskData.getDescriptionAttribute();
if (attribute != null && !attribute.isReadOnly()) {
if (getRenderingEngine() != null) {
// composite with StackLayout to hold text editor and preview widget
Composite descriptionComposite = toolkit.createComposite(sectionComposite);
descriptionComposite.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);
GridData descriptionGridData = new GridData(GridData.FILL_BOTH);
descriptionGridData.widthHint = DESCRIPTION_WIDTH;
descriptionGridData.minimumHeight = DESCRIPTION_HEIGHT;
descriptionGridData.grabExcessHorizontalSpace = true;
descriptionComposite.setLayoutData(descriptionGridData);
final StackLayout descriptionLayout = new StackLayout();
descriptionComposite.setLayout(descriptionLayout);
descriptionTextViewer = addTextEditor(repository, descriptionComposite, taskData.getDescription(),
true, SWT.FLAT | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL);
descriptionLayout.topControl = descriptionTextViewer.getControl();
descriptionComposite.layout();
// composite for edit/preview button
Composite buttonComposite = toolkit.createComposite(sectionComposite);
buttonComposite.setLayout(new GridLayout());
createPreviewButton(buttonComposite, descriptionTextViewer, descriptionComposite, descriptionLayout);
} else {
descriptionTextViewer = addTextEditor(repository, sectionComposite, taskData.getDescription(), true,
SWT.FLAT | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL);
final GridData gd = new GridData(GridData.FILL_HORIZONTAL);
// wrap text at this margin, see comment below
gd.widthHint = DESCRIPTION_WIDTH;
gd.minimumHeight = DESCRIPTION_HEIGHT;
gd.grabExcessHorizontalSpace = true;
descriptionTextViewer.getControl().setLayoutData(gd);
descriptionTextViewer.getControl().setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);
// the goal is to make the text viewer as big as the text so it does not require scrolling when first drawn
// on screen: when the descriptionTextViewer calculates its height it wraps the text according to the widthHint
// which does not reflect the actual size of the widget causing the widget to be taller
// (actual width > gd.widhtHint) or shorter (actual width < gd.widthHint) therefore the widthHint is tweaked
// once in the listener
sectionComposite.addControlListener(new ControlAdapter() {
private boolean first;
@Override
public void controlResized(ControlEvent e) {
if (!first) {
first = true;
int width = sectionComposite.getSize().x;
Point size = descriptionTextViewer.getTextWidget().computeSize(width, SWT.DEFAULT, true);
// limit width to parent widget
gd.widthHint = width;
// limit height to avoid dynamic resizing of the text widget
gd.heightHint = Math.min(Math.max(DESCRIPTION_HEIGHT, size.y), DESCRIPTION_HEIGHT * 4);
sectionComposite.layout();
}
}
});
}
descriptionTextViewer.setEditable(true);
descriptionTextViewer.addTextListener(new ITextListener() {
public void textChanged(TextEvent event) {
String newValue = descriptionTextViewer.getTextWidget().getText();
RepositoryTaskAttribute attribute = taskData.getAttribute(RepositoryTaskAttribute.DESCRIPTION);
if (attribute != null && !newValue.equals(attribute.getValue())) {
attribute.setValue(newValue);
attributeChanged(attribute);
taskData.setDescription(newValue);
}
}
});
StyledText styledText = descriptionTextViewer.getTextWidget();
controlBySelectableObject.put(taskData.getDescription(), styledText);
} else {
String text = taskData.getDescription();
descriptionTextViewer = addTextViewer(repository, sectionComposite, text, SWT.MULTI | SWT.WRAP);
StyledText styledText = descriptionTextViewer.getTextWidget();
GridDataFactory.fillDefaults().hint(DESCRIPTION_WIDTH, SWT.DEFAULT).applyTo(
descriptionTextViewer.getControl());
controlBySelectableObject.put(text, styledText);
}
if (hasChanged(taskData.getAttribute(RepositoryTaskAttribute.DESCRIPTION))) {
descriptionTextViewer.getTextWidget().setBackground(colorIncoming);
}
descriptionTextViewer.getTextWidget().addListener(SWT.FocusIn, new DescriptionListener());
Composite replyComp = toolkit.createComposite(descriptionSection);
replyComp.setLayout(new RowLayout());
replyComp.setBackground(null);
createReplyHyperlink(0, replyComp, taskData.getDescription());
descriptionSection.setTextClient(replyComp);
addDuplicateDetection(sectionComposite);
toolkit.paintBordersFor(sectionComposite);
if (descriptionTextViewer.isEditable()) {
descriptionSection.setExpanded(true);
}
}
protected ImageHyperlink createReplyHyperlink(final int commentNum, Composite composite, final String commentBody) {
final ImageHyperlink replyLink = new ImageHyperlink(composite, SWT.NULL);
toolkit.adapt(replyLink, true, true);
replyLink.setImage(CommonImages.getImage(TasksUiImages.COMMENT_REPLY));
replyLink.setToolTipText(LABEL_REPLY);
// no need for the background - transparency will take care of it
replyLink.setBackground(null);
// replyLink.setBackground(section.getTitleBarGradientBackground());
replyLink.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
String oldText = newCommentTextViewer.getDocument().get();
StringBuilder strBuilder = new StringBuilder();
strBuilder.append(oldText);
if (strBuilder.length() != 0) {
strBuilder.append("\n");
}
strBuilder.append(" (In reply to comment #" + commentNum + ")\n");
CommentQuoter quoter = new CommentQuoter();
strBuilder.append(quoter.quote(commentBody));
newCommentTextViewer.getDocument().set(strBuilder.toString());
RepositoryTaskAttribute attribute = taskData.getAttribute(RepositoryTaskAttribute.COMMENT_NEW);
if (attribute != null) {
attribute.setValue(strBuilder.toString());
attributeChanged(attribute);
}
selectNewComment();
newCommentTextViewer.getTextWidget().setCaretOffset(strBuilder.length());
}
});
return replyLink;
}
protected void addDuplicateDetection(Composite composite) {
List<AbstractLegacyDuplicateDetector> allCollectors = new ArrayList<AbstractLegacyDuplicateDetector>();
if (getDuplicateDetectorList() != null) {
allCollectors.addAll(getDuplicateDetectorList());
}
if (!allCollectors.isEmpty()) {
Section duplicatesSection = toolkit.createSection(composite, ExpandableComposite.TWISTIE
| ExpandableComposite.SHORT_TITLE_BAR);
duplicatesSection.setText(LABEL_SELECT_DETECTOR);
duplicatesSection.setLayout(new GridLayout());
GridDataFactory.fillDefaults().indent(SWT.DEFAULT, 15).applyTo(duplicatesSection);
Composite relatedBugsComposite = toolkit.createComposite(duplicatesSection);
relatedBugsComposite.setLayout(new GridLayout(4, false));
relatedBugsComposite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
duplicatesSection.setClient(relatedBugsComposite);
duplicateDetectorLabel = new Label(relatedBugsComposite, SWT.LEFT);
duplicateDetectorLabel.setText("Detector:");
duplicateDetectorChooser = new CCombo(relatedBugsComposite, SWT.FLAT | SWT.READ_ONLY);
toolkit.adapt(duplicateDetectorChooser, true, true);
duplicateDetectorChooser.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);
duplicateDetectorChooser.setFont(TEXT_FONT);
duplicateDetectorChooser.setLayoutData(GridDataFactory.swtDefaults().hint(150, SWT.DEFAULT).create());
Collections.sort(allCollectors, new Comparator<AbstractLegacyDuplicateDetector>() {
public int compare(AbstractLegacyDuplicateDetector c1, AbstractLegacyDuplicateDetector c2) {
return c1.getName().compareToIgnoreCase(c2.getName());
}
});
for (AbstractLegacyDuplicateDetector detector : allCollectors) {
duplicateDetectorChooser.add(detector.getName());
}
duplicateDetectorChooser.select(0);
duplicateDetectorChooser.setEnabled(true);
duplicateDetectorChooser.setData(allCollectors);
if (allCollectors.size() > 0) {
searchForDuplicates = toolkit.createButton(relatedBugsComposite, LABEL_SEARCH_DUPS, SWT.NONE);
GridData searchDuplicatesButtonData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
searchForDuplicates.setLayoutData(searchDuplicatesButtonData);
searchForDuplicates.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
searchForDuplicates();
}
});
}
// } else {
// Label label = new Label(composite, SWT.LEFT);
// label.setText(LABEL_NO_DETECTOR);
toolkit.paintBordersFor(relatedBugsComposite);
}
}
protected void createCustomAttributeLayout(Composite composite) {
// override
}
protected void createPeopleLayout(Composite composite) {
Section peopleSection = createSection(composite, getSectionLabel(SECTION_NAME.PEOPLE_SECTION));
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP).grab(true, true).applyTo(peopleSection);
Composite peopleComposite = toolkit.createComposite(peopleSection);
GridLayout layout = new GridLayout(2, false);
layout.marginWidth = 5;
peopleComposite.setLayout(layout);
addAssignedTo(peopleComposite);
boolean haveRealName = false;
RepositoryTaskAttribute reporterAttribute = taskData.getAttribute(RepositoryTaskAttribute.USER_REPORTER_NAME);
if (reporterAttribute == null) {
reporterAttribute = taskData.getAttribute(RepositoryTaskAttribute.USER_REPORTER);
} else {
haveRealName = true;
}
if (reporterAttribute != null) {
Label label = createLabel(peopleComposite, reporterAttribute);
GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(label);
Text textField = createTextField(peopleComposite, reporterAttribute, SWT.FLAT | SWT.READ_ONLY);
GridDataFactory.fillDefaults().grab(true, false).applyTo(textField);
if (haveRealName) {
textField.setText(textField.getText() + " <"
+ taskData.getAttributeValue(RepositoryTaskAttribute.USER_REPORTER) + ">");
}
}
addSelfToCC(peopleComposite);
addCCList(peopleComposite);
getManagedForm().getToolkit().paintBordersFor(peopleComposite);
peopleSection.setClient(peopleComposite);
peopleSection.setEnabled(true);
}
protected void addCCList(Composite attributesComposite) {
RepositoryTaskAttribute addCCattribute = taskData.getAttribute(RepositoryTaskAttribute.NEW_CC);
if (addCCattribute == null) {
// TODO: remove once TRAC is priming taskData with NEW_CC attribute
taskData.setAttributeValue(RepositoryTaskAttribute.NEW_CC, "");
addCCattribute = taskData.getAttribute(RepositoryTaskAttribute.NEW_CC);
}
if (addCCattribute != null) {
Label label = createLabel(attributesComposite, addCCattribute);
GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(label);
Text text = createTextField(attributesComposite, addCCattribute, SWT.FLAT);
GridDataFactory.fillDefaults().hint(150, SWT.DEFAULT).applyTo(text);
if (hasContentAssist(addCCattribute)) {
ContentAssistCommandAdapter adapter = applyContentAssist(text,
createContentProposalProvider(addCCattribute));
ILabelProvider propsalLabelProvider = createProposalLabelProvider(addCCattribute);
if (propsalLabelProvider != null) {
adapter.setLabelProvider(propsalLabelProvider);
}
adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
}
}
RepositoryTaskAttribute CCattribute = taskData.getAttribute(RepositoryTaskAttribute.USER_CC);
if (CCattribute != null) {
Label label = createLabel(attributesComposite, CCattribute);
GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.TOP).applyTo(label);
ccList = new org.eclipse.swt.widgets.List(attributesComposite, SWT.MULTI | SWT.V_SCROLL);// SWT.BORDER
ccList.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);
ccList.setFont(TEXT_FONT);
GridData ccListData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
ccListData.horizontalSpan = 1;
ccListData.widthHint = 150;
ccListData.heightHint = 95;
ccList.setLayoutData(ccListData);
if (hasChanged(taskData.getAttribute(RepositoryTaskAttribute.USER_CC))) {
ccList.setBackground(colorIncoming);
}
java.util.List<String> ccs = taskData.getCc();
if (ccs != null) {
for (String cc : ccs) {
ccList.add(cc);
}
}
java.util.List<String> removedCCs = taskData.getAttributeValues(RepositoryTaskAttribute.REMOVE_CC);
if (removedCCs != null) {
for (String item : removedCCs) {
int i = ccList.indexOf(item);
if (i != -1) {
ccList.select(i);
}
}
}
ccList.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
for (String cc : ccList.getItems()) {
int index = ccList.indexOf(cc);
if (ccList.isSelected(index)) {
List<String> remove = taskData.getAttributeValues(RepositoryTaskAttribute.REMOVE_CC);
if (!remove.contains(cc)) {
taskData.addAttributeValue(RepositoryTaskAttribute.REMOVE_CC, cc);
}
} else {
taskData.removeAttributeValue(RepositoryTaskAttribute.REMOVE_CC, cc);
}
}
attributeChanged(taskData.getAttribute(RepositoryTaskAttribute.REMOVE_CC));
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
toolkit.createLabel(attributesComposite, "");
label = toolkit.createLabel(attributesComposite, "(Select to remove)");
GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(label);
}
}
/**
* A listener for selection of the summary field.
*
* @since 2.1
*/
protected class DescriptionListener implements Listener {
public DescriptionListener() {
}
public void handleEvent(Event event) {
fireSelectionChanged(new SelectionChangedEvent(selectionProvider, new StructuredSelection(
new RepositoryTaskSelection(taskData.getTaskId(), taskData.getRepositoryUrl(),
taskData.getConnectorKind(), getSectionLabel(SECTION_NAME.DESCRIPTION_SECTION), true,
taskData.getSummary()))));
}
}
protected boolean supportsCommentDelete() {
return false;
}
protected void deleteComment(TaskComment comment) {
}
private boolean expandCommentSection() {
for (final TaskComment taskComment : taskData.getComments()) {
if ((repositoryTask != null && repositoryTask.getLastReadTimeStamp() == null)
|| editorInput.getOldTaskData() == null) {
return true;
} else if (isNewComment(taskComment)) {
return true;
}
}
if (taskData.getComments() == null || taskData.getComments().size() == 0) {
return false;
} else if (editorInput.getTaskData() != null && editorInput.getOldTaskData() != null) {
List<TaskComment> newTaskComments = editorInput.getTaskData().getComments();
List<TaskComment> oldTaskComments = editorInput.getOldTaskData().getComments();
if (newTaskComments == null || oldTaskComments == null) {
return true;
} else if (newTaskComments.size() != oldTaskComments.size()) {
return true;
}
}
return false;
}
protected void createCommentLayout(Composite composite) {
commentsSection = createSection(composite, getSectionLabel(SECTION_NAME.COMMENTS_SECTION),
expandCommentSection());
commentsSection.setText(commentsSection.getText() + " (" + taskData.getComments().size() + ")");
final Composite commentsSectionClient = toolkit.createComposite(commentsSection);
RowLayout rowLayout = new RowLayout();
rowLayout.pack = true;
rowLayout.marginLeft = 0;
rowLayout.marginBottom = 0;
rowLayout.marginTop = 0;
commentsSectionClient.setLayout(rowLayout);
commentsSectionClient.setBackground(null);
if (supportsCommentSort()) {
sortHyperlink = new ImageHyperlink(commentsSectionClient, SWT.NONE);
sortHyperlink.setToolTipText("Change order of comments");
toolkit.adapt(sortHyperlink, true, true);
sortHyperlink.setBackground(null);
sortHyperlink.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
sortComments();
}
});
sortHyperlinkState(false);
}
if (taskData.getComments().size() > 0) {
commentsSection.setEnabled(true);
commentsSection.addExpansionListener(new ExpansionAdapter() {
@Override
public void expansionStateChanged(ExpansionEvent e) {
if (commentsSection.isExpanded()) {
if (supportsCommentSort()) {
sortHyperlinkState(true);
}
} else {
if (supportsCommentSort()) {
sortHyperlinkState(false);
}
}
}
});
ImageHyperlink collapseAllHyperlink = new ImageHyperlink(commentsSectionClient, SWT.NONE);
collapseAllHyperlink.setToolTipText("Collapse All Comments");
toolkit.adapt(collapseAllHyperlink, true, true);
collapseAllHyperlink.setBackground(null);
collapseAllHyperlink.setImage(CommonImages.getImage(CommonImages.COLLAPSE_ALL_SMALL));
collapseAllHyperlink.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
hideAllComments();
}
});
ImageHyperlink expandAllHyperlink = new ImageHyperlink(commentsSectionClient, SWT.NONE);
expandAllHyperlink.setToolTipText("Expand All Comments");
toolkit.adapt(expandAllHyperlink, true, true);
expandAllHyperlink.setBackground(null);
expandAllHyperlink.setImage(CommonImages.getImage(CommonImages.EXPAND_ALL_SMALL));
expandAllHyperlink.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
BusyIndicator.showWhile(getControl().getDisplay(), new Runnable() {
public void run() {
revealAllComments();
if (supportsCommentSort()) {
sortHyperlinkState(true);
}
}
});
}
});
commentsSection.setTextClient(commentsSectionClient);
} else {
commentsSection.setEnabled(false);
}
// Additional (read-only) Comments Area
addCommentsComposite = toolkit.createComposite(commentsSection);
commentsSection.setClient(addCommentsComposite);
GridLayout addCommentsLayout = new GridLayout();
addCommentsLayout.numColumns = 1;
addCommentsComposite.setLayout(addCommentsLayout);
GridDataFactory.fillDefaults().grab(true, false).applyTo(addCommentsComposite);
boolean foundNew = false;
for (final TaskComment taskComment : taskData.getComments()) {
final ExpandableComposite expandableComposite = toolkit.createExpandableComposite(addCommentsComposite,
ExpandableComposite.TREE_NODE | ExpandableComposite.LEFT_TEXT_CLIENT_ALIGNMENT);
expandableComposite.setTitleBarForeground(toolkit.getColors().getColor(IFormColors.TITLE));
final Composite toolbarComp = toolkit.createComposite(expandableComposite);
rowLayout = new RowLayout();
rowLayout.pack = true;
rowLayout.marginLeft = 0;
rowLayout.marginBottom = 0;
rowLayout.marginTop = 0;
toolbarComp.setLayout(rowLayout);
toolbarComp.setBackground(null);
ImageHyperlink formHyperlink = toolkit.createImageHyperlink(toolbarComp, SWT.NONE);
formHyperlink.setBackground(null);
formHyperlink.setFont(expandableComposite.getFont());
formHyperlink.setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
if (taskComment.getAuthor() != null && taskComment.getAuthor().equalsIgnoreCase(repository.getUserName())) {
formHyperlink.setImage(CommonImages.getImage(CommonImages.PERSON_ME_NARROW));
} else {
formHyperlink.setImage(CommonImages.getImage(CommonImages.PERSON_NARROW));
}
String authorName = taskComment.getAuthorName();
String tooltipText = taskComment.getAuthor();
if (authorName.length() == 0) {
authorName = taskComment.getAuthor();
tooltipText = null;
}
formHyperlink.setText(taskComment.getNumber() + ": " + authorName + ", "
+ formatDate(taskComment.getCreated()));
formHyperlink.setToolTipText(tooltipText);
formHyperlink.setEnabled(true);
formHyperlink.setUnderlined(false);
final Composite toolbarButtonComp = toolkit.createComposite(toolbarComp);
RowLayout buttonCompLayout = new RowLayout();
buttonCompLayout.marginBottom = 0;
buttonCompLayout.marginTop = 0;
toolbarButtonComp.setLayout(buttonCompLayout);
toolbarButtonComp.setBackground(null);
if (supportsCommentDelete()) {
final ImageHyperlink deleteComment = new ImageHyperlink(toolbarButtonComp, SWT.NULL);
toolkit.adapt(deleteComment, true, true);
deleteComment.setImage(CommonImages.getImage(CommonImages.REMOVE));
deleteComment.setToolTipText("Remove");
deleteComment.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
deleteComment(taskComment);
submitToRepository();
}
});
}
final ImageHyperlink replyLink = createReplyHyperlink(taskComment.getNumber(), toolbarButtonComp,
taskComment.getText());
formHyperlink.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
toggleExpandableComposite(!expandableComposite.isExpanded(), expandableComposite);
}
@Override
public void linkEntered(HyperlinkEvent e) {
replyLink.setUnderlined(true);
super.linkEntered(e);
}
@Override
public void linkExited(HyperlinkEvent e) {
replyLink.setUnderlined(false);
super.linkExited(e);
}
});
expandableComposite.setTextClient(toolbarComp);
toolbarButtonComp.setVisible(expandableComposite.isExpanded());
// HACK: This is necessary
// due to a bug in SWT's ExpandableComposite.
// 165803: Expandable bars should expand when clicking anywhere
// https://bugs.eclipse.org/bugs/show_bug.cgi?taskId=165803
expandableComposite.setData(toolbarButtonComp);
expandableComposite.setLayout(new GridLayout());
expandableComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
final Composite ecComposite = toolkit.createComposite(expandableComposite);
GridLayout ecLayout = new GridLayout();
ecLayout.marginHeight = 0;
ecLayout.marginBottom = 3;
ecLayout.marginLeft = 15;
ecComposite.setLayout(ecLayout);
ecComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
expandableComposite.setClient(ecComposite);
// code for outline
commentComposites.add(expandableComposite);
controlBySelectableObject.put(taskComment, expandableComposite);
expandableComposite.addExpansionListener(new ExpansionAdapter() {
@Override
public void expansionStateChanged(ExpansionEvent e) {
toolbarButtonComp.setVisible(expandableComposite.isExpanded());
TextViewer viewer = null;
if (e.getState() && expandableComposite.getData("viewer") == null) {
viewer = addTextViewer(repository, ecComposite, taskComment.getText().trim(), SWT.MULTI
| SWT.WRAP);
expandableComposite.setData("viewer", viewer.getTextWidget());
viewer.getTextWidget().addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
selectedComment = taskComment;
}
public void focusLost(FocusEvent e) {
selectedComment = null;
}
});
StyledText styledText = viewer.getTextWidget();
GridDataFactory.fillDefaults().hint(DESCRIPTION_WIDTH, SWT.DEFAULT).applyTo(styledText);
resetLayout();
} else {
// dispose viewer
if (expandableComposite.getData("viewer") instanceof StyledText) {
((StyledText) expandableComposite.getData("viewer")).dispose();
expandableComposite.setData("viewer", null);
}
resetLayout();
}
}
});
if ((repositoryTask != null && repositoryTask.getLastReadTimeStamp() == null)
|| editorInput.getOldTaskData() == null) {
// hit or lost task data, expose all comments
toggleExpandableComposite(true, expandableComposite);
foundNew = true;
} else if (isNewComment(taskComment)) {
expandableComposite.setBackground(colorIncoming);
toggleExpandableComposite(true, expandableComposite);
foundNew = true;
}
}
if (supportsCommentSort()) {
if (commentSortIsUp) {
commentSortIsUp = !commentSortIsUp;
sortComments();
} else {
sortHyperlinkState(commentSortEnable);
}
}
if (foundNew) {
if (supportsCommentSort()) {
sortHyperlinkState(true);
}
} else if (taskData.getComments() == null || taskData.getComments().size() == 0) {
if (supportsCommentSort()) {
sortHyperlinkState(false);
}
} else if (editorInput.getTaskData() != null && editorInput.getOldTaskData() != null) {
List<TaskComment> newTaskComments = editorInput.getTaskData().getComments();
List<TaskComment> oldTaskComments = editorInput.getOldTaskData().getComments();
if (newTaskComments == null || oldTaskComments == null) {
if (supportsCommentSort()) {
sortHyperlinkState(true);
}
} else if (newTaskComments.size() != oldTaskComments.size()) {
if (supportsCommentSort()) {
sortHyperlinkState(true);
}
}
}
}
public String formatDate(String dateString) {
return dateString;
}
private boolean isNewComment(TaskComment comment) {
// Simple test (will not reveal new comments if offline data was lost
if (editorInput.getOldTaskData() != null) {
return (comment.getNumber() > editorInput.getOldTaskData().getComments().size());
}
return false;
// OLD METHOD FOR DETERMINING NEW COMMENTS
// if (repositoryTask != null) {
// if (repositoryTask.getLastSyncDateStamp() == null) {
// // new hit
// return true;
// }
// AbstractRepositoryConnector connector = (AbstractRepositoryConnector)
// TasksUiPlugin.getRepositoryManager()
// .getRepositoryConnector(taskData.getRepositoryKind());
// AbstractTaskDataHandler offlineHandler = connector.getTaskDataHandler();
// if (offlineHandler != null) {
//
// Date lastSyncDate =
// taskData.getAttributeFactory().getDateForAttributeType(
// RepositoryTaskAttribute.DATE_MODIFIED,
// repositoryTask.getLastSyncDateStamp());
//
// if (lastSyncDate != null) {
//
// // reduce granularity to minutes
// Calendar calLastMod = Calendar.getInstance();
// calLastMod.setTimeInMillis(lastSyncDate.getTime());
// calLastMod.set(Calendar.SECOND, 0);
//
// Date commentDate =
// taskData.getAttributeFactory().getDateForAttributeType(
// RepositoryTaskAttribute.COMMENT_DATE, comment.getCreated());
// if (commentDate != null) {
//
// Calendar calComment = Calendar.getInstance();
// calComment.setTimeInMillis(commentDate.getTime());
// calComment.set(Calendar.SECOND, 0);
// if (calComment.after(calLastMod)) {
// return true;
// }
// }
// }
// }
// }
// return false;
}
/**
* Subclasses that support HTML preview of ticket description and comments override this method to return an
* instance of AbstractRenderingEngine
*
* @return <code>null</code> if HTML preview is not supported for the repository (default)
* @since 2.1
*/
protected AbstractRenderingEngine getRenderingEngine() {
return null;
}
protected void createNewCommentLayout(Composite composite) {
// Section newCommentSection = createSection(composite,
// getSectionLabel(SECTION_NAME.NEWCOMMENT_SECTION));
Section newCommentSection = toolkit.createSection(composite, ExpandableComposite.TITLE_BAR);
newCommentSection.setText(getSectionLabel(SECTION_NAME.NEWCOMMENT_SECTION));
newCommentSection.setLayout(new GridLayout());
newCommentSection.setLayoutData(new GridData(GridData.FILL_BOTH));
Composite newCommentsComposite = toolkit.createComposite(newCommentSection);
newCommentsComposite.setLayout(new GridLayout());
// HACK: new new comment attribute not created by connector, create one.
if (taskData.getAttribute(RepositoryTaskAttribute.COMMENT_NEW) == null) {
taskData.setAttributeValue(RepositoryTaskAttribute.COMMENT_NEW, "");
}
final RepositoryTaskAttribute attribute = taskData.getAttribute(RepositoryTaskAttribute.COMMENT_NEW);
if (getRenderingEngine() != null) {
// composite with StackLayout to hold text editor and preview widget
Composite editPreviewComposite = toolkit.createComposite(newCommentsComposite);
GridData editPreviewData = new GridData(GridData.FILL_BOTH);
editPreviewData.widthHint = DESCRIPTION_WIDTH;
editPreviewData.minimumHeight = DESCRIPTION_HEIGHT;
editPreviewData.grabExcessHorizontalSpace = true;
editPreviewComposite.setLayoutData(editPreviewData);
editPreviewComposite.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);
final StackLayout editPreviewLayout = new StackLayout();
editPreviewComposite.setLayout(editPreviewLayout);
newCommentTextViewer = addTextEditor(repository, editPreviewComposite, attribute.getValue(), true, SWT.FLAT
| SWT.MULTI | SWT.WRAP | SWT.V_SCROLL);
editPreviewLayout.topControl = newCommentTextViewer.getControl();
editPreviewComposite.layout();
// composite for edit/preview button
Composite buttonComposite = toolkit.createComposite(newCommentsComposite);
buttonComposite.setLayout(new GridLayout());
createPreviewButton(buttonComposite, newCommentTextViewer, editPreviewComposite, editPreviewLayout);
} else {
newCommentTextViewer = addTextEditor(repository, newCommentsComposite, attribute.getValue(), true, SWT.FLAT
| SWT.MULTI | SWT.WRAP | SWT.V_SCROLL);
GridData addCommentsTextData = new GridData(GridData.FILL_BOTH);
addCommentsTextData.widthHint = DESCRIPTION_WIDTH;
addCommentsTextData.minimumHeight = DESCRIPTION_HEIGHT;
addCommentsTextData.grabExcessHorizontalSpace = true;
newCommentTextViewer.getControl().setLayoutData(addCommentsTextData);
newCommentTextViewer.getControl().setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);
}
newCommentTextViewer.setEditable(true);
newCommentTextViewer.addTextListener(new ITextListener() {
public void textChanged(TextEvent event) {
String newValue = addCommentsTextBox.getText();
if (!newValue.equals(attribute.getValue())) {
attribute.setValue(newValue);
attributeChanged(attribute);
}
}
});
newCommentTextViewer.getTextWidget().addListener(SWT.FocusIn, new NewCommentListener());
addCommentsTextBox = newCommentTextViewer.getTextWidget();
newCommentSection.setClient(newCommentsComposite);
toolkit.paintBordersFor(newCommentsComposite);
}
private Browser addBrowser(Composite parent, int style) {
Browser browser = new Browser(parent, style);
// intercept links to open tasks in rich editor and urls in separate browser
browser.addLocationListener(new LocationAdapter() {
@Override
public void changing(LocationEvent event) {
// ignore events that are caused by manually setting the contents of the browser
if (ignoreLocationEvents) {
return;
}
if (event.location != null && !event.location.startsWith("about")) {
event.doit = false;
IHyperlink link = new TaskUrlHyperlink(
new Region(0, 0)/* a fake region just to make constructor happy */, event.location);
link.open();
}
}
});
return browser;
}
/**
* Creates and sets up the button for switching between text editor and HTML preview. Subclasses that support HTML
* preview of new comments must override this method.
*
* @param buttonComposite
* the composite that holds the button
* @param editor
* the TextViewer for editing text
* @param previewBrowser
* the Browser for displaying the preview
* @param editorLayout
* the StackLayout of the <code>editorComposite</code>
* @param editorComposite
* the composite that holds <code>editor</code> and <code>previewBrowser</code>
* @since 2.1
*/
private void createPreviewButton(final Composite buttonComposite, final TextViewer editor,
final Composite editorComposite, final StackLayout editorLayout) {
// create an anonymous object that encapsulates the edit/preview button together with
// its state and String constants for button text;
// this implementation keeps all information needed to set up the button
// in this object and the method parameters, and this method is reused by both the
// description section and new comments section.
new Object() {
private static final String LABEL_BUTTON_PREVIEW = "Preview";
private static final String LABEL_BUTTON_EDIT = "Edit";
private int buttonState = 0;
private Button previewButton;
private Browser previewBrowser;
{
previewButton = toolkit.createButton(buttonComposite, LABEL_BUTTON_PREVIEW, SWT.PUSH);
GridData previewButtonData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
previewButtonData.widthHint = 100;
//previewButton.setImage(TasksUiImages.getImage(TasksUiImages.PREVIEW));
previewButton.setLayoutData(previewButtonData);
previewButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
if (previewBrowser == null) {
previewBrowser = addBrowser(editorComposite, SWT.NONE);
}
buttonState = ++buttonState % 2;
if (buttonState == 1) {
setText(previewBrowser, "Loading preview...");
previewWiki(previewBrowser, editor.getTextWidget().getText());
}
previewButton.setText(buttonState == 0 ? LABEL_BUTTON_PREVIEW : LABEL_BUTTON_EDIT);
editorLayout.topControl = (buttonState == 0 ? editor.getControl() : previewBrowser);
editorComposite.layout();
}
});
}
};
}
private void setText(Browser browser, String html) {
try {
ignoreLocationEvents = true;
browser.setText((html != null) ? html : "");
} finally {
ignoreLocationEvents = false;
}
}
private void previewWiki(final Browser browser, String sourceText) {
final class PreviewWikiJob extends Job {
private final String sourceText;
private String htmlText;
private IStatus jobStatus;
public PreviewWikiJob(String sourceText) {
super("Formatting Wiki Text");
if (sourceText == null) {
throw new IllegalArgumentException("source text must not be null");
}
this.sourceText = sourceText;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
AbstractRenderingEngine htmlRenderingEngine = getRenderingEngine();
if (htmlRenderingEngine == null) {
jobStatus = new RepositoryStatus(repository, IStatus.INFO, TasksUiPlugin.ID_PLUGIN,
RepositoryStatus.ERROR_INTERNAL, "The repository does not support HTML preview.");
return Status.OK_STATUS;
}
jobStatus = Status.OK_STATUS;
try {
htmlText = htmlRenderingEngine.renderAsHtml(repository, sourceText, monitor);
} catch (CoreException e) {
jobStatus = e.getStatus();
}
return Status.OK_STATUS;
}
public String getHtmlText() {
return htmlText;
}
public IStatus getStatus() {
return jobStatus;
}
}
final PreviewWikiJob job = new PreviewWikiJob(sourceText);
job.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(final IJobChangeEvent event) {
if (!form.isDisposed()) {
if (job.getStatus().isOK()) {
getPartControl().getDisplay().asyncExec(new Runnable() {
public void run() {
AbstractRepositoryTaskEditor.this.setText(browser, job.getHtmlText());
parentEditor.setMessage(null, IMessageProvider.NONE);
}
});
} else {
getPartControl().getDisplay().asyncExec(new Runnable() {
public void run() {
parentEditor.setMessage(job.getStatus().getMessage(), IMessageProvider.ERROR);
}
});
}
}
super.done(event);
}
});
job.setUser(true);
job.schedule();
}
/**
* Creates the button layout. This displays options and buttons at the bottom of the editor to allow actions to be
* performed on the bug.
*/
protected void createActionsLayout(Composite composite) {
Section section = createSection(composite, getSectionLabel(SECTION_NAME.ACTIONS_SECTION));
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP).grab(true, true).applyTo(section);
Composite buttonComposite = toolkit.createComposite(section);
GridLayout buttonLayout = new GridLayout();
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP).applyTo(buttonComposite);
buttonLayout.numColumns = 4;
buttonComposite.setLayout(buttonLayout);
addRadioButtons(buttonComposite);
addActionButtons(buttonComposite);
section.setClient(buttonComposite);
}
protected Section createSection(Composite composite, String title) {
return createSection(composite, title, true);
}
/**
* @Since 2.3
*/
private Section createSection(Composite composite, String title, boolean expandedState) {
int style = ExpandableComposite.TITLE_BAR | Section.TWISTIE;
if (expandedState) {
style |= ExpandableComposite.EXPANDED;
}
Section section = toolkit.createSection(composite, style);
section.setText(title);
section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
return section;
}
/**
* Adds buttons to this composite. Subclasses can override this method to provide different/additional buttons.
*
* @param buttonComposite
* Composite to add the buttons to.
*/
protected void addActionButtons(Composite buttonComposite) {
submitButton = toolkit.createButton(buttonComposite, LABEL_BUTTON_SUBMIT, SWT.NONE);
GridData submitButtonData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
submitButtonData.widthHint = 100;
submitButton.setImage(CommonImages.getImage(TasksUiImages.REPOSITORY_SUBMIT));
submitButton.setLayoutData(submitButtonData);
submitButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
submitToRepository();
}
});
setSubmitEnabled(true);
toolkit.createLabel(buttonComposite, " ");
ITask task = TasksUiInternal.getTaskList().getTask(repository.getRepositoryUrl(), taskData.getTaskId());
if (attachContextEnabled && task != null) {
addAttachContextButton(buttonComposite, task);
}
}
private void setSubmitEnabled(boolean enabled) {
if (submitButton != null && !submitButton.isDisposed()) {
submitButton.setEnabled(enabled);
if (enabled) {
submitButton.setToolTipText("Submit to " + this.repository.getRepositoryUrl());
}
}
}
/**
* Override to make hyperlink available. If not overridden hyperlink will simply not be displayed.
*
* @return url String form of url that points to task's past activity
*/
protected String getHistoryUrl() {
return null;
}
protected void saveTaskOffline(IProgressMonitor progressMonitor) {
if (taskData == null) {
return;
}
if (repositoryTask != null) {
try {
localChange = true;
TasksUiPlugin.getTaskDataManager().saveOutgoing(repositoryTask, changedAttributes);
} finally {
localChange = false;
}
}
markDirty(false);
}
// once the following bug is fixed, this check for first focus is probably
// not needed -> Bug# 172033: Restore editor focus
private boolean firstFocus = true;
@Override
public void setFocus() {
if (lastFocusControl != null && !lastFocusControl.isDisposed()) {
lastFocusControl.setFocus();
} else if (firstFocus && summaryTextViewer != null) {
summaryTextViewer.getControl().setFocus();
firstFocus = false;
}
}
/**
* Updates the title of the editor
*
*/
protected void updateEditorTitle() {
setPartName(editorInput.getName());
((TaskEditor) this.getEditor()).updateTitle(editorInput.getName());
}
@Override
public boolean isSaveAsAllowed() {
return false;
}
@Override
public void doSave(IProgressMonitor monitor) {
saveTaskOffline(monitor);
updateEditorTitle();
updateHeaderControls();
// fillToolBar(getParentEditor().getTopForm().getToolBarManager());
}
@Override
public void doSaveAs() {
// we don't save, so no need to implement
}
/**
* @return The composite for the whole editor.
*/
public Composite getEditorComposite() {
return editorComposite;
}
@Override
public void dispose() {
TasksUiInternal.getTaskList().removeChangeListener(TASKLIST_CHANGE_LISTENER);
getSite().getPage().removeSelectionListener(selectionListener);
if (waitCursor != null) {
waitCursor.dispose();
}
if (activateAction != null) {
activateAction.dispose();
}
super.dispose();
}
/**
* Fires a <code>SelectionChangedEvent</code> to all listeners registered under
* <code>selectionChangedListeners</code>.
*
* @param event
* The selection event.
*/
protected void fireSelectionChanged(final SelectionChangedEvent event) {
Object[] listeners = selectionChangedListeners.toArray();
for (Object listener : listeners) {
final ISelectionChangedListener l = (ISelectionChangedListener) listener;
SafeRunnable.run(new SafeRunnable() {
public void run() {
l.selectionChanged(event);
}
});
}
}
/*----------------------------------------------------------*
* CODE TO SCROLL TO A COMMENT OR OTHER PIECE OF TEXT
*----------------------------------------------------------*/
private final HashMap<Object, Control> controlBySelectableObject = new HashMap<Object, Control>();
private final List<ExpandableComposite> commentComposites = new ArrayList<ExpandableComposite>();
private StyledText addCommentsTextBox = null;
protected TextViewer descriptionTextViewer = null;
private void revealAllComments() {
try {
form.setRedraw(false);
refreshEnabled = false;
if (supportsCommentSort()) {
sortHyperlinkState(false);
}
if (commentsSection != null && !commentsSection.isExpanded()) {
commentsSection.setExpanded(true);
if (supportsCommentSort()) {
sortHyperlinkState(true);
}
}
for (ExpandableComposite composite : commentComposites) {
if (composite.isDisposed()) {
continue;
}
if (!composite.isExpanded()) {
toggleExpandableComposite(true, composite);
}
// Composite comp = composite.getParent();
// while (comp != null && !comp.isDisposed()) {
// if (comp instanceof ExpandableComposite && !comp.isDisposed()) {
// ExpandableComposite ex = (ExpandableComposite) comp;
// setExpandableCompositeState(true, ex);
//
// // HACK: This is necessary
// // due to a bug in SWT's ExpandableComposite.
// // 165803: Expandable bars should expand when clicking
// // anywhere
// // https://bugs.eclipse.org/bugs/show_bug.cgi?taskId=165803
// if (ex.getData() != null && ex.getData() instanceof Composite) {
// ((Composite) ex.getData()).setVisible(true);
// }
//
// break;
// }
// comp = comp.getParent();
// }
}
} finally {
refreshEnabled = true;
form.setRedraw(true);
}
resetLayout();
}
private void hideAllComments() {
try {
refreshEnabled = false;
for (ExpandableComposite composite : commentComposites) {
if (composite.isDisposed()) {
continue;
}
if (composite.isExpanded()) {
toggleExpandableComposite(false, composite);
}
// Composite comp = composite.getParent();
// while (comp != null && !comp.isDisposed()) {
// if (comp instanceof ExpandableComposite && !comp.isDisposed()) {
// ExpandableComposite ex = (ExpandableComposite) comp;
// setExpandableCompositeState(false, ex);
//
// // HACK: This is necessary
// // due to a bug in SWT's ExpandableComposite.
// // 165803: Expandable bars should expand when clicking anywhere
// // https://bugs.eclipse.org/bugs/show_bug.cgi?taskId=165803
// if (ex.getData() != null && ex.getData() instanceof Composite) {
// ((Composite) ex.getData()).setVisible(false);
// }
//
// break;
// }
// comp = comp.getParent();
// }
}
// if (commentsSection != null) {
// commentsSection.setExpanded(false);
// }
} finally {
refreshEnabled = true;
}
resetLayout();
}
private void sortHyperlinkState(boolean enabled) {
commentSortEnable = enabled;
if (sortHyperlink == null) {
return;
}
sortHyperlink.setEnabled(enabled);
if (enabled) {
if (commentSortIsUp) {
sortHyperlink.setImage(CommonImages.getImage(TasksUiImages.COMMENT_SORT_UP));
} else {
sortHyperlink.setImage(CommonImages.getImage(TasksUiImages.COMMENT_SORT_DOWN));
}
} else {
if (commentSortIsUp) {
sortHyperlink.setImage(CommonImages.getImage(TasksUiImages.COMMENT_SORT_UP_GRAY));
} else {
sortHyperlink.setImage(CommonImages.getImage(TasksUiImages.COMMENT_SORT_DOWN_GRAY));
}
}
}
private void sortComments() {
if (addCommentsComposite != null) {
Control[] commentControlList = addCommentsComposite.getChildren();
int commentControlListLength = commentControlList.length;
for (int i = 1; i < commentControlListLength; i++) {
commentControlList[commentControlListLength - i].moveAbove(commentControlList[0]);
}
}
commentSortIsUp = !commentSortIsUp;
TasksUiPlugin.getDefault().getPreferenceStore().setValue(
PREF_SORT_ORDER_PREFIX + repository.getConnectorKind(), commentSortIsUp);
sortHyperlinkState(commentSortEnable);
resetLayout();
}
/**
* Selects the given object in the editor.
*
* @param o
* The object to be selected.
* @param highlight
* Whether or not the object should be highlighted.
*/
public boolean select(Object o, boolean highlight) {
Control control = controlBySelectableObject.get(o);
if (control != null && !control.isDisposed()) {
// expand all children
if (control instanceof ExpandableComposite) {
ExpandableComposite ex = (ExpandableComposite) control;
if (!ex.isExpanded()) {
toggleExpandableComposite(true, ex);
}
}
// expand all parents of control
Composite comp = control.getParent();
while (comp != null) {
if (comp instanceof Section) {
if (!((Section) comp).isExpanded()) {
((Section) comp).setExpanded(true);
}
} else if (comp instanceof ExpandableComposite) {
ExpandableComposite ex = (ExpandableComposite) comp;
if (!ex.isExpanded()) {
toggleExpandableComposite(true, ex);
}
// HACK: This is necessary
// due to a bug in SWT's ExpandableComposite.
// 165803: Expandable bars should expand when clicking anywhere
// https://bugs.eclipse.org/bugs/show_bug.cgi?taskId=165803
if (ex.getData() != null && ex.getData() instanceof Composite) {
((Composite) ex.getData()).setVisible(true);
}
}
comp = comp.getParent();
}
focusOn(control, highlight);
} else if (o instanceof RepositoryTaskData) {
focusOn(null, highlight);
} else {
return false;
}
return true;
}
/**
* Programmatically expand the provided ExpandableComposite, using reflection to fire the expansion listeners (see
* bug#70358)
*
* @param comp
*/
private void toggleExpandableComposite(boolean expanded, ExpandableComposite comp) {
if (comp.isExpanded() != expanded) {
Method method = null;
try {
method = comp.getClass().getDeclaredMethod("programmaticToggleState");
method.setAccessible(true);
method.invoke(comp);
} catch (Exception e) {
// ignore
}
}
}
private void selectNewComment() {
focusOn(addCommentsTextBox, false);
}
/**
* @author Raphael Ackermann (bug 195514)
* @since 2.1
*/
protected void focusAttributes() {
if (attributesSection != null) {
focusOn(attributesSection, false);
}
}
private void focusDescription() {
if (descriptionTextViewer != null) {
focusOn(descriptionTextViewer.getTextWidget(), false);
}
}
/**
* Scroll to a specified piece of text
*
* @param selectionComposite
* The StyledText to scroll to
*/
private void focusOn(Control selectionComposite, boolean highlight) {
int pos = 0;
// if (previousText != null && !previousText.isDisposed()) {
// previousText.setsetSelection(0);
// }
// if (selectionComposite instanceof FormText)
// previousText = (FormText) selectionComposite;
if (selectionComposite != null) {
// if (highlight && selectionComposite instanceof FormText &&
// !selectionComposite.isDisposed())
// ((FormText) selectionComposite).set.setSelection(0, ((FormText)
// selectionComposite).getText().length());
// get the position of the text in the composite
pos = 0;
Control s = selectionComposite;
if (s.isDisposed()) {
return;
}
s.setEnabled(true);
s.setFocus();
s.forceFocus();
while (s != null && s != getEditorComposite()) {
if (!s.isDisposed()) {
pos += s.getLocation().y;
s = s.getParent();
}
}
pos = pos - 60; // form.getOrigin().y;
}
if (!form.getBody().isDisposed()) {
form.setOrigin(0, pos);
}
}
private RepositoryTaskOutlinePage outlinePage = null;
@SuppressWarnings("unchecked")
@Override
public Object getAdapter(Class adapter) {
return getAdapterDelgate(adapter);
}
public Object getAdapterDelgate(Class<?> adapter) {
if (IContentOutlinePage.class.equals(adapter)) {
if (outlinePage == null && editorInput != null && taskOutlineModel != null) {
outlinePage = new RepositoryTaskOutlinePage(taskOutlineModel);
}
return outlinePage;
}
return super.getAdapter(adapter);
}
public RepositoryTaskOutlinePage getOutline() {
return outlinePage;
}
private Button[] radios;
private Control[] radioOptions;
private Button attachContextButton;
private AbstractLegacyRepositoryConnector connector;
private Cursor waitCursor;
private boolean formBusy = false;
private Composite headerInfoComposite;
private Section attributesSection;
public void close() {
Display activeDisplay = getSite().getShell().getDisplay();
activeDisplay.asyncExec(new Runnable() {
public void run() {
if (getSite() != null && getSite().getPage() != null && !getManagedForm().getForm().isDisposed()) {
if (parentEditor != null) {
getSite().getPage().closeEditor(parentEditor, false);
} else {
getSite().getPage().closeEditor(AbstractRepositoryTaskEditor.this, false);
}
}
}
});
}
public void addAttributeListener(IRepositoryTaskAttributeListener listener) {
attributesListeners.add(listener);
}
public void removeAttributeListener(IRepositoryTaskAttributeListener listener) {
attributesListeners.remove(listener);
}
public void setParentEditor(TaskEditor parentEditor) {
this.parentEditor = parentEditor;
}
/**
* @since 2.1
*/
public TaskEditor getParentEditor() {
return parentEditor;
}
public RepositoryTaskOutlineNode getTaskOutlineModel() {
return taskOutlineModel;
}
public void setTaskOutlineModel(RepositoryTaskOutlineNode taskOutlineModel) {
this.taskOutlineModel = taskOutlineModel;
}
/**
* A listener for selection of the textbox where a new comment is entered in.
*/
private class NewCommentListener implements Listener {
public void handleEvent(Event event) {
fireSelectionChanged(new SelectionChangedEvent(selectionProvider, new StructuredSelection(
new RepositoryTaskSelection(taskData.getTaskId(), taskData.getRepositoryUrl(),
taskData.getConnectorKind(), getSectionLabel(SECTION_NAME.NEWCOMMENT_SECTION), false,
taskData.getSummary()))));
}
}
public Control getControl() {
return form;
}
public void setSummaryText(String text) {
if (summaryTextViewer != null && summaryTextViewer.getTextWidget() != null) {
summaryTextViewer.getTextWidget().setText(text);
}
}
public void setDescriptionText(String text) {
this.descriptionTextViewer.getDocument().set(text);
}
protected void addRadioButtons(Composite buttonComposite) {
int i = 0;
Button selected = null;
radios = new Button[taskData.getOperations().size()];
radioOptions = new Control[taskData.getOperations().size()];
for (RepositoryOperation o : taskData.getOperations()) {
radios[i] = toolkit.createButton(buttonComposite, "", SWT.RADIO);
radios[i].setFont(TEXT_FONT);
GridData radioData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
if (!o.hasOptions() && !o.isInput()) {
radioData.horizontalSpan = 4;
} else {
radioData.horizontalSpan = 1;
}
radioData.heightHint = 20;
String opName = o.getOperationName();
opName = opName.replaceAll("</.*>", "");
opName = opName.replaceAll("<.*>", "");
radios[i].setText(opName);
radios[i].setLayoutData(radioData);
// radios[i].setBackground(background);
radios[i].addSelectionListener(new RadioButtonListener());
if (o.hasOptions()) {
radioData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
radioData.horizontalSpan = 3;
radioData.heightHint = 20;
radioData.widthHint = RADIO_OPTION_WIDTH;
radioOptions[i] = new CCombo(buttonComposite, SWT.FLAT | SWT.READ_ONLY);
radioOptions[i].setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);
toolkit.adapt(radioOptions[i], true, true);
radioOptions[i].setFont(TEXT_FONT);
radioOptions[i].setLayoutData(radioData);
Object[] a = o.getOptionNames().toArray();
Arrays.sort(a);
for (int j = 0; j < a.length; j++) {
if (a[j] != null) {
((CCombo) radioOptions[i]).add((String) a[j]);
if (((String) a[j]).equals(o.getOptionSelection())) {
((CCombo) radioOptions[i]).select(j);
}
}
}
((CCombo) radioOptions[i]).addSelectionListener(new RadioButtonListener());
} else if (o.isInput()) {
radioData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
radioData.horizontalSpan = 3;
radioData.widthHint = RADIO_OPTION_WIDTH - 10;
String assignmentValue = "";
// NOTE: removed this because we now have content assit
// if (opName.equals(REASSIGN_BUG_TO)) {
// assignmentValue = repository.getUserName();
// }
radioOptions[i] = toolkit.createText(buttonComposite, assignmentValue);
radioOptions[i].setFont(TEXT_FONT);
radioOptions[i].setLayoutData(radioData);
// radioOptions[i].setBackground(background);
((Text) radioOptions[i]).setText(o.getInputValue());
((Text) radioOptions[i]).addModifyListener(new RadioButtonListener());
if (hasContentAssist(o)) {
ContentAssistCommandAdapter adapter = applyContentAssist((Text) radioOptions[i],
createContentProposalProvider(o));
ILabelProvider propsalLabelProvider = createProposalLabelProvider(o);
if (propsalLabelProvider != null) {
adapter.setLabelProvider(propsalLabelProvider);
}
adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
}
}
if (i == 0 || o.isChecked()) {
if (selected != null) {
selected.setSelection(false);
}
selected = radios[i];
radios[i].setSelection(true);
if (o.hasOptions() && o.getOptionSelection() != null) {
int j = 0;
for (String s : ((CCombo) radioOptions[i]).getItems()) {
if (s.compareTo(o.getOptionSelection()) == 0) {
((CCombo) radioOptions[i]).select(j);
}
j++;
}
}
taskData.setSelectedOperation(o);
}
i++;
}
toolkit.paintBordersFor(buttonComposite);
}
/**
* If implementing custom attributes you may need to override this method
*
* @return true if one or more attributes exposed in the editor have
*/
protected boolean hasVisibleAttributeChanges() {
if (taskData == null) {
return false;
}
for (RepositoryTaskAttribute attribute : taskData.getAttributes()) {
if (!attribute.isHidden()) {
if (hasChanged(attribute)) {
return true;
}
}
}
return false;
}
protected boolean hasOutgoingChange(RepositoryTaskAttribute newAttribute) {
return editorInput.getOldEdits().contains(newAttribute);
}
protected boolean hasChanged(RepositoryTaskAttribute newAttribute) {
if (newAttribute == null) {
return false;
}
RepositoryTaskData oldTaskData = editorInput.getOldTaskData();
if (oldTaskData == null) {
return false;
}
if (hasOutgoingChange(newAttribute)) {
return false;
}
RepositoryTaskAttribute oldAttribute = oldTaskData.getAttribute(newAttribute.getId());
if (oldAttribute == null) {
return true;
}
if (oldAttribute.getValue() != null && !oldAttribute.getValue().equals(newAttribute.getValue())) {
return true;
} else if (oldAttribute.getValues() != null && !oldAttribute.getValues().equals(newAttribute.getValues())) {
return true;
}
return false;
}
protected void addAttachContextButton(Composite buttonComposite, ITask task) {
attachContextButton = toolkit.createButton(buttonComposite, "Attach Context", SWT.CHECK);
attachContextButton.setImage(CommonImages.getImage(TasksUiImages.CONTEXT_ATTACH));
}
/**
* Creates a check box for adding the repository user to the cc list. Does nothing if the repository does not have a
* valid username, the repository user is the assignee, reporter or already on the the cc list.
*/
protected void addSelfToCC(Composite composite) {
if (repository.getUserName() == null) {
return;
}
RepositoryTaskAttribute owner = taskData.getAttribute(RepositoryTaskAttribute.USER_ASSIGNED);
if (owner != null && owner.getValue().indexOf(repository.getUserName()) != -1) {
return;
}
RepositoryTaskAttribute reporter = taskData.getAttribute(RepositoryTaskAttribute.USER_REPORTER);
if (reporter != null && reporter.getValue().indexOf(repository.getUserName()) != -1) {
return;
}
RepositoryTaskAttribute ccAttribute = taskData.getAttribute(RepositoryTaskAttribute.USER_CC);
if (ccAttribute != null && ccAttribute.getValues().contains(repository.getUserName())) {
return;
}
FormToolkit toolkit = getManagedForm().getToolkit();
toolkit.createLabel(composite, "");
final Button addSelfButton = toolkit.createButton(composite, "Add me to CC", SWT.CHECK);
addSelfButton.setSelection(RepositoryTaskAttribute.TRUE.equals(taskData.getAttributeValue(RepositoryTaskAttribute.ADD_SELF_CC)));
addSelfButton.setImage(CommonImages.getImage(CommonImages.PERSON));
addSelfButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (addSelfButton.getSelection()) {
taskData.setAttributeValue(RepositoryTaskAttribute.ADD_SELF_CC, RepositoryTaskAttribute.TRUE);
} else {
taskData.setAttributeValue(RepositoryTaskAttribute.ADD_SELF_CC, RepositoryTaskAttribute.FALSE);
}
RepositoryTaskAttribute attribute = taskData.getAttribute(RepositoryTaskAttribute.ADD_SELF_CC);
changedAttributes.add(attribute);
markDirty(true);
}
});
}
public boolean getAttachContext() {
if (attachContextButton == null || attachContextButton.isDisposed()) {
return false;
} else {
return attachContextButton.getSelection();
}
}
public void setExpandAttributeSection(boolean expandAttributeSection) {
this.expandedStateAttributes = expandAttributeSection;
}
public void setAttachContextEnabled(boolean attachContextEnabled) {
this.attachContextEnabled = attachContextEnabled;
// if (attachContextButton != null && attachContextButton.isEnabled()) {
// attachContextButton.setSelection(attachContext);
// }
}
@Override
public void showBusy(boolean busy) {
if (!getManagedForm().getForm().isDisposed() && busy != formBusy) {
// parentEditor.showBusy(busy);
if (synchronizeEditorAction != null) {
synchronizeEditorAction.setEnabled(!busy);
}
if (activateAction != null) {
activateAction.setEnabled(!busy);
}
if (openBrowserAction != null) {
openBrowserAction.setEnabled(!busy);
}
if (historyAction != null) {
historyAction.setEnabled(!busy);
}
if (newSubTaskAction != null) {
newSubTaskAction.setEnabled(!busy);
}
if (clearOutgoingAction != null) {
clearOutgoingAction.setEnabled(!busy);
}
if (submitButton != null && !submitButton.isDisposed()) {
submitButton.setEnabled(!busy);
}
setEnabledState(editorComposite, !busy);
formBusy = busy;
}
}
private void setEnabledState(Composite composite, boolean enabled) {
if (!composite.isDisposed()) {
composite.setEnabled(enabled);
for (Control control : composite.getChildren()) {
control.setEnabled(enabled);
if (control instanceof Composite) {
setEnabledState(((Composite) control), enabled);
}
}
}
}
public void setGlobalBusy(boolean busy) {
if (parentEditor != null) {
parentEditor.showBusy(busy);
} else {
showBusy(busy);
}
}
public void submitToRepository() {
setGlobalBusy(true);
if (isDirty()) {
saveTaskOffline(new NullProgressMonitor());
markDirty(false);
}
final boolean attachContext = getAttachContext();
Job submitJob = new Job(LABEL_JOB_SUBMIT) {
@Override
protected IStatus run(IProgressMonitor monitor) {
AbstractTask modifiedTask = null;
try {
monitor.beginTask("Submitting task", 3);
String taskId = connector.getLegacyTaskDataHandler().postTaskData(repository, taskData,
new SubProgressMonitor(monitor, 1));
final boolean isNew = taskData.isNew();
if (isNew) {
if (taskId != null) {
modifiedTask = updateSubmittedTask(taskId, new SubProgressMonitor(monitor, 1));
} else {
// null taskId, assume task could not be created...
throw new CoreException(
new RepositoryStatus(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN,
RepositoryStatus.ERROR_INTERNAL,
"Task could not be created. No additional information was provided by the connector."));
}
} else {
modifiedTask = (AbstractTask) TasksUiInternal.getTaskList().getTask(
repository.getRepositoryUrl(), taskData.getTaskId());
}
// Synchronization accounting...
if (modifiedTask != null) {
// Attach context if required
if (attachContext && connector.getAttachmentHandler() != null) {
AttachmentUtil.attachContext(connector.getAttachmentHandler(), repository, modifiedTask,
"", new SubProgressMonitor(monitor, 1));
}
modifiedTask.setSubmitting(true);
final AbstractTask finalModifiedTask = modifiedTask;
TasksUiInternal.synchronizeTask(connector, modifiedTask, true, new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
if (isNew) {
close();
TasksUiPlugin.getTaskDataManager().setTaskRead(finalModifiedTask, true);
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
TasksUiUtil.openTask(finalModifiedTask);
}
});
} else {
// PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
// public void run() {
// refreshEditor();
// }
// });
}
}
});
TasksUiPlugin.getSynchronizationScheduler().synchronize(repository);
} else {
close();
// For some reason the task wasn't retrieved.
// Try to
// open local then via web browser...
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
TasksUiUtil.openTask(repository.getRepositoryUrl(), taskData.getTaskId(),
connector.getTaskUrl(taskData.getRepositoryUrl(), taskData.getTaskId()));
}
});
}
return Status.OK_STATUS;
} catch (OperationCanceledException e) {
if (modifiedTask != null) {
modifiedTask.setSubmitting(false);
}
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
setGlobalBusy(false);// enableButtons();
}
});
return Status.CANCEL_STATUS;
} catch (CoreException e) {
if (modifiedTask != null) {
modifiedTask.setSubmitting(false);
}
return handleSubmitError(e);
} catch (Exception e) {
if (modifiedTask != null) {
modifiedTask.setSubmitting(false);
}
StatusHandler.fail(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, e.getMessage(), e));
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
setGlobalBusy(false);// enableButtons();
}
});
} finally {
monitor.done();
}
return Status.OK_STATUS;
}
};
IJobChangeListener jobListener = getSubmitJobListener();
if (jobListener != null) {
submitJob.addJobChangeListener(jobListener);
}
submitJob.schedule();
}
/**
* @since 2.0 If existing task editor, update contents in place
*/
public void refreshEditor() {
try {
if (!getManagedForm().getForm().isDisposed()) {
if (this.isDirty && taskData != null && !taskData.isNew()) {
this.doSave(new NullProgressMonitor());
}
setGlobalBusy(true);
changedAttributes.clear();
commentComposites.clear();
controlBySelectableObject.clear();
editorInput.refreshInput();
// Note: Marking read must run synchronously
// If not, incomings resulting from subsequent synchronization
// can get marked as read (without having been viewed by user
if (repositoryTask != null) {
try {
refreshing = true;
TasksUiPlugin.getTaskDataManager().setTaskRead(repositoryTask, true);
} finally {
refreshing = false;
}
}
this.setInputWithNotify(this.getEditorInput());
this.init(this.getEditorSite(), this.getEditorInput());
// Header must be updated after init is called to task data is available
updateHeaderControls();
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
if (editorComposite != null && !editorComposite.isDisposed()) {
if (taskData != null) {
updateEditorTitle();
menu = editorComposite.getMenu();
removeSections();
editorComposite.setMenu(menu);
createSections();
form.reflow(true);
// setFormHeaderLabel();
markDirty(false);
parentEditor.setMessage(null, 0);
AbstractRepositoryTaskEditor.this.getEditor().setActivePage(
AbstractRepositoryTaskEditor.this.getId());
// Activate editor disabled: bug#179078
// AbstractTaskEditor.this.getEditor().getEditorSite().getPage().activate(
// AbstractTaskEditor.this);
// TODO: expand sections that were previously
// expanded
if (taskOutlineModel != null && outlinePage != null
&& !outlinePage.getControl().isDisposed()) {
outlinePage.getOutlineTreeViewer().setInput(taskOutlineModel);
outlinePage.getOutlineTreeViewer().refresh(true);
}
// if (repositoryTask != null) {
// TasksUiPlugin.getTaskDataManager().setTaskRead(repositoryTask, true);
// }
setSubmitEnabled(true);
}
}
}
});
} else {
// Editor possibly closed as part of submit, mark read
// Note: Marking read must run synchronously
// If not, incomings resulting from subsequent synchronization
// can get marked as read (without having been viewed by user
if (repositoryTask != null) {
TasksUiPlugin.getTaskDataManager().setTaskRead(repositoryTask, true);
}
}
} finally {
if (!getManagedForm().getForm().isDisposed()) {
setGlobalBusy(false);
}
}
}
/**
* Used to prevent form menu from being disposed when disposing elements on the form during refresh
*/
private void setMenu(Composite comp, Menu menu) {
if (!comp.isDisposed()) {
comp.setMenu(null);
for (Control child : comp.getChildren()) {
child.setMenu(null);
if (child instanceof Composite) {
setMenu((Composite) child, menu);
}
}
}
}
protected IJobChangeListener getSubmitJobListener() {
return null;
}
protected AbstractTaskCategory getCategory() {
return null;
}
protected IStatus handleSubmitError(final CoreException exception) {
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
if (form != null && !form.isDisposed()) {
if (exception.getStatus().getCode() == RepositoryStatus.ERROR_IO) {
parentEditor.setMessage(ERROR_NOCONNECTIVITY, IMessageProvider.ERROR);
StatusHandler.log(exception.getStatus());
} else if (exception.getStatus().getCode() == RepositoryStatus.REPOSITORY_COMMENT_REQUIRED) {
TasksUiInternal.displayStatus("Comment required", exception.getStatus());
if (!getManagedForm().getForm().isDisposed() && newCommentTextViewer != null
&& !newCommentTextViewer.getControl().isDisposed()) {
newCommentTextViewer.getControl().setFocus();
}
} else if (exception.getStatus().getCode() == RepositoryStatus.ERROR_REPOSITORY_LOGIN) {
if (TasksUiUtil.openEditRepositoryWizard(repository) == MessageDialog.OK) {
submitToRepository();
return;
}
} else {
TasksUiInternal.displayStatus("Submit failed", exception.getStatus());
}
setGlobalBusy(false);
}
}
});
return Status.OK_STATUS;
}
protected AbstractTask updateSubmittedTask(String postResult, IProgressMonitor monitor) throws CoreException {
final AbstractTask newTask = (AbstractTask) TasksUiInternal.createTask(repository, postResult, monitor);
if (newTask != null) {
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
if (getCategory() != null) {
TasksUiInternal.getTaskList().addTask(newTask, getCategory());
}
}
});
}
return newTask;
}
/**
* Class to handle the selection change of the radio buttons.
*/
private class RadioButtonListener implements SelectionListener, ModifyListener {
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
public void widgetSelected(SelectionEvent e) {
Button selected = null;
for (Button radio : radios) {
if (radio.getSelection()) {
selected = radio;
}
}
// determine the operation to do to the bug
for (int i = 0; i < radios.length; i++) {
if (radios[i] != e.widget && radios[i] != selected) {
radios[i].setSelection(false);
}
if (e.widget == radios[i]) {
RepositoryOperation o = taskData.getOperation(radios[i].getText());
taskData.setSelectedOperation(o);
markDirty(true);
} else if (e.widget == radioOptions[i]) {
RepositoryOperation o = taskData.getOperation(radios[i].getText());
o.setOptionSelection(((CCombo) radioOptions[i]).getItem(((CCombo) radioOptions[i]).getSelectionIndex()));
if (taskData.getSelectedOperation() != null) {
taskData.getSelectedOperation().setChecked(false);
}
o.setChecked(true);
taskData.setSelectedOperation(o);
radios[i].setSelection(true);
if (selected != null && selected != radios[i]) {
selected.setSelection(false);
}
markDirty(true);
}
}
validateInput();
}
public void modifyText(ModifyEvent e) {
Button selected = null;
for (Button radio : radios) {
if (radio.getSelection()) {
selected = radio;
}
}
// determine the operation to do to the bug
for (int i = 0; i < radios.length; i++) {
if (radios[i] != e.widget && radios[i] != selected) {
radios[i].setSelection(false);
}
if (e.widget == radios[i]) {
RepositoryOperation o = taskData.getOperation(radios[i].getText());
taskData.setSelectedOperation(o);
markDirty(true);
} else if (e.widget == radioOptions[i]) {
RepositoryOperation o = taskData.getOperation(radios[i].getText());
o.setInputValue(((Text) radioOptions[i]).getText());
if (taskData.getSelectedOperation() != null) {
taskData.getSelectedOperation().setChecked(false);
}
o.setChecked(true);
taskData.setSelectedOperation(o);
radios[i].setSelection(true);
if (selected != null && selected != radios[i]) {
selected.setSelection(false);
}
markDirty(true);
}
}
validateInput();
}
}
public AbstractRepositoryConnector getConnector() {
return connector;
}
public void setShowAttachments(boolean showAttachments) {
this.showAttachments = showAttachments;
}
public String getCommonDateFormat() {
return HEADER_DATE_FORMAT;
}
public Color getColorIncoming() {
return colorIncoming;
}
/**
* @see #select(Object, boolean)
*/
public void addSelectableControl(Object item, Control control) {
controlBySelectableObject.put(item, control);
}
/**
* @see #addSelectableControl(Object, Control)
*/
public void removeSelectableControl(Object item) {
controlBySelectableObject.remove(item);
}
/**
* This method allow you to overwrite the generation of the form area for "assigned to" in the peopleLayout.<br>
* <br>
* The overwrite is used for Bugzilla Versions > 3.0
*
* @since 2.1
* @author Frank Becker (bug 198027)
*/
protected void addAssignedTo(Composite peopleComposite) {
boolean haveRealName = false;
RepositoryTaskAttribute assignedAttribute = taskData.getAttribute(RepositoryTaskAttribute.USER_ASSIGNED_NAME);
if (assignedAttribute == null) {
assignedAttribute = taskData.getAttribute(RepositoryTaskAttribute.USER_ASSIGNED);
} else {
haveRealName = true;
}
if (assignedAttribute != null) {
Label label = createLabel(peopleComposite, assignedAttribute);
GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(label);
Text textField;
if (assignedAttribute.isReadOnly()) {
textField = createTextField(peopleComposite, assignedAttribute, SWT.FLAT | SWT.READ_ONLY);
} else {
textField = createTextField(peopleComposite, assignedAttribute, SWT.FLAT);
ContentAssistCommandAdapter adapter = applyContentAssist(textField,
createContentProposalProvider(assignedAttribute));
ILabelProvider propsalLabelProvider = createProposalLabelProvider(assignedAttribute);
if (propsalLabelProvider != null) {
adapter.setLabelProvider(propsalLabelProvider);
}
adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
}
GridDataFactory.fillDefaults().grab(true, false).applyTo(textField);
if (haveRealName) {
textField.setText(textField.getText() + " <"
+ taskData.getAttributeValue(RepositoryTaskAttribute.USER_ASSIGNED) + ">");
}
}
}
/**
* force a re-layout of entire form
*/
protected void resetLayout() {
if (refreshEnabled) {
form.layout(true, true);
form.reflow(true);
}
}
/**
* @since 2.3
*/
protected Hyperlink createTaskListHyperlink(Composite parent, final String taskId, final String taskUrl,
final AbstractTask task) {
TaskHyperlink hyperlink = new TaskHyperlink(parent, SWT.SHORT | getManagedForm().getToolkit().getOrientation());
getManagedForm().getToolkit().adapt(hyperlink, true, true);
getManagedForm().getToolkit().getHyperlinkGroup().add(hyperlink);
hyperlink.setTask(task);
if (task == null) {
hyperlink.setText(taskId);
}
hyperlink.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
if (task != null) {
TasksUiInternal.refreshAndOpenTaskListElement(task);
} else {
TasksUiUtil.openTask(repository.getRepositoryUrl(), taskId, taskUrl);
}
}
});
return hyperlink;
}
}