Java tutorial
/******************************************************************************* * Copyright (c) 2008,2011 Peter Stibrany * 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: * Peter Stibrany (pstibrany@gmail.com) - initial API and implementation *******************************************************************************/ package com.foglyn.ui; import java.lang.reflect.InvocationTargetException; import java.text.DateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicReference; import net.miginfocom.swt.MigLayout; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.ComboViewer; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.wizard.IWizardContainer; import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.mylyn.tasks.core.IRepositoryQuery; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.ui.TasksUi; import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositoryQueryPage; import org.eclipse.swt.SWT; import org.eclipse.swt.events.FocusAdapter; import org.eclipse.swt.events.FocusEvent; 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.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import com.foglyn.core.AdvancedSearchQuery; import com.foglyn.core.FilterQuery; import com.foglyn.core.FoglynCorePlugin; import com.foglyn.core.FoglynQuery; import com.foglyn.core.FoglynRepositoryConnector; import com.foglyn.fogbugz.FogBugzClient; import com.foglyn.fogbugz.FogBugzException; import com.foglyn.fogbugz.FogBugzFilter; import com.foglyn.fogbugz.FogBugzFilter.FilterID; import com.foglyn.fogbugz.FogBugzFixFor; import com.foglyn.fogbugz.FogBugzProject; import com.foglyn.fogbugz.FogBugzProject.ProjectID; import com.foglyn.helpers.CollectionContentProvider; import com.foglyn.helpers.FilterLabelProvider; import com.foglyn.helpers.MappingLabelProvider; import com.foglyn.helpers.ProjectLabelProvider; public class FoglynNewQueryWizardPage extends AbstractRepositoryQueryPage { private static final String SIMPLE_QUERY_WIZARD = "SIMPLE_QUERY_WIZARD"; private static final String SIMPLE_QUERY_WIZARD_TYPE = "SIMPLE_QUERY_WIZARD_TYPE"; private static final String QUERY_TYPE_KEY = "QueryType"; private static final String ENABLED_FOR_QUERY_TYPE = "EnabledForQueryType"; // Do not rename ... private enum QueryType { MY_CASES, MY_PROJECT_CASES, MY_MILESTONE_CASES, FILTER_CASES, ADVANCED_SEARCH } private Text queryName; private ComboViewer project; private ComboViewer milestone; private ComboViewer filter; private List<Button> radioButtons = null; private List<ComboViewer> viewersToDisable = null; private final FoglynAdvancedSearchPage searchPage; private boolean firstTime = true; private boolean canChangeQueryName; private FoglynQuery query; private FogBugzClient client; public FoglynNewQueryWizardPage(TaskRepository taskRepository, IRepositoryQuery queryToEdit, FoglynQuery query) { super("New Foglyn Query", taskRepository, queryToEdit); setDescription(null); setImageDescriptor(FoglynImages.FOGBUGZ_REPOSITORY); this.query = query; searchPage = new FoglynAdvancedSearchPage(taskRepository); if (queryToEdit == null) { this.canChangeQueryName = true; } else { this.canChangeQueryName = false; } } public FoglynNewQueryWizardPage(TaskRepository repository) { this(repository, null, null); } public void createControl(Composite parent) { Composite control = new Composite(parent, SWT.NO_SCROLL); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).applyTo(control); control.setLayout(new MigLayout("fillx", "[left]rel[fill]")); Label queryNameLabel = new Label(control, SWT.NONE); queryNameLabel.setText("Query Name:"); queryName = new Text(control, SWT.SINGLE | SWT.BORDER | SWT.FILL); queryName.setLayoutData("grow, wrap para"); Label separator = new Label(control, SWT.SEPARATOR | SWT.HORIZONTAL); separator.setLayoutData("width 100%, span, wrap para"); /// My Cases Button myCasesRadio = new Button(control, SWT.RADIO); myCasesRadio.setText("My Cases Only"); myCasesRadio.setData(QUERY_TYPE_KEY, QueryType.MY_CASES); myCasesRadio.setLayoutData("span, wrap 2*unrel"); /// Project Button projectRadio = new Button(control, SWT.RADIO); projectRadio.setData(QUERY_TYPE_KEY, QueryType.MY_PROJECT_CASES); projectRadio.setText("My Cases for Project:"); project = new ComboViewer(control); project.setContentProvider(new CollectionContentProvider(false)); project.setLabelProvider(new ProjectLabelProvider()); project.getControl().setLayoutData("grow, wrap 2*unrel"); project.setData(ENABLED_FOR_QUERY_TYPE, QueryType.MY_PROJECT_CASES); /// Milestone Button milestoneRadio = new Button(control, SWT.RADIO); milestoneRadio.setData(QUERY_TYPE_KEY, QueryType.MY_MILESTONE_CASES); milestoneRadio.setText("My Cases for Milestone:"); milestone = new ComboViewer(control); milestone.setContentProvider(new CollectionContentProvider(false)); // Label provider is set in setupMilestones method milestone.getControl().setLayoutData("grow, wrap 2*unrel"); milestone.setData(ENABLED_FOR_QUERY_TYPE, QueryType.MY_MILESTONE_CASES); /// Filter Button filterRadio = new Button(control, SWT.RADIO); filterRadio.setData(QUERY_TYPE_KEY, QueryType.FILTER_CASES); filterRadio.setText("Cases From FogBugz Filter:"); filter = new ComboViewer(control); filter.setContentProvider(new CollectionContentProvider(false)); filter.setLabelProvider(new FilterLabelProvider()); filter.getControl().setLayoutData("grow, wrap 2*unrel"); filter.setData(ENABLED_FOR_QUERY_TYPE, QueryType.FILTER_CASES); /// Search options ... Button searchRadio = null; if (query == null) { searchRadio = new Button(control, SWT.RADIO); searchRadio.setText("Cases Matched by Search Options (specified on next page)"); searchRadio.setData(QUERY_TYPE_KEY, QueryType.ADVANCED_SEARCH); searchRadio.setLayoutData("span, wrap 2*unrel"); } setControl(control); // setup listeners, and stuff queryName.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { getContainer().updateButtons(); canChangeQueryName = false; } }); queryName.addFocusListener(new FocusAdapter() { public void focusLost(FocusEvent e) { if (queryName.getText().trim().length() == 0) { canChangeQueryName = true; determineQueryName(); } } }); viewersToDisable = new ArrayList<ComboViewer>(); viewersToDisable.add(project); viewersToDisable.add(milestone); viewersToDisable.add(filter); ISelectionChangedListener scl = new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { determineQueryName(); getContainer().updateButtons(); } }; for (ComboViewer cv : viewersToDisable) { cv.addSelectionChangedListener(scl); } radioButtons = new ArrayList<Button>(); radioButtons.add(myCasesRadio); radioButtons.add(projectRadio); radioButtons.add(milestoneRadio); radioButtons.add(filterRadio); if (searchRadio != null) { radioButtons.add(searchRadio); } SelectionAdapter listener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (!(e.widget instanceof Button)) { return; } updateViewers(); Button b = (Button) e.widget; if (b.getSelection()) { determineQueryName(); getContainer().updateButtons(); } } }; for (Button b : radioButtons) { b.addSelectionListener(listener); } updateViewers(); } protected void updateViewers() { QueryType qt = getSelectedQueryType(); for (ComboViewer v : viewersToDisable) { QueryType e = (QueryType) v.getData(ENABLED_FOR_QUERY_TYPE); v.getControl().setEnabled(e.equals(qt)); } } @Override public String getQueryTitle() { return queryName.getText(); } protected void determineQueryName() { if (!canChangeQueryName) { return; } QueryType qt = getSelectedQueryType(); if (qt == null) { return; } String newQueryName = null; switch (qt) { case ADVANCED_SEARCH: newQueryName = "FogBugz Search ..."; break; case MY_CASES: newQueryName = "My Cases"; break; case FILTER_CASES: FogBugzFilter f = getSelection(filter, FogBugzFilter.class); if (f != null) { newQueryName = "Filter: " + f.getDescription(); } else { newQueryName = "Filter: ..."; } break; case MY_PROJECT_CASES: FogBugzProject p = getSelection(project, FogBugzProject.class); if (p != null) { newQueryName = "Project: " + p.getName(); } else { newQueryName = "Project: ..."; } break; case MY_MILESTONE_CASES: FogBugzFixFor ff = getSelection(milestone, FogBugzFixFor.class); if (ff == null) { newQueryName = "Milestone: ..."; } else { FogBugzProject ffp = null; if (ff.getProject() != null && client != null) { ffp = client.getProject(ff.getProject()); } if (ffp != null) { newQueryName = "Milestone: " + ffp.getName() + ": " + ff.getName(); } else { newQueryName = "Milestone: " + ff.getName(); } } break; } if (newQueryName != null) { this.queryName.setText(newQueryName); canChangeQueryName = true; } } @Override public boolean isPageComplete() { if (!super.isPageComplete()) { return false; } QueryType qt = getSelectedQueryType(); if (qt == null) { setMessage("Please choose type of query"); return false; } switch (qt) { case ADVANCED_SEARCH: // We are not complete for ADV. Search... user must go to Next page return false; case MY_CASES: return true; case FILTER_CASES: if (getSelection(filter, FogBugzFilter.class) == null) { setMessage("Please select a filter."); return false; } setMessage(null); return true; case MY_MILESTONE_CASES: if (getSelection(milestone, FogBugzFixFor.class) == null) { setMessage("Please select a milestone."); return false; } setMessage(null); return true; case MY_PROJECT_CASES: if (getSelection(project, FogBugzProject.class) == null) { setMessage("Please select a project."); return false; } setMessage(null); return true; } setErrorMessage(null); return true; } <T> T getSelection(ComboViewer cv, Class<T> clz) { ISelection sel = cv.getSelection(); if (sel == null || sel.isEmpty()) { return null; } IStructuredSelection iss = (IStructuredSelection) sel; Object o = iss.getFirstElement(); return clz.cast(o); } @Override public void setVisible(boolean visible) { super.setVisible(visible); if (visible && firstTime) { firstTime = false; final IWizardContainer wizard = getContainer(); // run asynchronously -- we allow dialog to get displayed, and initiate fetching of FogBugz data Display.getDefault().asyncExec(new Runnable() { public void run() { if (getControl() != null && !getControl().isDisposed()) { initializePage(wizard); } } }); } } private void initializePage(IWizardContainer wizard) { final FoglynRepositoryConnector connector = (FoglynRepositoryConnector) TasksUi.getRepositoryManager() .getRepositoryConnector(FoglynCorePlugin.CONNECTOR_KIND); final AtomicReference<List<FogBugzFilter>> filtersRef = new AtomicReference<List<FogBugzFilter>>(); final AtomicReference<Collection<FogBugzProject>> projectsRef = new AtomicReference<Collection<FogBugzProject>>(); final AtomicReference<Collection<FogBugzFixFor>> milestonesRef = new AtomicReference<Collection<FogBugzFixFor>>(); final AtomicReference<FogBugzClient> fbclient = new AtomicReference<FogBugzClient>(); try { IRunnableWithProgress runnable = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { monitor.beginTask("Fetching data from FogBugz server", IProgressMonitor.UNKNOWN); FogBugzClient client = connector.getClientManager().getFogbugzClient(getTaskRepository(), monitor); filtersRef.set(client.listFilters(monitor)); projectsRef.set(client.getAllProjects()); milestonesRef.set(client.getAllFixFors()); fbclient.set(client); monitor.done(); } catch (FogBugzException e) { throw new InvocationTargetException(e, e.getMessage()); } catch (CoreException e) { throw new InvocationTargetException(e, e.getMessage()); } } }; wizard.run(true, true, runnable); client = fbclient.get(); filter.setInput(filtersRef.get()); project.setInput(projectsRef.get()); setupMilestones(fbclient.get(), milestonesRef.get()); QueryType qt = null; if (query != null) { if (query instanceof FilterQuery && filtersRef.get() != null) { qt = QueryType.FILTER_CASES; FilterID fid = ((FilterQuery) query).getFilterID(); for (FogBugzFilter f : filtersRef.get()) { if (f.getFilterID().equals(fid)) { filter.setSelection(new StructuredSelection(f), true); } } } if (query instanceof AdvancedSearchQuery) { AdvancedSearchQuery asq = (AdvancedSearchQuery) query; if (asq.getProject() != null && projectsRef.get() != null) { qt = QueryType.MY_PROJECT_CASES; for (FogBugzProject p : projectsRef.get()) { if (p.getID().equals(asq.getProject())) { project.setSelection(new StructuredSelection(p), true); } } } else if (asq.getFixFor() != null && milestonesRef.get() != null) { qt = QueryType.MY_MILESTONE_CASES; for (FogBugzFixFor m : milestonesRef.get()) { if (m.getID().equals(asq.getFixFor())) { milestone.setSelection(new StructuredSelection(m), true); } } } } if (qt != null) { for (Button b : radioButtons) { b.setSelection(qt.equals(b.getData(QUERY_TYPE_KEY))); } } updateViewers(); queryName.setText(query.getQueryTitle()); } } catch (InvocationTargetException e) { FoglynUIPlugin.log("Cannot fetch data from FogBugz", e.getCause()); setErrorMessage("Cannot fetch data from FogBugz"); } catch (InterruptedException e) { FoglynUIPlugin.log("Cannot fetch data from FogBugz", e); setErrorMessage("Cannot fetch data from FogBugz"); } } private void setupMilestones(FogBugzClient fogBugzClient, Collection<FogBugzFixFor> milestones) { Map<ProjectID, List<FogBugzFixFor>> projectMilestones = new HashMap<FogBugzProject.ProjectID, List<FogBugzFixFor>>(); List<FogBugzFixFor> globalMilestones = new ArrayList<FogBugzFixFor>(); // sort milestones into global, and project sortMilestones(fogBugzClient, milestones, projectMilestones, globalMilestones); Map<Object, String> milestoneLabels = new HashMap<Object, String>(); List<Object> milestonesInput = new ArrayList<Object>(); // global milestones first for (FogBugzFixFor ff : globalMilestones) { milestoneLabels.put(ff, getMilestoneName(ff, null, true)); milestonesInput.add(ff); } for (Entry<ProjectID, List<FogBugzFixFor>> pms : projectMilestones.entrySet()) { FogBugzProject p = fogBugzClient.getProject(pms.getKey()); for (FogBugzFixFor ff : pms.getValue()) { milestoneLabels.put(ff, getMilestoneName(ff, p, true)); milestonesInput.add(ff); } } milestone.setLabelProvider(new MappingLabelProvider(milestoneLabels)); milestone.setInput(milestonesInput); } // Sorts milestones into "global" and "per project" categories. Each category is sorted by milestone name. private void sortMilestones(FogBugzClient fogBugzClient, Collection<FogBugzFixFor> milestones, Map<ProjectID, List<FogBugzFixFor>> projectMilestones, List<FogBugzFixFor> globalMilestones) { for (FogBugzFixFor ff : milestones) { if (ff.isDeleted()) { continue; } ProjectID p = ff.getProject(); if (p == null && fogBugzClient.getProject(p) != null) { globalMilestones.add(ff); } else { List<FogBugzFixFor> ms = projectMilestones.get(p); if (ms == null) { ms = new ArrayList<FogBugzFixFor>(); projectMilestones.put(p, ms); } ms.add(ff); } } Comparator<FogBugzFixFor> comp = new Comparator<FogBugzFixFor>() { public int compare(FogBugzFixFor o1, FogBugzFixFor o2) { return o1.getName().compareTo(o2.getName()); } }; // Sort milestones in each category Collections.sort(globalMilestones, comp); for (List<FogBugzFixFor> l : projectMilestones.values()) { Collections.sort(l, comp); } } private String getMilestoneName(FogBugzFixFor m, FogBugzProject project, boolean date) { StringBuilder sb = new StringBuilder(); if (project != null) { sb.append(project.getName()); sb.append(": "); } sb.append(m.getName()); if (date) { Date d = m.getDate(); if (d != null) { DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); sb.append(" ("); sb.append(df.format(d)); sb.append(")"); } } return sb.toString(); } @Override public boolean canFlipToNextPage() { // We ignore query name validation. Our "isPageComplete" returns false for ADVANCED_SEARCH type, we skip it too. return getSelectedQueryType() == QueryType.ADVANCED_SEARCH; } @Override public IWizardPage getNextPage() { QueryType t = getSelectedQueryType(); if (t == QueryType.ADVANCED_SEARCH) { searchPage.setWizard(this.getWizard()); searchPage.setQueryTitle(getQueryTitle()); return searchPage; } return null; } @Override public void applyTo(IRepositoryQuery query) { FoglynQuery q = null; QueryType qt = getSelectedQueryType(); switch (qt) { case FILTER_CASES: q = getFilterQuery(); break; case MY_CASES: q = getMyCasesQuery(); break; case MY_MILESTONE_CASES: q = getMyMilestoneCasesQuery(); break; case MY_PROJECT_CASES: q = getMyProjectCasesQuery(); break; default: throw new IllegalStateException("Cannot happen"); } q.setQueryTitle(getQueryTitle()); query.setAttribute(SIMPLE_QUERY_WIZARD, Boolean.TRUE.toString()); query.setAttribute(SIMPLE_QUERY_WIZARD_TYPE, qt.name()); q.saveToQuery(query); } private FilterQuery getFilterQuery() { FilterQuery fq = new FilterQuery(); FogBugzFilter f = getSelection(filter, FogBugzFilter.class); fq.setFilterID(f.getFilterID()); return fq; } private AdvancedSearchQuery getMyCasesQuery() { AdvancedSearchQuery asq = new AdvancedSearchQuery(); asq.setAssignedToMe(true); return asq; } private AdvancedSearchQuery getMyMilestoneCasesQuery() { AdvancedSearchQuery asq = new AdvancedSearchQuery(); asq.setAssignedToMe(true); asq.setFixFor(getSelection(milestone, FogBugzFixFor.class).getID()); return asq; } private AdvancedSearchQuery getMyProjectCasesQuery() { AdvancedSearchQuery asq = new AdvancedSearchQuery(); asq.setAssignedToMe(true); asq.setProject(getSelection(project, FogBugzProject.class).getID()); return asq; } private QueryType getSelectedQueryType() { for (Button b : radioButtons) { if (b.getSelection()) { return (QueryType) b.getData(QUERY_TYPE_KEY); } } return null; } static boolean isWizardQuery(IRepositoryQuery queryToEdit) { return Boolean.parseBoolean(queryToEdit.getAttribute(FoglynNewQueryWizardPage.SIMPLE_QUERY_WIZARD)); } }