/**
* ItemUtils.java
* Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
*
* 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 3 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, see .
*/
package org.expeditee.items;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.expeditee.core.Colour;
import org.expeditee.core.bounds.AxisAlignedBoxBounds;
import org.expeditee.gui.DisplayController;
import org.expeditee.gui.DisplayController.TwinFramesSide;
import org.expeditee.gui.Frame;
import org.expeditee.gui.FrameUtils;
import org.expeditee.gui.FreeItems;
import org.expeditee.gui.Vector;
import org.expeditee.items.Item.HighlightMode;
import org.expeditee.items.widgets.InteractiveWidgetInitialisationFailedException;
import org.expeditee.items.widgets.InteractiveWidgetNotAvailableException;
import org.expeditee.items.widgets.Widget;
import org.expeditee.items.widgets.WidgetCorner;
import org.expeditee.items.widgets.WidgetEdge;
import org.expeditee.network.FrameShare;
import org.expeditee.settings.folders.FolderSettings;
//Static methods that provide functions for the objects\
//mostly to transform values (string -> color etc).
/**
* Static methods that provide functions for use in Items.
*/
public class ItemUtils {
// Tag constants
public static final int TAG_SORT = 0;
public static final int TAG_JOIN = 1;
public static final int TAG_INDENT = 2;
public static final int TAG_OVERLAY = 3;
public static final int TAG_ACTIVE_OVERLAY = 4;
public static final int TAG_IMAGE = 5;
public static final int TAG_ITEM_TEMPLATE = 6;
public static final int TAG_ANNOTATION_TEMPLATE = 7;
public static final int TAG_CODE_COMMENT_TEMPLATE = 8;
public static final int TAG_MENU = 9;
public static final int TAG_MENU_NEXT = 10;
public static final int TAG_PARENT = 11;
public static final int TAG_LITERAL = 12;
public static final int TAG_FRAME_IMAGE = 13;
public static final int TAG_BACKUP = 14;
public static final int TAG_POINTTYPE = 15;
// Brook: Im claiming this number!
public static final int TAG_IWIDGET = 16;
public static final int TAG_DOT_TEMPLATE = 17;
public static final int TAG_STAT_TEMPLATE = 18;
public static final int TAG_VECTOR = 19;
public static final int TAG_ACTIVE_VECTOR = 21;
public static final int TAG_BITMAP_IMAGE = 20;
public static final int TAG_MIN = 0;
public static final int TAG_MAX = 21;
/**
* Determines if the given List of Items contains an Item that is one of the
* pre-defined tags.
*
* @param items
* The list of Items to search through
* @param tag
* The Tag to search for, this should correspond to one of the
* predefined constants in this class
* @return True if an Item was found that is the given Tag, False otherwise.
*/
public static boolean ContainsTag(Collection- items, int tag) {
return ContainsTag(items, GetTag(tag));
}
public static boolean ContainsTag(Collection
- items, String tag) {
return (FindTag(items, tag) != null);
}
public static boolean ContainsExactTag(Collection
- items, int tag) {
return ContainsExactTag(items, GetTag(tag));
}
public static boolean ContainsExactTag(Collection
- items, String tag) {
return (FindExactTag(items, tag) != null);
}
/**
* Searches the given List of Items for an Item that is one of the
* pre-defined tags.
*
* @param items
* The list of Items to search through
* @param tag
* The Tag to search for, this should correspond to one of the
* predefined constants in this class
* @return The Item that is the given tag if one is found, or False if none
* is found
*/
public static Item FindTag(List
- items, int tag) {
return FindTag(items, GetTag(tag));
}
/**
* Searches the given List of Items for an Item that is the given tag
*
* @param items
* The list of Items to search through
* @param toFind
* The Tag to search for, this should include the at (@) symbol
* @return The Item that is the given tag if one is found, or False if none
* is found
*/
public static Text FindTag(Collection
- items, String toFind) {
for (Item i : items) {
if (i instanceof Text && i.isAnnotation()) {
if (((Text) i).startsWith(toFind)) {
return (Text) i;
}
}
}
return null;
}
public static Item FindExactTag(Collection
- items, String toFind) {
for (Item i : items) {
if (i instanceof Text && i.isAnnotation()) {
if (((Text) i).getText().trim().equalsIgnoreCase(toFind)) {
return i;
}
}
}
return null;
}
public static Item FindExactTag(List
- items, int tag) {
return FindExactTag(items, GetTag(tag));
}
/**
* Determines if the given Item is one of the pre-defined tags in this class
*
* @param toCheck
* The Item to check
* @param tag
* The tag to check the Item against, this should correspond to
* one of the constants defined in this class
* @return True if the Item matches the given tag, false otherwise
*/
public static boolean startsWithTag(Item toCheck, int tag) {
return startsWithTag(toCheck, GetTag(tag));
}
public static boolean startsWithTag(Item toCheck, int tag, boolean hasValue) {
return startsWithTag(toCheck, GetTag(tag), hasValue);
}
/**
* Checks if the given Item begins with the desired tag (case insensitive).
*
* @param toCheck
* The Item to check for the given tag
* @param tag
* The tag to check for in the given Item
* @param tagOnly
* True if the tag does not have a value
* @return True if the tag is found in the given Item, False otherwise.
*/
public static boolean startsWithTag(Item toCheck, String tag,
boolean valueAllowed) {
if (!(toCheck instanceof Text)) {
return false;
}
Text txt = (Text) toCheck;
String value = ItemUtils.StripTag(txt.getText(), tag);
if (value == null) {
return false;
}
return valueAllowed || value.equals("");
}
/**
* Checks if the item begins with the desired tag.
*
* @param toCheck
* @param tag
* @return
*/
public static boolean startsWithTag(Item toCheck, String tag) {
return startsWithTag(toCheck, tag, true);
}
/**
* Strips off the given tag from the given String, and returns wathever is
* left. Dont put the colon after tags as it is not needed.
*
* @param toStrip
* The String to strip the Tag from
* @param tag
* The tag to remove from the String
* @return The String that results from removing the given Tag from the
* given String, or null if the given String is not the given Tag
*/
public static String StripTag(String toStrip, String tag) {
if (toStrip == null) {
return null;
}
toStrip = toStrip.trim();
if (!toStrip.toLowerCase().startsWith(tag.toLowerCase())) {
return null;
}
if (toStrip.length() == tag.length()) {
return "";
}
// remove tag and ensure the char is the tag separator
char separator = toStrip.charAt(tag.length());
if (separator != ':') {
return null;
}
if (toStrip.length() == tag.length() + 1) {
return "";
}
return toStrip.substring(tag.length() + 1).trim();
}
/**
* Strips the first character from a string if it is the tag symbol and
* returns the remainder.
*
* @param toStrip
* the string to be stripped
* @return the stripped version of the string.
*/
public static String StripTagSymbol(String toStrip) {
// there must be something left after stripping
if (toStrip != null) {
toStrip = toStrip.trim();
if (toStrip.length() > 0) {
if (toStrip.charAt(0) == '@') {
return toStrip.substring(1);
}
}
}
return toStrip;
}
/**
* Converts the given int to the String tag. The int should correspond to
* one of the constants in this class, if it does not this method will
* return null.
*
* @param tag
* The int corresponding to the constants in this class of which
* tag to return
* @return The String representation of the given Tag, or null if the given
* value does not have a tag associated
*/
public static String GetTag(int tag) {
// TODO refactor so that this uses a map for INT to tags
switch (tag) {
case TAG_SORT:
return "@sort";
case TAG_JOIN:
return "@join";
case TAG_INDENT:
return "@indent";
case TAG_OVERLAY:
return "@o";
case TAG_VECTOR:
return "@v";
case TAG_ACTIVE_VECTOR:
return "@av";
case TAG_ACTIVE_OVERLAY:
return "@ao";
case TAG_IMAGE:
return "@i";
case TAG_ITEM_TEMPLATE:
return "@itemtemplate";
case TAG_ANNOTATION_TEMPLATE:
return "@annotationtemplate";
case TAG_STAT_TEMPLATE:
return "@stattemplate";
case TAG_CODE_COMMENT_TEMPLATE:
return "@commenttemplate";
case TAG_MENU:
return "@menu";
case TAG_MENU_NEXT:
return "@nextmenu";
case TAG_PARENT:
return "@parent";
case TAG_LITERAL:
return "@lit";
case TAG_FRAME_IMAGE:
return "@f";
case TAG_BITMAP_IMAGE:
return "@b";
case TAG_BACKUP:
return "@old";
case TAG_POINTTYPE:
return "@pointtype";
case TAG_IWIDGET:
return "@iw";
case TAG_DOT_TEMPLATE:
return "@dottemplate";
default:
return null;
}
}
/**
* Creates a picture object from the information stored in the given Text
* object.
* The paths searched are in the following order:
* /images/
* the source text as a relative path (from program root folder).
* the source text as an absolute path
*
* If the Image file cannot be found on disk null is returned.
*
* @param source
* The Text file containing the Picture information
* @return The Picture object representing the file, or Null if the file is
* not found.
*/
public static Picture CreatePicture(Text source, boolean tryRemote) {
String text = source.getText();
String path = "";
String fileName = "";
String size = "";
try {
// remove @i tag
text = text.replaceFirst("@i:", "");
text = text.replaceAll("\n", "");
text = text.trim();
int fileSuffixChar = text.indexOf('.');
if (fileSuffixChar < 0) {
return null;
}
int endOfFileName = text.indexOf(' ', fileSuffixChar);
if (endOfFileName < 0) {
path = text;
size = "";
} else {
path = text.substring(0, endOfFileName);
size = text.substring(endOfFileName).trim();
}
fileName = path;
if (!fileName.equals(Picture.REDACTED_IMAGE_NAME)) {
// try images subdirectory
File file = null;
for (String dir : FolderSettings.ImageDirs.getAbsoluteDirs()) {
file = new File(dir + path);
if (file.exists() && !file.isDirectory()) {
break;
}
}
if (file == null || !file.exists() || file.isDirectory()) {
file = new File(path);
}
// try relative path
if (!file.exists() || file.isDirectory()) {
URL picture = new Object().getClass().getResource(path);
// decode to remove %20 in windows folder names
if (picture != null) {
try {
path = URLDecoder.decode(picture.getFile(), "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} else {
path = file.getPath();
}
// if the image isn't found by now, try remote servers
file = new File(path);
if (!file.exists() || file.isDirectory()) {
if(tryRemote && FrameShare.getInstance().loadImage(fileName, null)) {
// call CreatePicture again, but with tryRemote set to false so we won't get into an infinite loop
// if something goes wrong with finding the downloaded image
return CreatePicture(source, false);
}
return null;
}
}
} catch (Exception e) {
return null;
}
try {
Picture pic = new Picture(source, fileName, path, size);
return pic;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Picture CreatePicture(Text source) {
return CreatePicture(source, true);
}
/**
* Creates a deep copy of the given List of Items.
*
* @param toCopy
* The list of Items to copy
* @return A list containing a copy of all Items in the given List
*/
public static List- CopyItems(Collection
- toCopy) {
return CopyItems(toCopy, false, null);
}
public static List
- CopyItems(Collection
- toCopy, Vector v) {
return CopyItems(toCopy, false, v);
}
public static List
- CopyItems(Collection
- toCopy, boolean extrude) {
return CopyItems(toCopy, extrude, null);
}
public static List
- CopyItems(Collection
- toCopy,
boolean extrude, Vector v) {
// The copies to return
List
- copies = new ArrayList
- ();
// list of dots at the end of lines
Collection
- lineEnds = new LinkedHashSet
- ();
Collection lines = new LinkedHashSet();
Collection xrayables = new LinkedHashSet();
Collection constraints = new LinkedHashSet();
Collection
- singles = new LinkedHashSet
- ();
Map
- lineEndMap = new HashMap
- ();
// Widgets are super special
List widgets = new ArrayList();
for (Item i : toCopy) {
// Dont copy parts of a vector
if (i == null || !i.hasPermission(UserAppliedPermission.copy)) {
continue;
}
// BROOK
if (i instanceof WidgetCorner) { // dont add these
if (!widgets.contains(((WidgetCorner) i).getWidgetSource()))
{
widgets.add(((WidgetCorner) i).getWidgetSource());
// BROOK
}
} else if (i instanceof WidgetEdge) { // dont add these
// lines are recreated later
} else if (i instanceof Line) {
lines.add((Line) i);
} else if (i instanceof XRayable) {
xrayables.add((XRayable) i);
} else {
if (i.isLineEnd()) {
lineEnds.add(i);
constraints.addAll(i.getConstraints());
} else {
singles.add(i);
}
}
}
// Dont copy the other items that are part of the circle
for (XRayable x : xrayables) {
Collection
- connected = x.getConnected();
singles.removeAll(connected);
lineEnds.removeAll(connected);
lines.removeAll(connected);
Item xCopy = x.copy();
copies.addAll(xCopy.getConnected());
// Scale items that are from a vector frame
if (v != null) {
scaleItem(v, xCopy);
}
}
// copy all single items
for (Item i : singles) {
Item copy = i.copy();
Frame parent = i.getParent();
if (parent != null) {
// Items copied from overlay will be anchored onto the current
// frame
copy.setParent(parent);
// if this is the frame name, make sure the frame is saved (in
// case it is a TDFC frame)
if (i.isFrameName()) {
parent.setChanged(true);
}// check if the item is being copied from a vector
else if (v != null) {
// Find the vector this item is from
assert (v.Frame == parent);
scaleItem(v, copy);
}
}
copies.add(copy);
}
// replace line ends with their copies
// this is done here so that copied lines can still share end points
for (Item i : lineEnds) {
// create a copy of the line end
Item copy = i.copy();
copy.removeAllLines();
copy.removeAllConstraints();
if (extrude) {
Frame frame = i.getParentOrCurrentFrame();
Line newLine = new Line(i, copy, frame.getNextItemID());
// make sure overlay items are put back on the overlay
newLine.setParent(frame);
frame.addItem(newLine);
copies.add(newLine);
}
copies.add(copy);
lineEndMap.put(i, copy);
// Scale items that are from a vector frame
if (v != null) {
scaleItem(v, copy);
}
}
// recreate lines
for (Line line : lines) {
Line lineCopy = line.copy();
// get the lineEnd we copied above if it is in the MAPPING
Item originalLineEnd = line.getEndItem();
Item actualLineEnd = lineEndMap.get(originalLineEnd);
if (actualLineEnd == null) {
lineCopy.setEndItem(originalLineEnd);
} else {
lineCopy.setEndItem(actualLineEnd);
}
Item originalLineStart = line.getStartItem();
Item actualLineStart = lineEndMap.get(originalLineStart);
if (actualLineStart == null) {
lineCopy.setStartItem(originalLineStart);
} else {
lineCopy.setStartItem(actualLineStart);
}
copies.add(lineCopy);
}
// recreate constraints
for (Constraint c : constraints) {
Item start = lineEndMap.get(c.getStart());
Item end = lineEndMap.get(c.getEnd());
int id = start.getParent().getNextItemID();
if (start != null && end != null) {
new Constraint(start, end, id, c.getType());
}
}
// BROOK
for (Widget iw : widgets) {
try {
Widget icopy = iw.copy();
copies.addAll(icopy.getItems());
} catch (InteractiveWidgetNotAvailableException e) {
e.printStackTrace();
} catch (InteractiveWidgetInitialisationFailedException e) {
e.printStackTrace();
}
}
// Make sure filled rectangles are shown filled on vector overlays
if (v != null) {
EnclosedCheck(copies);
}
return copies;
}
/**
* Attempts to create a new line that starts from the given Item
* ('unreeling'). The Item must already have at least one line, and not be a
* line itself to be unreeled from.
*
* @param toUnreelFrom
* The Item that will be one end point of the new line
* @return A List containing the newly created Item and Line that unreel
* from the given Item, or null if this Item cannot be unreeled
* from.
*/
public static List
- UnreelLine(Item toUnreelFrom, boolean constrain) {
// the Item must already have one line to be unreeled from
if (toUnreelFrom == null || toUnreelFrom.getLines().size() < 1) {
return null;
}
List
- unreel = new ArrayList
- (2);
unreel.add(toUnreelFrom);
unreel.addAll(toUnreelFrom.getLines());
return UnreelLine(unreel, constrain);
}
/**
* Attempts to create a new line that starts from the given list of Items
* ('unreeling'). The List must contain only one non-line Item. The non-line
* Item must already have at least one line to be unreeled from.
*
* @param toUnreel
* The List containing the Item that will be one end point of the
* new line
* @return A List of the newly created Item and Line that unreel from the
* Item in the given List, or null if this List cannot be unreeled
* from.
*/
public static List
- UnreelLine(List
- toUnreel, boolean constrain) {
Item origEnd = null;
// find the end being unreeled from
for (Item item : toUnreel) {
// we dont want to unreel anything other than lines
if (item.hasEnclosures()
|| !(item.isLineEnd() || item instanceof Line)) {
return null;
}
// find the dot to unreel from
if (item.isLineEnd()) {
// if there are multiple ends in the list, return
if (origEnd != null) {
return null;
}
origEnd = item;
}
}
// copy the original endpoint
Item copy = origEnd.copy();
origEnd.setHighlightMode(HighlightMode.None);
origEnd.setHighlightColorToDefault();
copy.removeAllLines();
copy.removeAllConstraints();
for (Line l : origEnd.getLines()) {
l.invalidateAll();
}
// create a new line
Frame currentFrame = DisplayController.getCurrentFrame();
Line line = new Line(origEnd, copy, currentFrame.getNextItemID());
// if the previous line was constrained then make the new line
// constrained if it was a single line
// TODO add later a diagonal constraint if getLines() == 3 or 4
Collection constraints = origEnd.getConstraints();
if (constrain && constraints.size() > 0 && origEnd.getLines().size() == 2) {
Integer type = null;
for (Constraint c : constraints) {
if (c.getType() == Constraint.HORIZONTAL) {
type = Constraint.VERTICAL;
} else if (c.getType() == Constraint.VERTICAL) {
type = Constraint.HORIZONTAL;
}
if (c.getType() == Constraint.DIAGONAL_NEG) {
type = Constraint.DIAGONAL_POS;
} else if (c.getType() == Constraint.DIAGONAL_POS) {
type = Constraint.DIAGONAL_NEG;
}
}
if (type != null) {
new Constraint(origEnd, copy, currentFrame.getNextItemID(), type);
}
}
// copy.setFloating(true);
origEnd.setArrowheadLength(0);
// copy.setArrowheadLength(0);
List
- toReturn = new LinkedList
- ();
toReturn.add(copy);
toReturn.add(line);
return toReturn;
}
public static void New() {
EnclosedCheck(DisplayController.getCurrentFrame().getSortedItems());
}
public static void Old() {
OldEnclosedCheck(DisplayController.getCurrentFrame().getSortedItems());
}
/**
* Updates the connectedToAnnotation flags for all items
*/
public static void UpdateConnectedToAnnotations(Collection
- items) {
// get all lineEnds on the Frame
Collection
- lineEnds = new LinkedHashSet
- ();
for (Item i : items) {
i.setConnectedToAnnotation(false);
if (i.isLineEnd()) {
lineEnds.add(i);
}
}
// if there are no line endpoints on the Frame, then there can't be an
// enclosure
if (lineEnds.size() == 0) {
return;
}
// Now find go through line ends and see if any are annotation items
while (lineEnds.size() > 0) {
Item item = lineEnds.iterator().next();
// If its an annotation item then set the flag for all its connected
// items
if (item.isAnnotation()) {
Collection
- connected = item.getAllConnected();
for (Item i : connected) {
i.setConnectedToAnnotation(true);
}
lineEnds.removeAll(connected);
}
lineEnds.remove(item);
}
}
/**
* Checks through all Lines and Dots on the current Frame to detect if any
* form an enclosure, which can then be used to manipulate items within the
* polygon. If an enclosure is found, then the dots will have their
* enclosure value set to true, and a List is created that contains all the
* Dots in the order they were processed. Actual calculation of the Polygon
* is done dynamically (to account for Dots being moved).
*/
public static void EnclosedCheck(Collection
- items) {
// get all lineEnds on the Frame
List
- lineEnds = new LinkedList
- ();
for (Item i : items) {
if (i.isLineEnd()) {
i.setEnclosedList(null);
// Add line ends joined to 2 other lines
if (i.getLines().size() == 2) {
lineEnds.add(i);
}
}
}
// if there are no line endpoints on the Frame, then there can't be an
// enclosure
if (lineEnds.size() == 0) {
return;
}
// New approach
while (lineEnds.size() > 0) {
Item item = lineEnds.get(0);
// Get the lineEnds connected to this item
Collection
- connected = item.getAllConnected();
Collection
- connectedLineEnds = new LinkedHashSet
- ();
for (Item itemToCheck : connected) {
if (itemToCheck.isLineEnd()) {
connectedLineEnds.add(itemToCheck);
}
}
// Check that all the line ends are in our lineEnds list
int oldSize = lineEnds.size();
// Remove all the items from our line ends list
lineEnds.removeAll(connectedLineEnds);
int newSize = lineEnds.size();
int connectedSize = connectedLineEnds.size();
// Check if all the connectedItems were in the lineEnds collection
if (oldSize == newSize + connectedSize) {
// Set them to be the enclosed list for each of the items
for (Item enclosedLineEnd : connectedLineEnds) {
enclosedLineEnd.setEnclosedList(connectedLineEnds);
}
}
}
}
/**
* Checks through all Lines and Dots on the current Frame to detect if any
* form an enclosure, which can then be used to manipulate items within the
* polygon. If an enclosure is found, then the dots will have their
* enclosure value set to true, and a List is created that contains all the
* Dots in the order they were processed. Actual calculation of the Polygon
* is done dynamically (to account for Dots being moved).
*/
public static void OldEnclosedCheck(Collection
- items) {
_seen.clear();
// get all lineEnds on the Frame
List
- lineEnds = new ArrayList
- (0);
for (Item i : items) {
if (i.isLineEnd()) {
i.setEnclosedList(null);
if (i.getLines().size() == 2) {
lineEnds.add(i);
}
}
}
// if there are no line endpoints on the Frame, then there can't be an
// enclosure
if (lineEnds.size() == 0) {
return;
}
// TODO optimise this code!!
// iterate through all the lineEnds
for (Item searchFor : lineEnds) {
_seen.clear();
for (Line l : searchFor.getLines()) {
_seen.add(l);
if (traverse(searchFor, l.getOppositeEnd(searchFor))) {
_path.add(l.getOppositeEnd(searchFor));
for (Item i : _path) {
i.setEnclosedList(_path);
}
_path = new ArrayList
- (0);
break;
}
}
}
}
private static List _seen = new ArrayList();
private static List
- _path = new ArrayList
- ();
private static boolean traverse(Item toFind, Item searchFrom) {
if (toFind == null || searchFrom == null || !searchFrom.isLineEnd()) {
return false;
}
if (searchFrom.getLines().size() != 2) {
return false;
}
if (toFind == searchFrom) {
return true;
}
for (Line l : searchFrom.getLines()) {
if (!(_seen.contains(l))) {
_seen.add(l);
if (traverse(toFind, l.getOppositeEnd(searchFrom))) {
_path.add(l.getOppositeEnd(searchFrom));
return true;
}
}
}
return false;
}
/**
* Determines if an item is visible from a the current frame(s). If the item
* is free then it is considered visible.
*
* @param i
* The item to check
* @return True if visible/free from given frame.
*/
public static boolean isVisible(Item i) {
if (DisplayController.isTwinFramesOn()) {
if (!isVisible(DisplayController.getFrameOnSide(TwinFramesSide.LEFT), i)) {
return isVisible(DisplayController.getFrameOnSide(TwinFramesSide.RIGHT), i);
} else {
return true;
}
} else {
return isVisible(DisplayController.getCurrentFrame(), i);
}
}
/**
* Determines if an item is visible from a given frame. If the item is free
* then it is considered visible.
*
* @param fromFrame
* The frame to check from.
* @param i
* The item to check
* @return True if visible/free from given frame.
*/
public static boolean isVisible(Frame fromFrame, Item i)
{
if (fromFrame == null) {
return false;
}
Frame parent = i.getParent();
if (parent == fromFrame) {
return true;
} else if (parent == null) {
return FreeItems.getInstance().contains(i) || FreeItems.getCursor().contains(i);
}
return fromFrame.getAllItems().contains(i) && i.isVisible();
}
public static AxisAlignedBoxBounds expandRectangle(AxisAlignedBoxBounds r, int n)
{
if (r == null) {
return null;
}
return new AxisAlignedBoxBounds(r.getMinX() - (n >> 1), r.getMinY() - (n >> 1), r.getWidth() + n, r.getHeight() + n);
}
/*
* FrameMouseActions while (!copies.isEmpty()) { Iterator
- iterator =
* copies.iterator(); Item item = iterator.next(); // Dont paint annotation
* items for @v if (!item.isVisible() || item.isAnnotation()) {
* iterator.remove(); continue; }
*
* if (!(item instanceof Line)) { item.setThickness(item.getThickness() *
* scale); if (item instanceof XRayable || item.hasEnclosures()) {
* scaleItem(scale, defaultForeground, defaultBackground, origin.x,
* origin.y, item); items.add(item); copies.remove(item); } else {
* Collection
- connected = item.getAllConnected(); // Get all the
* connected items because we can only set the // thickness ONCE for (Item i :
* connected) { scaleItem(scale, defaultForeground, defaultBackground,
* origin.x, origin.y, i); } items.addAll(connected);
* copies.removeAll(connected); } } else { iterator.remove(); } }
*/
/**
* @param scale
* @param defaultForeground
* @param defaultBackground
* @param originX
* @param originY
* @param item
*/
private static void scaleItem(Vector v, Item item) {
Float scale = v.Scale;
int originX = v.Origin.getX();
int originY = v.Origin.getY();
Colour defaultForeground = v.Foreground;
Colour defaultBackground = v.Background;
UserAppliedPermission permission = v.permission;
// TODO should this be checking if the frame has the
// same permissions as the vector
// and if so don't set the item's permissions?
item.setOverlayPermission(permission);
// TODO encapsulate this somewhere inside of circle class!
// if(item instanceof Circle){
// scaleItem(v, ((Circle)item).getCenter());
// }
if (!(item instanceof Line)) {
if (item.getColor() == null) {
item.setColor(defaultForeground);
}
if (item.getBackgroundColor() == null) {
item.setBackgroundColor(defaultBackground);
}
if (item.getFillColor() == null) {
item.setFillColor(defaultBackground);
}
if (permission.equals(UserAppliedPermission.none)) {
item.setLinkMark(false);
item.setActionMark(false);
}
item.scale(scale, originX, originY);
}
}
/**
* Extracts widgets from an item list.
*
* @param items
* Items to extract from. Must not be null.
*
* @return List of (unique)widgets in items. Never null.
*/
public static List extractWidgets(List
- items) {
assert (items != null);
List iWidgets = new LinkedList();
for (Item i : items) {
if (i instanceof WidgetEdge) {
WidgetEdge we = (WidgetEdge) i;
if (!iWidgets.contains(we.getWidgetSource())) {
iWidgets.add(we.getWidgetSource());
}
} else if (i instanceof WidgetCorner) {
WidgetCorner wc = (WidgetCorner) i;
if (!iWidgets.contains(wc.getWidgetSource())) {
iWidgets.add(wc.getWidgetSource());
}
}
}
return iWidgets;
}
/**
* Wraps any text items to the size of their container, or the frame size if they have not container
*
* @param items A list of Items to wrap (non-Text items are ignored)
*/
public static void Justify(Collection
- items) {
for (Item i : items) {
if (i instanceof Text) {
Collection
- enclosure = FrameUtils.getEnclosingLineEnds(i.getPosition());
((Text)i).justify(false, enclosure != null ? enclosure.iterator().next().getEnclosedShape() : null);
}
}
}
/**
* Recalculates containers on the frame, then wraps all text items
*
* @param frame
*/
public static void Justify(Frame frame)
{
if (frame == null) {
return;
}
EnclosedCheck(frame.getSortedItems());
Justify(frame.getSortedItems());
}
}