/******************************************************************************* * Copyright 2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. * 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 * IBM Corporation *******************************************************************************/ package ca.uvic.cs.tagsea.editing; import java.util.Arrays; import java.util.HashSet; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.jface.text.IDocument; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Item; import org.eclipse.swt.widgets.MessageBox; import ca.uvic.cs.tagsea.TagSEAPlugin; import ca.uvic.cs.tagsea.core.Tag; import ca.uvic.cs.tagsea.core.Waypoint; import ca.uvic.cs.tagsea.core.resource.ResourceUtil; import ca.uvic.cs.tagsea.editing.events.ItemDragEvent; import ca.uvic.cs.tagsea.editing.events.TreeItemCopyEvent; import ca.uvic.cs.tagsea.editing.events.TreeItemDeleteEvent; import ca.uvic.cs.tagsea.editing.events.TreeItemListener; import ca.uvic.cs.tagsea.editing.events.TreeItemMoveEvent; import ca.uvic.cs.tagsea.editing.events.TreeItemRenameEvent; import ca.uvic.cs.tagsea.monitoring.TagSEARefactorEvent; import ca.uvic.cs.tagsea.monitoring.internal.Monitoring; import ca.uvic.cs.tagsea.ui.views.TagsView; import ca.uvic.cs.tagsea.util.DescendingWaypointComparator; /** * This class gets notified when a UI refactor event occurs: move, * copy, rename, or delete. When an event occurs this class will update * the underlying tags model.dra * * @author Chris Callendar */ public class TagTreeItemListener implements TreeItemListener { private enum RefactorAction { Delete, Rename, Move, } private TagsView view; public TagTreeItemListener(TagsView tagsView) { this.view = view; } /** * Does nothing. */ public void beforeMove(TreeItemMoveEvent event) { if (event.data instanceof Tag) { //Tag tag = (Tag) event.data; } } /** * If any keyed data gets stored in the tag TreeItems, then * here is where you copy it to the new item. */ public void copyData(TreeItemCopyEvent event) { /* e.g. TreeItem oldItem = event.item; TreeItem newItem = event.newItem; newItem.setData("KEY", oldItem.getData("KEY")) */ } /** Does nothing. */ public void afterCopy(TreeItemCopyEvent event) { } public void afterMove(TreeItemMoveEvent event) { if (event.data instanceof Tag) { Tag tag = (Tag) event.data; Tag parentTag = null; if (event.parent != null && (event.parent.getData() instanceof Tag)) { parentTag = (Tag) event.parent.getData(); } moveTag(tag, parentTag); } } /** Does nothing. */ public void beforeRename(TreeItemRenameEvent event) { // don't need to do anything - no rename has happened yet } public void afterRename(TreeItemRenameEvent event) { if (event.data instanceof Tag) { renameTag((Tag)event.data, event.newName); } } public void beforeDelete(TreeItemDeleteEvent event) { if (event.data instanceof Tag) { Tag tag = (Tag) event.data; Waypoint[] wps = tag.getAllWaypoints(); int wpCount = wps.length; // if multiple waypoints are being deleted, prompt the user if (wpCount > 1) { MessageBox delParent = new MessageBox(event.tree.getShell(), SWT.YES | SWT.NO); delParent.setMessage("Deleting " + wpCount + " waypoints. Do you want to continue?"); delParent.setText("Delete Waypoints?"); int dialogReturn = delParent.open(); if (dialogReturn == SWT.NO) { // cancel the deletion event.doit = false; return; } } } } public void afterDelete(TreeItemDeleteEvent event) { if (event.data instanceof Tag) { deleteTag((Tag)event.data); } else if (event.data instanceof Waypoint) { deleteTag(((Waypoint)event.data).getTag()); } } /** Does nothing. */ public void dragStart(ItemDragEvent event) {} /** Does nothing. */ public void dragOver(ItemDragEvent event) {} /** Does nothing. */ public void drop(ItemDragEvent event) {} /** Does nothing */ public void finishedMove(Item[] movedData) { } /** Does nothing */ public void finishedDelete() { } /** * Moves the given tag to the new parent (can be null). * @param tag the tag to move * @param newParent the new parent for the tag - can be null to make tag a root */ public void moveTag(Tag tag, Tag newParent) { if (tag.getParent() != newParent) { refactor(RefactorAction.Move, tag, null, newParent); } } /** * Deletes the given tag. * @param tag the tag to delete */ public void deleteTag(Tag tag) { refactor(RefactorAction.Delete, tag, null, null); } /** * Renames the given tag. * @param tag the tag to rename * @param newName the new name - can't be null */ public void renameTag(Tag tag, String newName) { if ((newName != null) && !newName.equals(tag.getName())) { refactor(RefactorAction.Rename, tag, newName, null); } } /** * Does the refactoring - deletes, renames, or moves a tag. * @param action the action to perform - delete, rename or move * @param tag the tag being acted upon * @param newName the new name (rename action only, null otherwise) * @param newParent the new parent (move action only, null otherwise). Can be null when moving. * If the newParent is null, then the tag will have a parent Tag with a blank name. */ private void refactor(RefactorAction action, Tag tag, String newName, Tag newParent) { Waypoint[] allWaypoints = tag.getAllWaypoints(); if (allWaypoints.length > 1) { // sort the waypoints based on resource and line number - descending order // this must be done so that the marker's positions don't get out of whack Arrays.sort(allWaypoints, new DescendingWaypointComparator()); } // now go through each file and change the tag name final TagSEAPlugin plugin = TagSEAPlugin.getDefault(); // first save any changes to the editors if (plugin != null) { // this check is only for testing purposes } // store the resource and offset keys so that waypoints on the same line aren't done twice HashSet<String> completedResources = new HashSet<String>(); IFile resource = null; for (Waypoint wp : allWaypoints) { Tag wpTag = wp.getTag(); IMarker marker = wp.getMarker(); if ((marker != null) && marker.exists()) { resource = (IFile)marker.getResource(); IDocument doc = ResourceUtil.getDocument(resource); int offset = marker.getAttribute(IMarker.CHAR_START, 0); int length = marker.getAttribute(IMarker.CHAR_END, offset) - offset; // check if this resource and offset (same line) has already been refactored String key = resource.getFullPath().toString() + "_" + offset; if (!completedResources.contains(key)) { boolean okay = false; try { Object oldValue; switch (action) { case Delete : oldValue = tag.getParent(); okay = TagRefactoring.deleteTagInDocument(tag, doc, offset, length); if (wpTag.getParent() != null) { wpTag.getParent().removeWaypoint(wp); } marker.delete(); if (okay) { Monitoring.getDefault().fireEvent(new TagSEARefactorEvent(TagSEARefactorEvent.Refactoring.Delete, tag, oldValue)); } break; case Rename : oldValue = tag.getName(); okay =TagRefactoring.renameTagInDocument(tag, newName, doc, offset, length); if (okay) { Monitoring.getDefault().fireEvent(new TagSEARefactorEvent(TagSEARefactorEvent.Refactoring.Rename, tag, oldValue)); } break; case Move : oldValue = tag.getParent(); // note we want to use the tag variable, not the wpTag because they could be different // what has moved is tag, wpTag could be a child of tag. okay = TagRefactoring.moveTagInDocument(tag, newParent, doc, offset, length); if (okay) { Monitoring.getDefault().fireEvent(new TagSEARefactorEvent(TagSEARefactorEvent.Refactoring.Move, tag, oldValue)); } break; } completedResources.add(key); } catch (Exception e) { TagSEAPlugin.log("Error refactoring (" + action.name() + ")", e); e.printStackTrace(); } } else { //System.out.println("Already done " + key); } } } completedResources.clear(); // now update the Tags model switch (action) { case Delete : // remove the tag from its parent Tag parent = tag.getParent(); if (parent != null) { parent.removeChild(tag); tag.setParent(null); } break; case Rename : // update the tag name, ids (children too), and waypoint keywords tag.rename(newName); break; case Move : // update the tags parent if (tag.getParent() != null) { tag.getParent().removeChild(tag); } if (newParent == null) { if (plugin != null) { // for testing purposes tag = plugin.getTagCollection().addRootTag(tag); } else { tag.setParent(new Tag()); } } else { tag = newParent.addChild(tag); } break; } // now save all our changes if (plugin != null && resource != null) { //@tag bug(1524158) : must save in the actual file, not in the editor. ResourceUtil.commit(resource); //plugin.getWorkbench().saveAllEditors(false); } // and refresh the views // if(fTagsView!=null) // { // fTagsView.getTagsComposite().refreshTagsViewer(null); // fTagsView.getWaypointsComposite().getWaypointsTableViewer().refresh(true); // } } }