diff options
author | Frank Becker | 2015-07-22 17:08:46 +0000 |
---|---|---|
committer | Frank Becker | 2015-07-31 03:20:51 +0000 |
commit | eff1cccfaa7d3a6dca543d273e094ba3464bffbc (patch) | |
tree | 720391fd438458c4fedc3bbcc27c4d8b39ee6cda | |
parent | 869a056a29aac2a817adb0b2ce02b1bbe1d07a89 (diff) | |
download | org.eclipse.mylyn.tasks-eff1cccfaa7d3a6dca543d273e094ba3464bffbc.tar.gz org.eclipse.mylyn.tasks-eff1cccfaa7d3a6dca543d273e094ba3464bffbc.tar.xz org.eclipse.mylyn.tasks-eff1cccfaa7d3a6dca543d273e094ba3464bffbc.zip |
414360: create UI classes for the schema for AbstractRepositoryQueryPage
(provisional version)
Change-Id: I7d72728509546efd85dd334000acab991893a5b5
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=414360
5 files changed, 540 insertions, 1 deletions
diff --git a/org.eclipse.mylyn.tasks.ui/META-INF/MANIFEST.MF b/org.eclipse.mylyn.tasks.ui/META-INF/MANIFEST.MF index a98edf8dd..e8e6b72d3 100644 --- a/org.eclipse.mylyn.tasks.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.mylyn.tasks.ui/META-INF/MANIFEST.MF @@ -35,7 +35,8 @@ Require-Bundle: org.eclipse.ui, com.google.guava;bundle-version="15.0.0" Bundle-ActivationPolicy: lazy Bundle-Vendor: %Bundle-Vendor -Export-Package: org.eclipse.mylyn.internal.tasks.ui;x-internal:=true, +Export-Package: org.eclipse.mylyn.internal.provisional.tasks.ui.wizards;x-internal:=true, + org.eclipse.mylyn.internal.tasks.ui;x-internal:=true, org.eclipse.mylyn.internal.tasks.ui.actions;x-internal:=true, org.eclipse.mylyn.internal.tasks.ui.commands;x-internal:=true, org.eclipse.mylyn.internal.tasks.ui.compare;x-internal:=true, diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/provisional/tasks/ui/wizards/QueryPageDetails.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/provisional/tasks/ui/wizards/QueryPageDetails.java new file mode 100644 index 000000000..62263ea8b --- /dev/null +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/provisional/tasks/ui/wizards/QueryPageDetails.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2015 Frank Becker 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: + * Frank Becker - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.provisional.tasks.ui.wizards; + +public class QueryPageDetails { + private final boolean needsTitle; + + private final String queryUrlPart; + + private final String pageTitle; + + private final String pageDescription; + + private final String urlPattern; + + private final String queryAttributeName; + + public QueryPageDetails(boolean needsTitle, String queryUrlPart, String pageTitle, String pageDescription, + String urlPattern, String queryAttributeName) { + super(); + this.needsTitle = needsTitle; + this.queryUrlPart = queryUrlPart; + this.pageTitle = pageTitle; + this.pageDescription = pageDescription; + this.urlPattern = urlPattern; + this.queryAttributeName = queryAttributeName; + } + + public boolean needsTitle() { + return needsTitle; + } + + public String getQueryUrlPart() { + return queryUrlPart; + } + + public String getPageTitle() { + return pageTitle; + } + + public String getPageDescription() { + return pageDescription; + } + + public String getUrlPattern() { + return urlPattern; + } + + public String getQueryAttributeName() { + return queryAttributeName; + } + +} diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/provisional/tasks/ui/wizards/QueryPageFilter.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/provisional/tasks/ui/wizards/QueryPageFilter.java new file mode 100644 index 000000000..aadd6cadd --- /dev/null +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/provisional/tasks/ui/wizards/QueryPageFilter.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2015 Frank Becker 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: + * Frank Becker - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.provisional.tasks.ui.wizards; + +import java.util.ArrayList; +import java.util.List; + +public class QueryPageFilter { + + private final String key; + + private final List<String> values = new ArrayList<String>(); + + public QueryPageFilter(String key, String value) { + this.key = key; + values.add(value); + } + + public String getKey() { + return key; + } + + public String getValue() { + return values.get(0); + } + + public List<String> getValues() { + return values; + } + + public void setValue(String value) { + values.clear(); + values.add(value); + } + + public void setValues(List<String> value) { + values.clear(); + values.addAll(value); + } + + public void addValue(String value) { + values.add(value); + } + +} diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/provisional/tasks/ui/wizards/QueryPageSearch.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/provisional/tasks/ui/wizards/QueryPageSearch.java new file mode 100644 index 000000000..4b3d7e9eb --- /dev/null +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/provisional/tasks/ui/wizards/QueryPageSearch.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2015 Frank Becker 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: + * Frank Becker - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.provisional.tasks.ui.wizards; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.mylyn.commons.core.StatusHandler; +import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; + +public class QueryPageSearch { + + /** Stores search criteria in the order entered by the user. */ + private final Map<String, QueryPageFilter> filterByFieldName = new LinkedHashMap<String, QueryPageFilter>(); + + public QueryPageSearch() { + } + + public QueryPageSearch(String queryParameter) { + fromUrl(queryParameter); + } + + public void addFilter(String key, String value) { + QueryPageFilter filter = filterByFieldName.get(key); + if (filter == null) { + filter = new QueryPageFilter(key, value); + filterByFieldName.put(key, filter); + } + } + + public void addFilter(QueryPageFilter filter) { + filterByFieldName.put(filter.getKey(), filter); + } + + public List<QueryPageFilter> getFilters() { + return new ArrayList<QueryPageFilter>(filterByFieldName.values()); + } + + public QueryPageFilter getFilter(String key) { + return filterByFieldName.get(key); + } + + public void fromUrl(String url) { + int idx = url.indexOf('?'); + StringTokenizer t = new StringTokenizer(idx != -1 ? url.substring(idx + 1) : url, "&"); //$NON-NLS-1$ + while (t.hasMoreTokens()) { + String token = t.nextToken(); + int i = token.indexOf("="); //$NON-NLS-1$ + if (i != -1) { + try { + String key = URLDecoder.decode(token.substring(0, i), "UTF-8"); + String value = URLDecoder.decode(token.substring(i + 1), "UTF-8"); + QueryPageFilter filter = filterByFieldName.get(key); + if (filter == null) { + addFilter(key, value); + } else { + filter.addValue(value); + } + } catch (UnsupportedEncodingException e) { + StatusHandler.log(new Status(IStatus.WARNING, TasksUiPlugin.ID_PLUGIN, + "Unexpected exception while decoding URL", e)); //$NON-NLS-1$ + } + } + } + } + + public String toQuery() { + StringBuilder sb = new StringBuilder(); + int count = 0; + for (QueryPageFilter filter : filterByFieldName.values()) { + for (String actualValue : filter.getValues()) { + String encodedValue = null; + try { + encodedValue = URLEncoder.encode(actualValue, "UTF-8"); + if (count++ > 0) { + sb.append("&"); + } + sb.append(filter.getKey()); + sb.append("="); + sb.append(encodedValue); + } catch (UnsupportedEncodingException e) { + StatusHandler.log(new Status(IStatus.WARNING, TasksUiPlugin.ID_PLUGIN, + "Unexpected exception while encoding URL", e)); //$NON-NLS-1$ + } + } + } + return sb.toString(); + } + +} diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/provisional/tasks/ui/wizards/RepositoryQuerySchemaPage.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/provisional/tasks/ui/wizards/RepositoryQuerySchemaPage.java new file mode 100644 index 000000000..103ba627e --- /dev/null +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/provisional/tasks/ui/wizards/RepositoryQuerySchemaPage.java @@ -0,0 +1,315 @@ +/******************************************************************************* + * Copyright (c) 2015 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.provisional.tasks.ui.wizards; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.mylyn.commons.workbench.forms.SectionComposite; +import org.eclipse.mylyn.internal.provisional.tasks.ui.wizards.AbstractQueryPageSchema.Field; +import org.eclipse.mylyn.internal.tasks.core.TaskTask; +import org.eclipse.mylyn.internal.tasks.ui.notifications.TaskDiffUtil; +import org.eclipse.mylyn.tasks.core.IRepositoryQuery; +import org.eclipse.mylyn.tasks.core.ITask; +import org.eclipse.mylyn.tasks.core.TaskRepository; +import org.eclipse.mylyn.tasks.core.data.ITaskDataWorkingCopy; +import org.eclipse.mylyn.tasks.core.data.TaskAttribute; +import org.eclipse.mylyn.tasks.core.data.TaskData; +import org.eclipse.mylyn.tasks.core.data.TaskDataModel; +import org.eclipse.mylyn.tasks.core.data.TaskDataModelEvent; +import org.eclipse.mylyn.tasks.core.data.TaskDataModelListener; +import org.eclipse.mylyn.tasks.ui.TasksUi; +import org.eclipse.mylyn.tasks.ui.editors.AbstractAttributeEditor; +import org.eclipse.mylyn.tasks.ui.editors.AttributeEditorFactory; +import org.eclipse.mylyn.tasks.ui.editors.LayoutHint; +import org.eclipse.mylyn.tasks.ui.editors.LayoutHint.ColumnSpan; +import org.eclipse.mylyn.tasks.ui.editors.LayoutHint.RowSpan; +import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositoryQueryPage2; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.forms.widgets.FormToolkit; + +public class RepositoryQuerySchemaPage extends AbstractRepositoryQueryPage2 { + private static final String QUERYPAGE_FILTER_ID = "org.eclipse.mylyn.tasks.ui.wizards.QueryPageFilter"; + + private static final int LABEL_WIDTH = 110; + + private static final int COLUMN_WIDTH = 140; + + private static final int COLUMN_GAP = 20; + + private static final int MULTI_COLUMN_WIDTH = COLUMN_WIDTH + 5 + COLUMN_GAP + LABEL_WIDTH + 5 + COLUMN_WIDTH; + + private static final int MULTI_ROW_HEIGHT = 55; + + protected final AbstractQueryPageSchema schema; + + private final TaskData data; + + private final Pattern URL_PATTERN; + + private QueryPageSearch search; + + private final QueryPageDetails pageDetails; + + private AttributeEditorFactory factory; + + private SectionComposite scrolledComposite; + + protected TaskData targetTaskData; + + protected final Map<String, AbstractAttributeEditor> editorMap = new HashMap<String, AbstractAttributeEditor>(); + + public RepositoryQuerySchemaPage(String pageName, TaskRepository repository, IRepositoryQuery query, + AbstractQueryPageSchema schema, TaskData data, QueryPageDetails pageDetails) { + super(pageName, repository, query); + this.schema = schema; + this.data = data; + this.pageDetails = pageDetails; + setTitle(pageDetails.getPageTitle()); + setDescription(pageDetails.getPageDescription()); + URL_PATTERN = Pattern.compile(pageDetails.getUrlPattern()); + if (query != null) { + search = new QueryPageSearch(query.getUrl()); + } else { + search = new QueryPageSearch(); + } + } + + @Override + protected void createPageContent(@NonNull SectionComposite parent) { + this.scrolledComposite = parent; + + Composite scrolledBodyComposite = scrolledComposite.getContent(); + GridLayout layout = new GridLayout(); + layout.marginHeight = 0; + layout.marginWidth = 10; + layout.horizontalSpacing = 0; + layout.verticalSpacing = 0; + scrolledBodyComposite.setLayout(layout); + + Composite attributesComposite = new Composite(scrolledBodyComposite, SWT.NONE); + GridDataFactory.fillDefaults() + .align(SWT.FILL, SWT.FILL) + .grab(true, true) + .span(2, 1) + .applyTo(attributesComposite); + layout = new GridLayout(6, false); + layout.marginHeight = 0; + layout.marginWidth = 0; + attributesComposite.setLayout(layout); + GridData g = new GridData(GridData.FILL, GridData.FILL, true, true); + g.widthHint = 400; + attributesComposite.setLayoutData(g); + attributesComposite.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND)); + FormToolkit toolkit = new FormToolkit(parent.getDisplay()); + + TaskRepository repository = getTaskRepository(); + ITask nTask = new TaskTask(repository.getConnectorKind(), repository.getRepositoryUrl(), data.getTaskId()); + ITaskDataWorkingCopy workingCopy = TasksUi.getTaskDataManager().createWorkingCopy(nTask, data); + + final TaskDataModel model = new TaskDataModel(repository, nTask, workingCopy); + factory = new AttributeEditorFactory(model, repository); + model.addModelListener(new TaskDataModelListener() { + + @Override + public void attributeChanged(TaskDataModelEvent event) { + getContainer().updateButtons(); + } + }); + targetTaskData = workingCopy.getLocalData(); + final TaskAttribute target = targetTaskData.getRoot(); + createFieldControls(attributesComposite, toolkit, layout.numColumns, target); + Point p = scrolledBodyComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); + scrolledComposite.setMinSize(p); + + } + + private void createFieldControls(Composite attributesComposite, FormToolkit toolkit, int columnCount, + TaskAttribute target) { + int currentColumn = 1; + int currentPriority = 0; + int currentLayoutPriority = 0; + for (Field field : schema.getFields()) { + TaskAttribute dataAttribute = target.getAttribute(field.getKey()); + AbstractAttributeEditor attributeEditor = factory.createEditor(field.getType(), dataAttribute); + editorMap.put(dataAttribute.getId(), attributeEditor); + + String layoutPriorityString = dataAttribute.getMetaData().getValue("LayoutPriority"); + int layoutPriority = layoutPriorityString == null ? -1 : Integer.parseInt(layoutPriorityString); + int priority = (attributeEditor.getLayoutHint() != null) + ? attributeEditor.getLayoutHint().getPriority() + : LayoutHint.DEFAULT_PRIORITY; + // TODO: copied from AbstractTaskEditorAttributeSection.createAttributeControls (only layoutPriority is new) + if (priority != currentPriority || currentLayoutPriority != layoutPriority) { + currentPriority = priority; + currentLayoutPriority = layoutPriority; + if (currentColumn > 1) { + while (currentColumn <= columnCount) { + Label l = toolkit.createLabel(attributesComposite, ""); //$NON-NLS-1$ + + GridData gd = GridDataFactory.fillDefaults() + .align(SWT.LEFT, SWT.CENTER) + .hint(0, SWT.DEFAULT) + .create(); + l.setLayoutData(gd); + + currentColumn++; + } + currentColumn = 1; + } + } + + if (attributeEditor.hasLabel()) { + attributeEditor.createLabelControl(attributesComposite, toolkit); + Label label = attributeEditor.getLabelControl(); + label.setBackground(attributesComposite.getBackground()); + label.setForeground(attributesComposite.getForeground()); + String text = label.getText(); + String shortenText = TaskDiffUtil.shortenText(label, text, LABEL_WIDTH); + label.setText(shortenText); + if (!text.equals(shortenText)) { + label.setToolTipText(text); + } + GridData gd = GridDataFactory.fillDefaults() + .align(SWT.RIGHT, SWT.CENTER) + .grab(true, true) + .hint(LABEL_WIDTH, SWT.DEFAULT) + .create(); + if (currentColumn > 1) { + gd.horizontalIndent = COLUMN_GAP; + gd.widthHint = LABEL_WIDTH + COLUMN_GAP; + } + label.setLayoutData(gd); + currentColumn++; + } + attributeEditor.createControl(attributesComposite, toolkit); + attributeEditor.getControl().setBackground( + attributesComposite.getParent().getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); + attributeEditor.getControl().setForeground(attributesComposite.getForeground()); + LayoutHint layoutHint = attributeEditor.getLayoutHint(); + GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); + RowSpan rowSpan = (layoutHint != null && layoutHint.rowSpan != null) ? layoutHint.rowSpan : RowSpan.SINGLE; + ColumnSpan columnSpan = (layoutHint != null && layoutHint.columnSpan != null) + ? layoutHint.columnSpan + : ColumnSpan.SINGLE; + gd.horizontalIndent = 1;// prevent clipping of decorators on Windows + if (rowSpan == RowSpan.SINGLE && columnSpan == ColumnSpan.SINGLE) { + gd.widthHint = COLUMN_WIDTH; + gd.horizontalSpan = 1; + } else { + if (rowSpan == RowSpan.MULTIPLE) { + gd.heightHint = MULTI_ROW_HEIGHT; + } + if (columnSpan == ColumnSpan.SINGLE) { + gd.widthHint = COLUMN_WIDTH; + gd.horizontalSpan = 1; + } else { + gd.widthHint = MULTI_COLUMN_WIDTH; + gd.horizontalSpan = columnCount - currentColumn + 1; + } + } + attributeEditor.getControl().setLayoutData(gd); + + currentColumn += gd.horizontalSpan; + currentColumn %= columnCount; + } + } + + @Override + public boolean isPageComplete() { + setMessage(pageDetails.getPageDescription()); + boolean result = super.isPageComplete(); + if (!result) { + return result; + } + setErrorMessage(null); + setMessage(""); + boolean oneFieldHasValue = false; + for (Field field : schema.getFields()) { + oneFieldHasValue |= (targetTaskData.getRoot().getAttribute(field.getKey()).hasValue() + && !targetTaskData.getRoot().getAttribute(field.getKey()).getValue().equals("")); + if (field.isQueryRequired()) { + String text = targetTaskData.getRoot().getAttribute(field.getKey()).getValue(); + if (text == null || text.length() == 0) { + setMessage("Enter a value for " + field.getLabel()); + return false; + } + } + if (field.getType().equals("url")) { + String text = targetTaskData.getRoot().getAttribute(field.getKey()).getValue(); + if (text != null && text.length() > 0) { + Matcher m = URL_PATTERN.matcher(text); + if (m.find()) { + setErrorMessage(null); + return true; + } else { + setErrorMessage("Please specify a valid URL in " + field.getLabel()); + return false; + } + } + } + } + if (!oneFieldHasValue) { + setErrorMessage("Please fill at least on field!"); + } + return true; + } + + protected String getQueryUrl(String repsitoryUrl) { + StringBuilder sb = new StringBuilder(); + sb.append(repsitoryUrl); + sb.append("/"); + sb.append(pageDetails.getQueryUrlPart()); + sb.append(search.toQuery()); + return sb.toString(); + + } + + @Override + public void applyTo(IRepositoryQuery query) { + query.setSummary(this.getQueryTitle()); + query.setUrl(getQueryUrl(getTaskRepository().getRepositoryUrl())); + if (pageDetails.getQueryAttributeName() != null) { + query.setAttribute(pageDetails.getQueryAttributeName(), Boolean.TRUE.toString()); + } + } + + //FIXME: REST überarbeiten + @Override + protected void doRefreshControls() { + // ignore + + } + + //FIXME: REST überarbeiten + @Override + protected boolean hasRepositoryConfiguration() { + // ignore + return true; + } + + //FIXME: REST überarbeiten + @Override + protected boolean restoreState(@NonNull IRepositoryQuery query) { + // ignore + return false; + } +} |