/******************************************************************************* * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada * and IBM Corporation. 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: * The Chisel Group, University of Victoria *******************************************************************************/ package net.sourceforge.tagsea.core.ui.tags; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import net.sourceforge.tagsea.TagSEAPlugin; import net.sourceforge.tagsea.core.ITag; import net.sourceforge.tagsea.core.ITagChangeListener; import net.sourceforge.tagsea.core.TagDelta; import net.sourceforge.tagsea.core.internal.ITagSEAPreferences; import net.sourceforge.tagsea.core.ui.ITagSEAImageConstants; import net.sourceforge.tagsea.core.ui.internal.TagSEAUI; import net.sourceforge.tagsea.core.ui.internal.TagSEAUIEvent; import net.sourceforge.tagsea.core.ui.internal.tags.TagActionGroup; import net.sourceforge.tagsea.core.ui.internal.tags.TagToggleTreeAction; import net.sourceforge.tagsea.core.ui.internal.tags.TagTreeItem; import net.sourceforge.tagsea.core.ui.internal.tags.TagTreeItemTransfer; import net.sourceforge.tagsea.core.ui.internal.tags.TagWaypointViewerFilter; import net.sourceforge.tagsea.core.ui.internal.tags.TagsDragListener; import net.sourceforge.tagsea.core.ui.internal.tags.TagsTree; import net.sourceforge.tagsea.core.ui.internal.tags.TagsViewDropListener; import net.sourceforge.tagsea.core.ui.internal.views.CachingTreePatternFilter; import net.sourceforge.tagsea.core.ui.internal.views.PatternFilteredTree; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; 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.ITreeSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Item; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.actions.ActionContext; import org.eclipse.ui.model.BaseWorkbenchContentProvider; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.progress.IWorkbenchSiteProgressService; /** * The Tags view. * @author Del Myers */ @Deprecated public class TagsView extends ViewPart implements ISelectionProvider { public static final String ID = "net.sourceforge.tagsea.ui.TagsView"; private PatternFilteredTree treeViewer; private TagsChangedListener tagsListener; private boolean refreshScheduled; private List<ISelectionChangedListener> selectionListeners; private ISelection currentSelection; private TreeSelectionChangedListener treeSelectionListener; private TagActionGroup actionGroup; private TagsPreferenceListener preferenceListener; private Action fFilterToWaypointsAction; private TagToggleTreeAction toggleTreeAction; private TagWaypointViewerFilter fWaypointViewerFilter; private ISelectionListener fWorkbenchSelectionListener; /** * Listener used in the tree viewer that opens an item for editing or opens the waypoint view. The * editor is opened when one of the following occurs: * 1) F2 is pressed & released * 2) "space" is pressed & released * 3) An item is selected for the second time. * * The waypoints view is opened when an item is double-clicked. * @author Del Myers * */ private final class ItemEditListener implements Listener { boolean doubleClicked = false; //timer to make sure that a double-click isn't pressed. private Timer doubleClickTimer = null; private Display display; private Item thisSelection; private Item lastSelection; public void handleEvent(Event event) { this.display = event.widget.getDisplay(); switch (event.type) { case SWT.Dispose: if (doubleClickTimer != null) { doubleClickTimer.cancel(); doubleClickTimer = null; } break; case SWT.KeyUp: if (event.detail == 0) { if (event.keyCode == SWT.F2 || event.character == ' ') { actionGroup.runEditAction(); } } break; case SWT.Selection: lastSelection = thisSelection; thisSelection = (Item) event.item; if (this.doubleClickTimer != null) { this.doubleClickTimer.cancel(); this.doubleClickTimer = null; } if (doubleClicked) { doubleClicked = false; } else { if (true) { if (event.widget instanceof Tree) { if (thisSelection == lastSelection && lastSelection != null) { doubleClickTimer = new Timer(); doubleClickTimer.schedule(new TimerTask(){ @Override public void run() { display.asyncExec(new Runnable(){ public void run() { if (!doubleClicked) { actionGroup.runEditAction(); } } }); } }, display.getDoubleClickTime()+25); } } } } break; case SWT.MouseDoubleClick: doubleClicked = true; if (this.doubleClickTimer != null) { this.doubleClickTimer.cancel(); this.doubleClickTimer = null; } actionGroup.runDefaultAction(event); break; } } } /** * Listener for the internal tree viewer to translate the viewer model * to tags. * @author Del Myers */ private class TreeSelectionChangedListener implements ISelectionChangedListener { /* (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent) */ public void selectionChanged(SelectionChangedEvent event) { ISelection selection = event.getSelection(); actionGroup.setContext(new ActionContext(selection)); updateSelection(selection); } } private class TagsChangedListener implements ITagChangeListener { /* (non-Javadoc) * @see net.sourceforge.tagsea.core.ITagChangeListener#tagsChanged(net.sourceforge.tagsea.core.TagDelta) */ public void tagsChanged(TagDelta delta) { if (treeViewer.isDisposed()) return; scheduleViewerRefresh(); } } private class TagsPreferenceListener implements IPropertyChangeListener { /* (non-Javadoc) * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(org.eclipse.core.runtime.Preferences.PropertyChangeEvent) */ public void propertyChange(PropertyChangeEvent event) { refreshActions(); if (ITagSEAPreferences.TAGS_VIEW_TREE.equals(event.getProperty())) { boolean newValue = ((Boolean)event.getNewValue()); treeViewer.getViewer().setInput(new TagsTree(!newValue)); scheduleViewerRefresh(); } } } public TagsView() { selectionListeners = new LinkedList<ISelectionChangedListener>(); currentSelection = StructuredSelection.EMPTY; } /* (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite) */ @Override public void createPartControl(Composite parent) { Composite page = new Composite(parent, SWT.FLAT); page.setLayout(new GridLayout()); page.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); createTreeViewer(page); makeActions(); hookContextMenu(); contributeToActionBars(); preferenceListener = new TagsPreferenceListener(); TagSEAPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(preferenceListener); IWorkbenchSiteProgressService service = (IWorkbenchSiteProgressService) getSite().getAdapter(IWorkbenchSiteProgressService.class); if (service != null) { service.showBusyForFamily(TagSEAPlugin.getDefault()); } this.fWorkbenchSelectionListener = new ISelectionListener() { public void selectionChanged(IWorkbenchPart part, ISelection selection) { updateForSelection(part, selection); } }; this.fWaypointViewerFilter = new TagWaypointViewerFilter(); updateForWaypointsFilter(); } /** * */ public void scheduleViewerRefresh() { if (!refreshScheduled) { this.refreshScheduled = true; TimerTask refresher = new TimerTask() { @Override public void run() { Display.getDefault().asyncExec(new Runnable(){ public void run() { if (!refreshScheduled) return; if (treeViewer.getViewer().getControl().isDisposed()) return; treeViewer.refresh(); refreshScheduled = false; IWorkbenchSiteProgressService service = (IWorkbenchSiteProgressService) getSite().getAdapter(IWorkbenchSiteProgressService.class); if (service != null) { service.warnOfContentChange(); } updateSelection(treeViewer.getViewer().getSelection()); } }); } }; new Timer().schedule(refresher, 1000); } } /** * Updates this view's selection according to the given selection (from the tree viewer). * @param selection */ protected void updateSelection(ISelection selection) { if (selection instanceof IStructuredSelection) { IStructuredSelection ss = (IStructuredSelection) selection; List<ITag> tagList = new LinkedList<ITag>(); Iterator<?> it = ss.iterator(); while (it.hasNext()) { TagTreeItem item = (TagTreeItem) it.next(); LinkedList<TagTreeItem> children = new LinkedList<TagTreeItem>(); children.add(item); while (children.size() > 0) { item = children.removeFirst(); ITag tag = item.getTag(); if (tag != null) { tagList.add(tag); } for (TagTreeItem child : item.getChildren()) { children.add(child); } } } IStructuredSelection newSelection = new StructuredSelection(tagList); // check the selection. if (!currentSelection.equals(newSelection)) { currentSelection = newSelection; fireSelectionChanged(newSelection); } } } /** * */ private void contributeToActionBars() { actionGroup.fillActionBars(getViewSite().getActionBars()); // IContributionItem item = getViewSite().getActionBars().getMenuManager().find("view"); // if (item instanceof IMenuManager) { // ((IMenuManager)item).add(fFilterToWaypointsAction); // } IMenuManager manager = getViewSite().getActionBars().getMenuManager(); manager.add(new Separator()); manager.add(toggleTreeAction); manager.add(fFilterToWaypointsAction); } /** * */ private void hookContextMenu() { MenuManager manager = new MenuManager(); manager.setRemoveAllWhenShown(true); manager.addMenuListener(new IMenuListener(){ public void menuAboutToShow(IMenuManager manager) { actionGroup.fillContextMenu(manager); } }); Menu menu = manager.createContextMenu(treeViewer.getViewer().getTree()); treeViewer.getViewer().getControl().setMenu(menu); //getSite().registerContextMenu(manager, treeViewer.getViewer()); } /** * */ private void makeActions() { this.actionGroup = new TagActionGroup(this); this.fFilterToWaypointsAction = new Action("Link to Waypoint Filters",Action.AS_CHECK_BOX) { @Override public void run() { boolean filter = TagSEAPlugin.getDefault().getPluginPreferences().getBoolean(ITagSEAPreferences.FILTER_TAGS_TO_WAYPOINTS); TagSEAPlugin.getDefault().getPluginPreferences().setValue(ITagSEAPreferences.FILTER_TAGS_TO_WAYPOINTS, !filter); updateForWaypointsFilter(); } }; this.fFilterToWaypointsAction.setImageDescriptor(TagSEAPlugin.getDefault().getImageRegistry().getDescriptor(ITagSEAImageConstants.IMG_FILTER_WAYPOINT)); toggleTreeAction = new TagToggleTreeAction(); toggleTreeAction.setText("View As Hierarchy"); toggleTreeAction.setDescription("Toggles the display mode of tags."); toggleTreeAction.setImageDescriptor(TagSEAPlugin.getDefault().getImageRegistry().getDescriptor(ITagSEAImageConstants.IMG_TAG_HIERARCHY)); refreshActions(); } /** * */ private void refreshActions() { IPreferenceStore store = TagSEAPlugin.getDefault().getPreferenceStore(); boolean asTree = store.getBoolean(ITagSEAPreferences.TAGS_VIEW_TREE); toggleTreeAction.setChecked(asTree); if (asTree) { toggleTreeAction.setToolTipText("Uncheck to view tags with flat names"); } else { toggleTreeAction.setToolTipText("Check to view dot-separated tag names as a hierarchy"); } } private void updateForWaypointsFilter() { boolean filter = TagSEAPlugin.getDefault().getPluginPreferences().getBoolean(ITagSEAPreferences.FILTER_TAGS_TO_WAYPOINTS); fFilterToWaypointsAction.setChecked(filter); if (filter) { treeViewer.getViewer().addFilter(fWaypointViewerFilter); getSite().getPage().addSelectionListener(fWorkbenchSelectionListener); } else { treeViewer.getViewer().removeFilter(fWaypointViewerFilter); getSite().getPage().removeSelectionListener(fWorkbenchSelectionListener); } scheduleViewerRefresh(); } /** * @param part * @param selection */ protected void updateForSelection(IWorkbenchPart part, ISelection selection) { if (fWaypointViewerFilter.isImportantSelection(selection)) { scheduleViewerRefresh(); } } /** * */ private void createTreeViewer(Composite parent) { this.treeViewer = new PatternFilteredTree(parent, SWT.FLAT | SWT.BORDER | SWT.MULTI, new CachingTreePatternFilter()); this.treeViewer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); this.treeViewer.getViewer().setContentProvider(new BaseWorkbenchContentProvider()); this.treeViewer.getViewer().setLabelProvider(new TagsViewLabelProvider()); this.treeViewer.getViewer().setSorter(new TagsViewSorter()); boolean asTree = TagSEAPlugin.getDefault().getPreferenceStore().getBoolean(ITagSEAPreferences.TAGS_VIEW_TREE); treeViewer.getViewer().setInput(new TagsTree(!asTree)); treeViewer.getFilterControl().addModifyListener(new ModifyListener(){ public void modifyText(ModifyEvent e) { if (e.widget instanceof Text) { ((TagSEAUI)TagSEAPlugin.getDefault().getUI()).getUIEventModel().fireEvent(TagSEAUIEvent.createViewEvent(TagSEAUIEvent.VIEW_FILTERED, ID, ((Text)e.widget).getText())); } } }); //set up columns Tree tree = treeViewer.getViewer().getTree(); final TreeColumn nameColumn = new TreeColumn(tree, SWT.FLAT | SWT.LEFT); final TreeColumn sizeColumn = new TreeColumn(tree, SWT.FLAT | SWT.LEFT); tree.addControlListener(new ControlListener(){ public void controlMoved(ControlEvent e) { //auto resize the columns Tree tree = (Tree) e.widget; int width = tree.getClientArea().width; sizeColumn.setWidth(30); nameColumn.setWidth(width-30); } public void controlResized(ControlEvent e) { controlMoved(e); } }); Listener openListener = new ItemEditListener(); tree.addListener(SWT.KeyUp, openListener); tree.addListener(SWT.MouseDoubleClick, openListener); tree.addListener(SWT.Selection, openListener); tree.addListener(SWT.Dispose, openListener); treeViewer.getViewer().setColumnProperties(new String[] {"name", "waypointCount"}); tagsListener = new TagsChangedListener(); this.treeSelectionListener = new TreeSelectionChangedListener(); treeViewer.getViewer().addSelectionChangedListener(treeSelectionListener); treeViewer.getViewer().addDragSupport(DND.DROP_MOVE | DND.DROP_COPY, new Transfer[] {TagTreeItemTransfer.getInstance(), TagNameTransfer.getInstance()}, new TagsDragListener(treeViewer.getViewer())); treeViewer.getViewer().addDropSupport(DND.DROP_MOVE, new Transfer[] {TagTreeItemTransfer.getInstance()}, new TagsViewDropListener()); TagSEAPlugin.addTagChangeListener(tagsListener); } /* (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart#setFocus() */ @Override public void setFocus() { // TODO Auto-generated method stub } public TreeViewer getTreeViewer() { return this.treeViewer.getViewer(); } /* (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart#dispose() */ @Override public void dispose() { getSite().getPage().removeSelectionListener(fWorkbenchSelectionListener); super.dispose(); refreshScheduled = false; TagSEAPlugin.removeTagChangeListener(tagsListener); TagSEAPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(preferenceListener); treeViewer.getViewer().removeSelectionChangedListener(treeSelectionListener); actionGroup.dispose(); } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) */ public void addSelectionChangedListener(ISelectionChangedListener listener) { if (selectionListeners.contains(listener)) return; selectionListeners.add(listener); } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection() */ public ISelection getSelection() { treeViewer.getViewer().getSelection(); return currentSelection; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) */ public void removeSelectionChangedListener(ISelectionChangedListener listener) { selectionListeners.remove(listener); } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection) */ public void setSelection(ISelection selection) { this.currentSelection = selection; if (selection instanceof IStructuredSelection) { IStructuredSelection ss = (IStructuredSelection) selection; ITreeSelection treeSelection = createTreeSelection(ss); treeViewer.getViewer().setSelection(treeSelection, true); } fireSelectionChanged(selection); } /** * @param ss * @return */ private ITreeSelection createTreeSelection(IStructuredSelection ss) { List<TreePath> treeItems = new LinkedList<TreePath>(); Iterator<?> it = ss.iterator(); while (it.hasNext()) { Object next = it.next(); if (next instanceof ITag) { ITag tag = (ITag) next; //make a dummy item to select. TreePath path = createTreePath(tag); treeItems.add(path); } } TreeSelection selection = new TreeSelection(treeItems.toArray(new TreePath[treeItems.size()])); return selection; } /** * @param tag * @return */ private TreePath createTreePath(ITag tag) { String[] segments = tag.getName().split("\\."); boolean flat = !TagSEAPlugin.getDefault().getPreferenceStore().getBoolean(ITagSEAPreferences.TAGS_VIEW_TREE); TagTreeItem parent = null; String parentName = ""; TreePath path = TreePath.EMPTY; for (String segment : segments) { TagTreeItem item = new TagTreeItem(parentName + segment, parent, flat); parentName = item.getName() + "."; path = path.createChildPath(item); parent = item; } return path; } private void fireSelectionChanged(ISelection selection) { ISelectionChangedListener[] localListeners = selectionListeners. toArray(new ISelectionChangedListener[selectionListeners.size()]); SelectionChangedEvent event = new SelectionChangedEvent(this, selection); for (ISelectionChangedListener listener : localListeners) { listener.selectionChanged(event); } } }