Java tutorial
/******************************************************************************* * Copyright (c) 2011 Ralf Sternberg. * 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: * Ralf Sternberg - initial implementation and API ******************************************************************************/ package ralfstx.mylyn.bugview.internal; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.fieldassist.ContentProposalAdapter; import org.eclipse.jface.fieldassist.TextContentAdapter; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.mylyn.tasks.core.IRepositoryQuery; import org.eclipse.mylyn.tasks.core.ITask; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.Text; import org.hamcrest.CoreMatchers; import org.hamcrest.Matcher; import ralfstx.mylyn.bugview.TaskMatchers; public class BugView extends AbstractBugView { static final int COL_ID = 0; static final int COL_TITLE = 1; private TableViewer viewer; private Text searchField; private IRepositoryQuery activeQuery; private Matcher<ITask> toolbarMatcher = CoreMatchers.anything(); private Matcher<ITask> searchMatcher = CoreMatchers.anything(); private final SearchQueryParser queryParser = new SearchQueryParser(); private WordProposalProvider proposalProvider; @Override public void createPartControl(Composite parent) { parent.setLayout(createMainLayout()); createQuickFilterArea(parent); createSearchTextField(parent); createTableViewer(parent); addContentProposalToSearchField(); makeActions(); refreshViewer(); refreshAutoSuggestions(); } @Override public void setFocus() { searchField.setFocus(); } @Override public void setActiveQuery(IRepositoryQuery query) { activeQuery = query; updateIdColumnWidth(); refreshViewer(); refreshAutoSuggestions(); } private void createQuickFilterArea(Composite parent) { final QuickFilterArea filterArea = new QuickFilterArea(parent, SWT.NONE); filterArea.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); addQuickFilterContributions(filterArea); filterArea.setMatcherChangedListener(new Runnable() { public void run() { toolbarMatcher = filterArea.getMatcher(); refreshFilter(); } }); } private static void addQuickFilterContributions(final QuickFilterArea filterArea) { QuickFilterContribution showIncoming = createIncomingContribution(); QuickFilterContribution showOutgoing = createOutgoingContribution(); filterArea.createToolBar(showIncoming, showOutgoing); QuickFilterContribution showEnhancements = createEnhancementsContribution(); QuickFilterContribution showDefects = createDefectsContribution(); filterArea.createToolBar(showEnhancements, showDefects); QuickFilterContribution hideCompleted = createHideCompletedContribution(); filterArea.createToolBar(hideCompleted); } private static QuickFilterContribution createIncomingContribution() { return new QuickFilterContribution("show only incoming", Activator.getImageDescriptor("/icons/incoming.png"), TaskMatchers.isIncoming()); } private static QuickFilterContribution createOutgoingContribution() { return new QuickFilterContribution("show only outgoing", Activator.getImageDescriptor("/icons/outgoing.png"), TaskMatchers.isOutgoing()); } private static QuickFilterContribution createEnhancementsContribution() { return new QuickFilterContribution("show only enhancements", Activator.getImageDescriptor("/icons/enhancement.png"), TaskMatchers.isEnhancement()); } private static QuickFilterContribution createDefectsContribution() { return new QuickFilterContribution("show only defects", Activator.getImageDescriptor("/icons/defect.png"), CoreMatchers.not(TaskMatchers.isEnhancement())); } private static QuickFilterContribution createHideCompletedContribution() { return new QuickFilterContribution("hide completed", Activator.getImageDescriptor("/icons/hidecompleted.png"), CoreMatchers.not(TaskMatchers.isCompleted())); } private void createSearchTextField(Composite parent) { searchField = new Text(parent, SWT.SEARCH | SWT.CANCEL | SWT.ICON_SEARCH | SWT.ICON_CANCEL); searchField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); searchField.addSelectionListener(new SelectionAdapter() { @Override public void widgetDefaultSelected(SelectionEvent e) { String query = searchField.getText().trim(); searchMatcher = queryParser.parse(query); refreshFilter(); } }); } private void addContentProposalToSearchField() { proposalProvider = new WordProposalProvider(); TextContentAdapter controlAdapter = new TextContentAdapter(); ContentProposalAdapter proposalAdapter = new ContentProposalAdapter(searchField, controlAdapter, proposalProvider, null, null); proposalAdapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE); } private void refreshFilter() { viewer.refresh(false); updateStatusBar(); } private void createTableViewer(Composite parent) { Table table = new Table(parent, SWT.VIRTUAL | SWT.FULL_SELECTION); table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); table.setLinesVisible(true); table.addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent e) { layoutTable(); } }); new TableColumn(table, SWT.LEFT).setWidth(80); new TableColumn(table, SWT.LEFT).setWidth(400); viewer = new TableViewer(table); viewer.setLabelProvider(new TaskLabelProvider()); viewer.setContentProvider(new ArrayContentProvider()); viewer.setComparator(new TaskLastModifiedComparator()); viewer.addFilter(new TaskViewerFilter()); ColumnViewerToolTipSupport.enableFor(viewer); addStrikeThrough(); addDoubleClickBehavior(); } private void layoutTable() { Table table = viewer.getTable(); int clientWidth = table.getClientArea().width; int idWidth = table.getColumn(COL_ID).getWidth(); table.getColumn(COL_TITLE).setWidth(clientWidth - idWidth); } private void updateIdColumnWidth() { Table table = viewer.getTable(); int iconWidth = 16; int padding = 12; int idWidth = calculateIdWidth() + iconWidth + padding; table.getColumn(COL_ID).setWidth(idWidth); } private int calculateIdWidth() { int maxWidth = 0; Table table = viewer.getTable(); Font boldFont = JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT); GC gc = new GC(table); try { gc.setFont(boldFont); Collection<ITask> tasks = getTasks(); for (ITask task : tasks) { String id = task.getTaskId(); int width = gc.stringExtent(id).x; maxWidth = Math.max(maxWidth, width); } } finally { gc.dispose(); } return maxWidth; } private void addStrikeThrough() { StrikeThroughProvider strikeThroughProvider = new StrikeThroughProvider() { public boolean getStrikeThrough(Object element) { if (element instanceof ITask) { ITask task = (ITask) element; return task.isCompleted(); } return false; } }; TableViewerStrikeThroughUtil.attach(strikeThroughProvider, viewer); } private void addDoubleClickBehavior() { viewer.addDoubleClickListener(new IDoubleClickListener() { public void doubleClick(DoubleClickEvent event) { ITask selectedTask = getSelectedTask(); if (selectedTask != null) { MylynBridge.openTaskInEditor(selectedTask); } } }); } private void makeActions() { ImageDescriptor refreshImage = Activator.getImageDescriptor("/icons/refresh.gif"); IAction refreshViewAction = new Action("Refresh View", refreshImage) { @Override public void run() { refreshViewer(); refreshAutoSuggestions(); } }; ImageDescriptor refreshAllImage = Activator.getImageDescriptor("/icons/repository-synchronize.gif"); IAction refreshAllAction = new Action("Refresh all Repositories", refreshAllImage) { @Override public void run() { MylynBridge.synchronizeAllRepositories(); } }; IToolBarManager toolBarManager = getViewSite().getActionBars().getToolBarManager(); toolBarManager.add(refreshViewAction); toolBarManager.add(refreshAllAction); IMenuManager menuManager = getViewSite().getActionBars().getMenuManager(); menuManager.add(new QueryFilterDropDownMenuAction(this)); } private void refreshViewer() { Collection<ITask> tasks = getTasks(); viewer.setInput(tasks); updateStatusBar(); } private void refreshAutoSuggestions() { ArrayList<String> suggestions = new ArrayList<String>(); List<String> initialSuggestions = SearchQueryParser.getSuggestions(); List<String> allTags = findAllTags(); suggestions.addAll(initialSuggestions); suggestions.addAll(allTags); proposalProvider.setSuggestions(suggestions); } private List<String> findAllTags() { List<String> allTags = new ArrayList<String>(); Collection<ITask> tasks = getTasks(); HashTagParser tagParser = new HashTagParser(); for (ITask task : tasks) { String notes = MylynBridge.getNotes(task); if (notes != null) { List<String> foundTags = tagParser.parse(notes); for (String tag : foundTags) { String prefixedTag = "#" + tag; if (!allTags.contains(prefixedTag)) { allTags.add(prefixedTag); } } } } return allTags; } private Collection<ITask> getTasks() { if (activeQuery != null) { return MylynBridge.getAllTasks(activeQuery); } return MylynBridge.getAllTasks(); } private ITask getSelectedTask() { ISelection selection = viewer.getSelection(); if (!selection.isEmpty() && selection instanceof StructuredSelection) { StructuredSelection structuredSelection = (StructuredSelection) selection; Object element = structuredSelection.getFirstElement(); if (element instanceof ITask) { return (ITask) element; } } return null; } private void updateStatusBar() { String message = null; int items = viewer.getTable().getItemCount(); message = items + " bugs"; IStatusLineManager statusLineManager = getViewSite().getActionBars().getStatusLineManager(); statusLineManager.setMessage(message); } private static GridLayout createMainLayout() { GridLayout mainLayout = new GridLayout(); mainLayout.marginWidth = 0; mainLayout.marginHeight = 0; mainLayout.verticalSpacing = 0; return mainLayout; } private static final class TaskLastModifiedComparator extends ViewerComparator { @Override public int compare(Viewer viewer, Object element1, Object element2) { int result = 0; if (element1 instanceof ITask && element2 instanceof ITask) { result = compareModificationDate((ITask) element1, (ITask) element2) * -1; } return result; } private static int compareModificationDate(ITask task1, ITask task2) { int result; Date modDate1 = task1.getModificationDate(); Date modDate2 = task2.getModificationDate(); if (modDate1 == null) { result = modDate2 == null ? 0 : -1; } else { result = modDate2 == null ? 1 : modDate1.compareTo(modDate2); } return result; } } private final class TaskViewerFilter extends ViewerFilter { @Override public boolean select(Viewer viewer, Object parentElement, Object element) { if (element instanceof ITask) { ITask task = (ITask) element; return toolbarMatcher.matches(task) && searchMatcher.matches(task); } return false; } } }