Java tutorial
/* Kick Assembler plugin - An Eclipse plugin for convenient Kick Assembling Copyright (c) 2012 - P-a Backstrom <pa.backstrom@gmail.com> Based on ASMPlugin - http://sourceforge.net/projects/asmplugin/ Copyright (c) 2006 - Andy Reek, D. Mitte This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.lyllo.kickassplugin.editor; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.runtime.Status; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.viewers.IContentProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.views.contentoutline.ContentOutlinePage; import org.lyllo.kickassplugin.Activator; import org.lyllo.kickassplugin.Constants; import org.lyllo.kickassplugin.Messages; import org.lyllo.kickassplugin.Patterns; /** * Outlinepage for the ASM-Editor. * * @author Andy Reek * @since 13.02.2006 */ public class ASMContentOutlinePage extends ContentOutlinePage { private IEditorInput input; private ASMEditor editor; private ContentProvider contentProvider; /** * The constructor. * * @param editor An ASM-Editor. */ public ASMContentOutlinePage(ASMEditor editor) { this.editor = editor; contentProvider = new ContentProvider(); } public List<String> getLabels() { return this.contentProvider.getLabels(); } public List<String> getMacros() { return this.contentProvider.getMacros(); } public List<String> getConsts() { return this.contentProvider.getConsts(); } public List<String> getFunctions() { return this.contentProvider.getFunctions(); } /** * Sets the input for the outlinepage. * * @param input The new input. */ public void setInput(IEditorInput input) { this.input = input; final TreeViewer viewer = getTreeViewer(); if ((viewer != null) && (viewer.getContentProvider() != null)) { editor.getSite().getShell().getDisplay().asyncExec(new Runnable() { public void run() { Control control = viewer.getControl(); control.setRedraw(false); ITextSelection textselect = (ITextSelection) editor.getSelectionProvider().getSelection(); TreeObject treeobj = getSelectedTreeObject(viewer); viewer.setInput(ASMContentOutlinePage.this.input); viewer.refresh(); viewer.expandAll(); selectTreeObject(viewer, treeobj); editor.getSelectionProvider().setSelection(textselect); control.setRedraw(true); } }); } } /** * Returns the selected element in the tree viewer. * * @param viewer The tree viewer. * * @return The selected element. */ private TreeObject getSelectedTreeObject(TreeViewer viewer) { ISelection selection = viewer.getSelection(); if (!selection.isEmpty()) { if (selection instanceof IStructuredSelection) { Object object = ((IStructuredSelection) selection).getFirstElement(); if (object instanceof TreeObject) { return (TreeObject) object; } } } return null; } /** * Select a given TreeObject in the given TreeViewer. * * @param viewer The given TreeViewer. * @param treeobj The given TreeObject. */ private void selectTreeObject(TreeViewer viewer, TreeObject treeobj) { if (treeobj == null) { return; } IContentProvider icp = viewer.getContentProvider(); if (icp instanceof ContentProvider) { ContentProvider cp = (ContentProvider) icp; TreeObject fto = cp.findEqualTreeObject(treeobj); if (fto != null) { ArrayList<Object> newSelection = new ArrayList<Object>(); newSelection.add(fto); viewer.setSelection(new StructuredSelection(newSelection)); } } } /** * {@inheritDoc} */ public void createControl(Composite parent) { super.createControl(parent); TreeViewer viewer = getTreeViewer(); viewer.setContentProvider(this.contentProvider); viewer.setLabelProvider(new ASMLabelProvider()); viewer.addSelectionChangedListener(this); viewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS); if (input != null) { viewer.setInput(input); } } /** * {@inheritDoc} */ public void selectionChanged(SelectionChangedEvent event) { super.selectionChanged(event); ISelection selection = event.getSelection(); if (selection.isEmpty()) { editor.resetHighlightRange(); } else { if (selection instanceof IStructuredSelection) { Object object = ((IStructuredSelection) selection).getFirstElement(); if (object instanceof TreeObject) { try { Position position = (Position) ((TreeObject) object).getData(); if (position != null) { editor.setHighlightRange(position.offset, 0, true); editor.getSelectionProvider() .setSelection(new TextSelection(position.offset, position.length)); } } catch (IllegalArgumentException x) { editor.resetHighlightRange(); } } } } } /** * The ContentProvider for the TreeViewer in ContentOutlinePage. * * @author Andy Reek * @since 08.09.2006 */ private class ContentProvider implements ITreeContentProvider { private IEditorInput input; private TreeObject functions = new TreeObject(Messages.TREEOBJECT_PROCEDURE_NAME, Constants.TREEOBJECT_TYPE_ROOT_PROCEDURE); private TreeObject macros = new TreeObject(Messages.TREEOBJECT_MACRO_NAME, Constants.TREEOBJECT_TYPE_ROOT_MACRO); private TreeObject consts = new TreeObject(Messages.TREEOBJECT_CONST_NAME, Constants.TREEOBJECT_TYPE_ROOT_CONST); private TreeObject labelsAndSegments = new TreeObject(Messages.TREEOBJECT_LABEL_NAME, Constants.TREEOBJECT_TYPE_ROOT_LABEL); public List<String> getLabels() { List<String> list = removeEqualSigns(getChildren(labelsAndSegments, Constants.TREEOBJECT_TYPE_LABEL)); Collections.sort(list); return list; } public List<String> getConsts() { List<String> list = removeEqualSigns(getChildren(consts, Constants.TREEOBJECT_TYPE_CONST)); Collections.sort(list); return list; } public List<String> getFunctions() { List<String> list = getChildren(functions, Constants.TREEOBJECT_TYPE_PROCEDURE); Collections.sort(list); return list; } public List<String> getMacros() { List<String> list = getChildren(macros, Constants.TREEOBJECT_TYPE_MACRO); Collections.sort(list); return list; } protected List<String> removeEqualSigns(List<String> list) { List<String> cleanLabels = new ArrayList<String>(); { Pattern p = Patterns.EQUALS_PATTERN; for (String s : list) { cleanLabels.add(p.matcher(s).replaceAll("")); } } return cleanLabels; } private List<String> getChildren(TreeObject treeObject, int type) { return getChildrenAsList(type, treeObject.getChildren()); } protected List<String> getChildrenAsList(int typeFilter, Object[] children) { List<String> list = new ArrayList<String>(); if (children != null) { for (Object segment : children) { if (((TreeObject) segment).getType() == typeFilter) { list.add(segment.toString()); } else { Object[] labels = ((TreeObject) segment).getChildren(); if (labels != null) { for (Object label : labels) { list.add(label.toString()); } } } } } return list; } /** * {@inheritDoc} */ public Object[] getChildren(Object parentElement) { if (parentElement instanceof TreeObject) { return ((TreeObject) parentElement).getChildren(); } return null; } /** * {@inheritDoc} */ public Object getParent(Object element) { if (element instanceof TreeObject) { return ((TreeObject) element).getParent(); } return null; } /** * {@inheritDoc} */ public boolean hasChildren(Object element) { if (element instanceof TreeObject) { return (((TreeObject) element).getChildren().length > 0); } return false; } /** * {@inheritDoc} */ public Object[] getElements(Object inputElement) { if (inputElement == input) { ArrayList<TreeObject> objects = new ArrayList<TreeObject>(); if (labelsAndSegments.getChildren().length > 0) { objects.add(labelsAndSegments); } if (functions.getChildren().length > 0) { objects.add(functions); } if (macros.getChildren().length > 0) { objects.add(macros); } if (consts.getChildren().length > 0) { objects.add(consts); } return objects.toArray(new Object[0]); } return null; } /** * {@inheritDoc} */ public void dispose() { input = null; } /** * {@inheritDoc} */ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { if (oldInput instanceof IEditorInput) { input = null; } if (newInput instanceof IEditorInput) { input = (IEditorInput) newInput; parse(); } } /** * Finds an existing TreeObject in the tree model. * * @param treeobj The given TreeObject. * * @return The TreeObject, if found. Or null if not found. */ private TreeObject findEqualTreeObject(TreeObject treeobj) { if (treeobj == null) { return null; } if (functions.equals(treeobj)) { return functions; } if (macros.equals(treeobj)) { return macros; } if (labelsAndSegments.equals(treeobj)) { return labelsAndSegments; } if (consts.equals(treeobj)) { return consts; } int i = 0; TreeObject to = null; Object[] o = functions.getChildren(); for (i = 0; i < o.length; i++) { if (o[i] instanceof TreeObject) { to = (TreeObject) o[i]; if (to.equals(treeobj)) { return to; } } } o = macros.getChildren(); for (i = 0; i < o.length; i++) { if (o[i] instanceof TreeObject) { to = (TreeObject) o[i]; if (to.equals(treeobj)) { return to; } } } o = labelsAndSegments.getChildren(); for (i = 0; i < o.length; i++) { if (o[i] instanceof TreeObject) { to = (TreeObject) o[i]; if (to.equals(treeobj)) { return to; } } } o = consts.getChildren(); for (i = 0; i < o.length; i++) { if (o[i] instanceof TreeObject) { to = (TreeObject) o[i]; if (to.equals(treeobj)) { return to; } } } return null; } /** * Parse the new input and build up the tree. */ private void parse() { functions.setChildren(null); macros.setChildren(null); labelsAndSegments.setChildren(null); consts.setChildren(null); IDocument document = editor.getDocumentProvider().getDocument(editor.getEditorInput()); if (document != null) { int lines = document.getNumberOfLines(); int lineOffset, linelen, matchStart, matchEnd, startOffset, length; String stringLine = ""; String stringLineLower = ""; Pattern pattern = null; Matcher matcher = null; TreeObject child = null; lineOffset = 0; linelen = 0; matchStart = 0; matchEnd = 0; startOffset = 0; length = 0; for (int line = 0; line < lines; line++) { try { lineOffset = document.getLineOffset(line); linelen = document.getLineLength(line); stringLine = document.get(lineOffset, linelen); stringLineLower = stringLine.toLowerCase(); if (stringLineLower.contains(".const") || stringLineLower.contains(".var")) { pattern = Patterns.CONSTVAR_PATTERN; matcher = pattern.matcher(stringLine); if (matcher.matches()) { child = new TreeObject(matcher.group(2) + matcher.group(3), Constants.TREEOBJECT_TYPE_CONST); child.setData(new Position(lineOffset, 1)); consts.addChild(child); } } if (stringLineLower.indexOf(".function") > -1) { pattern = Patterns.FUNCTION_PATTERN; matcher = pattern.matcher(stringLine); if (matcher.find()) { child = new TreeObject(matcher.group(1), Constants.TREEOBJECT_TYPE_PROCEDURE); child.setData(new Position(lineOffset, 1)); functions.addChild(child); } } if (stringLineLower.indexOf(".macro") > -1) { pattern = Patterns.MACRO_PATTERN; matcher = pattern.matcher(stringLine); if (matcher.find()) { child = new TreeObject(matcher.group(1).trim(), Constants.TREEOBJECT_TYPE_MACRO); child.setData(new Position(lineOffset, 1)); macros.addChild(child); } } if (stringLineLower.indexOf(".pseudocommand") > -1) { pattern = Patterns.PSEUDOCOMMAND_PATTERN; matcher = pattern.matcher(stringLine); if (matcher.find()) { child = new TreeObject(matcher.group(1).replaceAll("\\{.*$", "").trim(), Constants.TREEOBJECT_TYPE_MACRO); child.setData(new Position(lineOffset, 1)); macros.addChild(child); } } child = null; if (stringLineLower.indexOf(".label") > -1) { pattern = Patterns.LABEL_PATTERN; matcher = pattern.matcher(stringLine); if (matcher.find()) { child = new TreeObject(matcher.group(1).trim(), Constants.TREEOBJECT_TYPE_LABEL); child.setData(new Position(lineOffset, 1)); } } if (stringLineLower.indexOf(":") > -1) { pattern = Patterns.LABEL_PATTERN_ALT; matcher = pattern.matcher(stringLine); if (matcher.find()) { matchStart = matcher.start(1); matchEnd = matcher.end(1); startOffset = lineOffset + matchStart; length = lineOffset + matchEnd - startOffset; child = new TreeObject(stringLine.substring(matchStart, matchEnd), Constants.TREEOBJECT_TYPE_LABEL); child.setData(new Position(startOffset, length)); } } if (child != null) { TreeObject node = labelsAndSegments; int sz = labelsAndSegments.getChildren().length; if (sz > 0 && ((TreeObject) labelsAndSegments.getChild(sz - 1)) .getType() == Constants.TREEOBJECT_TYPE_SEGMENT) { node = ((TreeObject) labelsAndSegments.getChild(sz - 1)); } node.addChild(child); } if (stringLineLower.indexOf(".pc") > -1 || stringLineLower.indexOf(".pseudopc") > -1) { child = new TreeObject(stringLineLower.replace("{", "").trim(), Constants.TREEOBJECT_TYPE_SEGMENT); child.setData(new Position(lineOffset, 1)); labelsAndSegments.addChild(child); } } catch (BadLocationException e) { Activator.getDefault().getLog().log(new Status(Status.ERROR, Constants.PLUGIN_ID, Status.OK, Messages.BADLOCATION_ERROR, e)); } } } } } }