[919] | 1 | /**
|
---|
| 2 | * ItemUtils.java
|
---|
| 3 | * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
|
---|
| 4 | *
|
---|
| 5 | * This program is free software: you can redistribute it and/or modify
|
---|
| 6 | * it under the terms of the GNU General Public License as published by
|
---|
| 7 | * the Free Software Foundation, either version 3 of the License, or
|
---|
| 8 | * (at your option) any later version.
|
---|
| 9 | *
|
---|
| 10 | * This program is distributed in the hope that it will be useful,
|
---|
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 13 | * GNU General Public License for more details.
|
---|
| 14 | *
|
---|
| 15 | * You should have received a copy of the GNU General Public License
|
---|
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
---|
| 17 | */
|
---|
| 18 |
|
---|
[4] | 19 | package org.expeditee.items;
|
---|
| 20 |
|
---|
| 21 | import java.io.File;
|
---|
| 22 | import java.io.UnsupportedEncodingException;
|
---|
| 23 | import java.net.URL;
|
---|
| 24 | import java.net.URLDecoder;
|
---|
| 25 | import java.util.ArrayList;
|
---|
[70] | 26 | import java.util.Collection;
|
---|
| 27 | import java.util.HashMap;
|
---|
[72] | 28 | import java.util.LinkedHashSet;
|
---|
[4] | 29 | import java.util.LinkedList;
|
---|
| 30 | import java.util.List;
|
---|
[70] | 31 | import java.util.Map;
|
---|
[4] | 32 |
|
---|
[1102] | 33 | import org.expeditee.core.Colour;
|
---|
| 34 | import org.expeditee.core.bounds.AxisAlignedBoxBounds;
|
---|
| 35 | import org.expeditee.gui.DisplayController;
|
---|
| 36 | import org.expeditee.gui.DisplayController.TwinFramesSide;
|
---|
[7] | 37 | import org.expeditee.gui.Frame;
|
---|
[920] | 38 | import org.expeditee.gui.FrameUtils;
|
---|
[121] | 39 | import org.expeditee.gui.FreeItems;
|
---|
[115] | 40 | import org.expeditee.gui.Vector;
|
---|
[1434] | 41 | import org.expeditee.gui.management.ResourceManager;
|
---|
[115] | 42 | import org.expeditee.items.Item.HighlightMode;
|
---|
[198] | 43 | import org.expeditee.items.widgets.InteractiveWidgetInitialisationFailedException;
|
---|
| 44 | import org.expeditee.items.widgets.InteractiveWidgetNotAvailableException;
|
---|
[1190] | 45 | import org.expeditee.items.widgets.Widget;
|
---|
[198] | 46 | import org.expeditee.items.widgets.WidgetCorner;
|
---|
| 47 | import org.expeditee.items.widgets.WidgetEdge;
|
---|
[838] | 48 | import org.expeditee.network.FrameShare;
|
---|
[778] | 49 | import org.expeditee.settings.folders.FolderSettings;
|
---|
[4] | 50 |
|
---|
| 51 | //Static methods that provide functions for the objects\
|
---|
| 52 | //mostly to transform values (string -> color etc).
|
---|
| 53 |
|
---|
| 54 | /**
|
---|
| 55 | * Static methods that provide functions for use in Items.
|
---|
| 56 | */
|
---|
| 57 | public class ItemUtils {
|
---|
| 58 | // Tag constants
|
---|
| 59 | public static final int TAG_SORT = 0;
|
---|
| 60 |
|
---|
| 61 | public static final int TAG_JOIN = 1;
|
---|
| 62 |
|
---|
| 63 | public static final int TAG_INDENT = 2;
|
---|
| 64 |
|
---|
| 65 | public static final int TAG_OVERLAY = 3;
|
---|
| 66 |
|
---|
| 67 | public static final int TAG_ACTIVE_OVERLAY = 4;
|
---|
| 68 |
|
---|
| 69 | public static final int TAG_IMAGE = 5;
|
---|
| 70 |
|
---|
| 71 | public static final int TAG_ITEM_TEMPLATE = 6;
|
---|
| 72 |
|
---|
| 73 | public static final int TAG_ANNOTATION_TEMPLATE = 7;
|
---|
| 74 |
|
---|
| 75 | public static final int TAG_CODE_COMMENT_TEMPLATE = 8;
|
---|
| 76 |
|
---|
| 77 | public static final int TAG_MENU = 9;
|
---|
| 78 |
|
---|
| 79 | public static final int TAG_MENU_NEXT = 10;
|
---|
| 80 |
|
---|
| 81 | public static final int TAG_PARENT = 11;
|
---|
| 82 |
|
---|
| 83 | public static final int TAG_LITERAL = 12;
|
---|
| 84 |
|
---|
| 85 | public static final int TAG_FRAME_IMAGE = 13;
|
---|
| 86 |
|
---|
| 87 | public static final int TAG_BACKUP = 14;
|
---|
| 88 |
|
---|
| 89 | public static final int TAG_POINTTYPE = 15;
|
---|
| 90 |
|
---|
[10] | 91 | // Brook: Im claiming this number!
|
---|
| 92 | public static final int TAG_IWIDGET = 16;
|
---|
[4] | 93 |
|
---|
[247] | 94 | public static final int TAG_DOT_TEMPLATE = 17;
|
---|
[70] | 95 |
|
---|
[72] | 96 | public static final int TAG_STAT_TEMPLATE = 18;
|
---|
[80] | 97 |
|
---|
[78] | 98 | public static final int TAG_VECTOR = 19;
|
---|
[427] | 99 |
|
---|
[154] | 100 | public static final int TAG_ACTIVE_VECTOR = 21;
|
---|
[80] | 101 |
|
---|
[78] | 102 | public static final int TAG_BITMAP_IMAGE = 20;
|
---|
[72] | 103 |
|
---|
[70] | 104 | public static final int TAG_MIN = 0;
|
---|
| 105 |
|
---|
[154] | 106 | public static final int TAG_MAX = 21;
|
---|
[70] | 107 |
|
---|
[4] | 108 | /**
|
---|
| 109 | * Determines if the given List of Items contains an Item that is one of the
|
---|
| 110 | * pre-defined tags.
|
---|
| 111 | *
|
---|
| 112 | * @param items
|
---|
| 113 | * The list of Items to search through
|
---|
| 114 | * @param tag
|
---|
| 115 | * The Tag to search for, this should correspond to one of the
|
---|
| 116 | * predefined constants in this class
|
---|
| 117 | * @return True if an Item was found that is the given Tag, False otherwise.
|
---|
| 118 | */
|
---|
[156] | 119 | public static boolean ContainsTag(Collection<Item> items, int tag) {
|
---|
[4] | 120 | return ContainsTag(items, GetTag(tag));
|
---|
| 121 | }
|
---|
| 122 |
|
---|
[156] | 123 | public static boolean ContainsTag(Collection<Item> items, String tag) {
|
---|
[4] | 124 | return (FindTag(items, tag) != null);
|
---|
| 125 | }
|
---|
| 126 |
|
---|
[156] | 127 | public static boolean ContainsExactTag(Collection<Item> items, int tag) {
|
---|
[70] | 128 | return ContainsExactTag(items, GetTag(tag));
|
---|
| 129 | }
|
---|
| 130 |
|
---|
[156] | 131 | public static boolean ContainsExactTag(Collection<Item> items, String tag) {
|
---|
[70] | 132 | return (FindExactTag(items, tag) != null);
|
---|
| 133 | }
|
---|
| 134 |
|
---|
[4] | 135 | /**
|
---|
| 136 | * Searches the given List of Items for an Item that is one of the
|
---|
| 137 | * pre-defined tags.
|
---|
| 138 | *
|
---|
| 139 | * @param items
|
---|
| 140 | * The list of Items to search through
|
---|
| 141 | * @param tag
|
---|
| 142 | * The Tag to search for, this should correspond to one of the
|
---|
| 143 | * predefined constants in this class
|
---|
| 144 | * @return The Item that is the given tag if one is found, or False if none
|
---|
| 145 | * is found
|
---|
| 146 | */
|
---|
[78] | 147 | public static Item FindTag(List<Item> items, int tag) {
|
---|
[4] | 148 | return FindTag(items, GetTag(tag));
|
---|
| 149 | }
|
---|
| 150 |
|
---|
| 151 | /**
|
---|
| 152 | * Searches the given List of Items for an Item that is the given tag
|
---|
| 153 | *
|
---|
| 154 | * @param items
|
---|
| 155 | * The list of Items to search through
|
---|
| 156 | * @param toFind
|
---|
| 157 | * The Tag to search for, this should include the at (@) symbol
|
---|
| 158 | * @return The Item that is the given tag if one is found, or False if none
|
---|
| 159 | * is found
|
---|
| 160 | */
|
---|
[156] | 161 | public static Text FindTag(Collection<Item> items, String toFind) {
|
---|
[4] | 162 | for (Item i : items) {
|
---|
[1190] | 163 | if (i instanceof Text && i.isAnnotation()) {
|
---|
| 164 | if (((Text) i).startsWith(toFind)) {
|
---|
[4] | 165 | return (Text) i;
|
---|
[1190] | 166 | }
|
---|
| 167 | }
|
---|
[4] | 168 | }
|
---|
| 169 | return null;
|
---|
| 170 | }
|
---|
| 171 |
|
---|
[156] | 172 | public static Item FindExactTag(Collection<Item> items, String toFind) {
|
---|
[70] | 173 | for (Item i : items) {
|
---|
[1190] | 174 | if (i instanceof Text && i.isAnnotation()) {
|
---|
| 175 | if (((Text) i).getText().trim().equalsIgnoreCase(toFind)) {
|
---|
| 176 | return i;
|
---|
| 177 | }
|
---|
| 178 | }
|
---|
[70] | 179 | }
|
---|
| 180 |
|
---|
| 181 | return null;
|
---|
| 182 | }
|
---|
| 183 |
|
---|
[78] | 184 | public static Item FindExactTag(List<Item> items, int tag) {
|
---|
[70] | 185 | return FindExactTag(items, GetTag(tag));
|
---|
| 186 | }
|
---|
| 187 |
|
---|
[4] | 188 | /**
|
---|
| 189 | * Determines if the given Item is one of the pre-defined tags in this class
|
---|
| 190 | *
|
---|
| 191 | * @param toCheck
|
---|
| 192 | * The Item to check
|
---|
| 193 | * @param tag
|
---|
| 194 | * The tag to check the Item against, this should correspond to
|
---|
| 195 | * one of the constants defined in this class
|
---|
| 196 | * @return True if the Item matches the given tag, false otherwise
|
---|
| 197 | */
|
---|
[80] | 198 | public static boolean startsWithTag(Item toCheck, int tag) {
|
---|
| 199 | return startsWithTag(toCheck, GetTag(tag));
|
---|
[4] | 200 | }
|
---|
[72] | 201 |
|
---|
[80] | 202 | public static boolean startsWithTag(Item toCheck, int tag, boolean hasValue) {
|
---|
| 203 | return startsWithTag(toCheck, GetTag(tag), hasValue);
|
---|
[70] | 204 | }
|
---|
[4] | 205 |
|
---|
| 206 | /**
|
---|
[80] | 207 | * Checks if the given Item begins with the desired tag (case insensitive).
|
---|
[4] | 208 | *
|
---|
| 209 | * @param toCheck
|
---|
| 210 | * The Item to check for the given tag
|
---|
| 211 | * @param tag
|
---|
| 212 | * The tag to check for in the given Item
|
---|
[70] | 213 | * @param tagOnly
|
---|
| 214 | * True if the tag does not have a value
|
---|
[4] | 215 | * @return True if the tag is found in the given Item, False otherwise.
|
---|
| 216 | */
|
---|
[97] | 217 | public static boolean startsWithTag(Item toCheck, String tag,
|
---|
| 218 | boolean valueAllowed) {
|
---|
[1190] | 219 | if (!(toCheck instanceof Text)) {
|
---|
[4] | 220 | return false;
|
---|
[1190] | 221 | }
|
---|
[4] | 222 |
|
---|
| 223 | Text txt = (Text) toCheck;
|
---|
[80] | 224 | String value = ItemUtils.StripTag(txt.getText(), tag);
|
---|
| 225 |
|
---|
[1190] | 226 | if (value == null) {
|
---|
[80] | 227 | return false;
|
---|
[1190] | 228 | }
|
---|
[80] | 229 | return valueAllowed || value.equals("");
|
---|
[70] | 230 | }
|
---|
[4] | 231 |
|
---|
[80] | 232 | /**
|
---|
| 233 | * Checks if the item begins with the desired tag.
|
---|
[97] | 234 | *
|
---|
[80] | 235 | * @param toCheck
|
---|
| 236 | * @param tag
|
---|
| 237 | * @return
|
---|
| 238 | */
|
---|
| 239 | public static boolean startsWithTag(Item toCheck, String tag) {
|
---|
| 240 | return startsWithTag(toCheck, tag, true);
|
---|
[4] | 241 | }
|
---|
| 242 |
|
---|
| 243 | /**
|
---|
| 244 | * Strips off the given tag from the given String, and returns wathever is
|
---|
[86] | 245 | * left. Dont put the colon after tags as it is not needed.
|
---|
[4] | 246 | *
|
---|
| 247 | * @param toStrip
|
---|
| 248 | * The String to strip the Tag from
|
---|
| 249 | * @param tag
|
---|
| 250 | * The tag to remove from the String
|
---|
| 251 | * @return The String that results from removing the given Tag from the
|
---|
| 252 | * given String, or null if the given String is not the given Tag
|
---|
| 253 | */
|
---|
| 254 | public static String StripTag(String toStrip, String tag) {
|
---|
[1190] | 255 | if (toStrip == null) {
|
---|
[80] | 256 | return null;
|
---|
[1190] | 257 | }
|
---|
[80] | 258 | toStrip = toStrip.trim();
|
---|
[1190] | 259 | if (!toStrip.toLowerCase().startsWith(tag.toLowerCase())) {
|
---|
[80] | 260 | return null;
|
---|
[1190] | 261 | }
|
---|
[4] | 262 |
|
---|
[1190] | 263 | if (toStrip.length() == tag.length()) {
|
---|
[80] | 264 | return "";
|
---|
[1190] | 265 | }
|
---|
[80] | 266 | // remove tag and ensure the char is the tag separator
|
---|
| 267 | char separator = toStrip.charAt(tag.length());
|
---|
[1190] | 268 | if (separator != ':') {
|
---|
[80] | 269 | return null;
|
---|
[1190] | 270 | }
|
---|
[4] | 271 |
|
---|
[1190] | 272 | if (toStrip.length() == tag.length() + 1) {
|
---|
[80] | 273 | return "";
|
---|
[1190] | 274 | }
|
---|
[4] | 275 |
|
---|
[80] | 276 | return toStrip.substring(tag.length() + 1).trim();
|
---|
[4] | 277 | }
|
---|
| 278 |
|
---|
| 279 | /**
|
---|
[80] | 280 | * Strips the first character from a string if it is the tag symbol and
|
---|
| 281 | * returns the remainder.
|
---|
[97] | 282 | *
|
---|
[4] | 283 | * @param toStrip
|
---|
| 284 | * the string to be stripped
|
---|
[80] | 285 | * @return the stripped version of the string.
|
---|
[4] | 286 | */
|
---|
| 287 | public static String StripTagSymbol(String toStrip) {
|
---|
| 288 | // there must be something left after stripping
|
---|
| 289 | if (toStrip != null) {
|
---|
[80] | 290 | toStrip = toStrip.trim();
|
---|
[4] | 291 | if (toStrip.length() > 0) {
|
---|
| 292 | if (toStrip.charAt(0) == '@') {
|
---|
| 293 | return toStrip.substring(1);
|
---|
| 294 | }
|
---|
| 295 | }
|
---|
| 296 | }
|
---|
| 297 | return toStrip;
|
---|
| 298 | }
|
---|
| 299 |
|
---|
| 300 | /**
|
---|
| 301 | * Converts the given int to the String tag. The int should correspond to
|
---|
| 302 | * one of the constants in this class, if it does not this method will
|
---|
| 303 | * return null.
|
---|
| 304 | *
|
---|
| 305 | * @param tag
|
---|
| 306 | * The int corresponding to the constants in this class of which
|
---|
| 307 | * tag to return
|
---|
| 308 | * @return The String representation of the given Tag, or null if the given
|
---|
| 309 | * value does not have a tag associated
|
---|
| 310 | */
|
---|
| 311 | public static String GetTag(int tag) {
|
---|
[72] | 312 | // TODO refactor so that this uses a map for INT to tags
|
---|
[4] | 313 | switch (tag) {
|
---|
| 314 | case TAG_SORT:
|
---|
| 315 | return "@sort";
|
---|
| 316 | case TAG_JOIN:
|
---|
| 317 | return "@join";
|
---|
| 318 | case TAG_INDENT:
|
---|
| 319 | return "@indent";
|
---|
| 320 | case TAG_OVERLAY:
|
---|
| 321 | return "@o";
|
---|
[78] | 322 | case TAG_VECTOR:
|
---|
| 323 | return "@v";
|
---|
[154] | 324 | case TAG_ACTIVE_VECTOR:
|
---|
| 325 | return "@av";
|
---|
[4] | 326 | case TAG_ACTIVE_OVERLAY:
|
---|
| 327 | return "@ao";
|
---|
| 328 | case TAG_IMAGE:
|
---|
[80] | 329 | return "@i";
|
---|
[4] | 330 | case TAG_ITEM_TEMPLATE:
|
---|
| 331 | return "@itemtemplate";
|
---|
| 332 | case TAG_ANNOTATION_TEMPLATE:
|
---|
| 333 | return "@annotationtemplate";
|
---|
[72] | 334 | case TAG_STAT_TEMPLATE:
|
---|
| 335 | return "@stattemplate";
|
---|
[4] | 336 | case TAG_CODE_COMMENT_TEMPLATE:
|
---|
| 337 | return "@commenttemplate";
|
---|
| 338 | case TAG_MENU:
|
---|
| 339 | return "@menu";
|
---|
| 340 | case TAG_MENU_NEXT:
|
---|
| 341 | return "@nextmenu";
|
---|
| 342 | case TAG_PARENT:
|
---|
| 343 | return "@parent";
|
---|
| 344 | case TAG_LITERAL:
|
---|
| 345 | return "@lit";
|
---|
| 346 | case TAG_FRAME_IMAGE:
|
---|
| 347 | return "@f";
|
---|
[78] | 348 | case TAG_BITMAP_IMAGE:
|
---|
| 349 | return "@b";
|
---|
[4] | 350 | case TAG_BACKUP:
|
---|
| 351 | return "@old";
|
---|
| 352 | case TAG_POINTTYPE:
|
---|
[80] | 353 | return "@pointtype";
|
---|
[10] | 354 | case TAG_IWIDGET:
|
---|
| 355 | return "@iw";
|
---|
[247] | 356 | case TAG_DOT_TEMPLATE:
|
---|
| 357 | return "@dottemplate";
|
---|
[4] | 358 | default:
|
---|
| 359 | return null;
|
---|
| 360 | }
|
---|
| 361 | }
|
---|
| 362 |
|
---|
| 363 | /**
|
---|
| 364 | * Creates a picture object from the information stored in the given Text
|
---|
| 365 | * object. <br>
|
---|
| 366 | * The paths searched are in the following order:<br>
|
---|
| 367 | * /images/<br>
|
---|
| 368 | * the source text as a relative path (from program root folder). <br>
|
---|
| 369 | * the source text as an absolute path <br>
|
---|
| 370 | * <br>
|
---|
| 371 | * If the Image file cannot be found on disk null is returned.
|
---|
| 372 | *
|
---|
[601] | 373 | * @param source
|
---|
[1102] | 374 | * The Text file containing the Picture information
|
---|
[4] | 375 | * @return The Picture object representing the file, or Null if the file is
|
---|
| 376 | * not found.
|
---|
| 377 | */
|
---|
[1102] | 378 | public static Picture CreatePicture(Text source, boolean tryRemote) {
|
---|
[1434] | 379 | return ResourceManager.getExpediteePicture(source, tryRemote);
|
---|
[4] | 380 | }
|
---|
[1434] | 381 | // public static Picture CreatePicture(Text source, boolean tryRemote) {
|
---|
| 382 | // String text = source.getText();
|
---|
| 383 | // String path = "";
|
---|
| 384 | // String fileName = "";
|
---|
| 385 | // String size = "";
|
---|
| 386 | //
|
---|
| 387 | // try {
|
---|
| 388 | // // remove @i tag
|
---|
| 389 | // text = text.replaceFirst("@i:", "");
|
---|
| 390 | // text = text.replaceAll("\n", "");
|
---|
| 391 | // text = text.trim();
|
---|
| 392 | //
|
---|
| 393 | // int fileSuffixChar = text.indexOf('.');
|
---|
| 394 | // if (fileSuffixChar < 0) {
|
---|
| 395 | // return null;
|
---|
| 396 | // }
|
---|
| 397 | // int endOfFileName = text.indexOf(' ', fileSuffixChar);
|
---|
| 398 | // if (endOfFileName < 0) {
|
---|
| 399 | // path = text;
|
---|
| 400 | // size = "";
|
---|
| 401 | // } else {
|
---|
| 402 | // path = text.substring(0, endOfFileName);
|
---|
| 403 | // size = text.substring(endOfFileName).trim();
|
---|
| 404 | // }
|
---|
| 405 | // fileName = path;
|
---|
| 406 | //
|
---|
| 407 | // if (!fileName.equals(Picture.REDACTED_IMAGE_NAME)) {
|
---|
| 408 | // // try images subdirectory
|
---|
| 409 | // File file = null;
|
---|
| 410 | //
|
---|
| 411 | // List<String> absoluteDirs = FolderSettings.ImageDirs.getAbsoluteDirs();
|
---|
| 412 | // for (String dir : absoluteDirs) {
|
---|
| 413 | // file = new File(dir + path);
|
---|
| 414 | // if (file.exists() && !file.isDirectory()) {
|
---|
| 415 | // break;
|
---|
| 416 | // }
|
---|
| 417 | // }
|
---|
| 418 | //
|
---|
| 419 | // if (file == null || !file.exists() || file.isDirectory()) {
|
---|
| 420 | // file = new File(path);
|
---|
| 421 | // }
|
---|
| 422 | //
|
---|
| 423 | // // try relative path
|
---|
| 424 | // if (!file.exists() || file.isDirectory()) {
|
---|
| 425 | // URL picture = new Object().getClass().getResource(path);
|
---|
| 426 | //
|
---|
| 427 | // // decode to remove %20 in windows folder names
|
---|
| 428 | // if (picture != null) {
|
---|
| 429 | // try {
|
---|
| 430 | // path = URLDecoder.decode(picture.getFile(), "UTF-8");
|
---|
| 431 | // } catch (UnsupportedEncodingException e) {
|
---|
| 432 | // // TODO Auto-generated catch block
|
---|
| 433 | // e.printStackTrace();
|
---|
| 434 | // }
|
---|
| 435 | // }
|
---|
| 436 | //
|
---|
| 437 | // } else {
|
---|
| 438 | // path = file.getPath();
|
---|
| 439 | // }
|
---|
| 440 | //
|
---|
| 441 | // // if the image isn't found by now, try remote servers
|
---|
| 442 | // file = new File(path);
|
---|
| 443 | // if (!file.exists() || file.isDirectory()) {
|
---|
| 444 | // if(tryRemote && FrameShare.getInstance().loadImage(fileName, null)) {
|
---|
| 445 | // // call CreatePicture again, but with tryRemote set to false so we won't get into an infinite loop
|
---|
| 446 | // // if something goes wrong with finding the downloaded image
|
---|
| 447 | // return CreatePicture(source, false);
|
---|
| 448 | // }
|
---|
| 449 | // return null;
|
---|
| 450 | // }
|
---|
| 451 | // }
|
---|
| 452 | // } catch (Exception e) {
|
---|
| 453 | // return null;
|
---|
| 454 | // }
|
---|
| 455 | //
|
---|
| 456 | // try {
|
---|
| 457 | // Picture pic = new Picture(source, fileName, path, size);
|
---|
| 458 | //
|
---|
| 459 | // return pic;
|
---|
| 460 | // } catch (Exception e) {
|
---|
| 461 | // e.printStackTrace();
|
---|
| 462 | // return null;
|
---|
| 463 | // }
|
---|
| 464 | //
|
---|
| 465 | // }
|
---|
[838] | 466 |
|
---|
[1102] | 467 | public static Picture CreatePicture(Text source) {
|
---|
| 468 | return CreatePicture(source, true);
|
---|
[838] | 469 | }
|
---|
[4] | 470 |
|
---|
| 471 | /**
|
---|
| 472 | * Creates a deep copy of the given List of Items.
|
---|
| 473 | *
|
---|
| 474 | * @param toCopy
|
---|
| 475 | * The list of Items to copy
|
---|
| 476 | * @return A list containing a copy of all Items in the given List
|
---|
| 477 | */
|
---|
[70] | 478 | public static List<Item> CopyItems(Collection<Item> toCopy) {
|
---|
[115] | 479 | return CopyItems(toCopy, false, null);
|
---|
[7] | 480 | }
|
---|
[70] | 481 |
|
---|
[115] | 482 | public static List<Item> CopyItems(Collection<Item> toCopy, Vector v) {
|
---|
| 483 | return CopyItems(toCopy, false, v);
|
---|
| 484 | }
|
---|
| 485 |
|
---|
[70] | 486 | public static List<Item> CopyItems(Collection<Item> toCopy, boolean extrude) {
|
---|
[115] | 487 | return CopyItems(toCopy, extrude, null);
|
---|
| 488 | }
|
---|
| 489 |
|
---|
| 490 | public static List<Item> CopyItems(Collection<Item> toCopy,
|
---|
| 491 | boolean extrude, Vector v) {
|
---|
[4] | 492 | // The copies to return
|
---|
| 493 | List<Item> copies = new ArrayList<Item>();
|
---|
| 494 |
|
---|
| 495 | // list of dots at the end of lines
|
---|
[78] | 496 | Collection<Item> lineEnds = new LinkedHashSet<Item>();
|
---|
| 497 | Collection<Line> lines = new LinkedHashSet<Line>();
|
---|
[108] | 498 | Collection<XRayable> xrayables = new LinkedHashSet<XRayable>();
|
---|
[78] | 499 | Collection<Constraint> constraints = new LinkedHashSet<Constraint>();
|
---|
[4] | 500 |
|
---|
[78] | 501 | Collection<Item> singles = new LinkedHashSet<Item>();
|
---|
[4] | 502 |
|
---|
[70] | 503 | Map<Item, Item> lineEndMap = new HashMap<Item, Item>();
|
---|
| 504 |
|
---|
[10] | 505 | // Widgets are super special
|
---|
[1102] | 506 | List<Widget> widgets = new ArrayList<Widget>();
|
---|
[70] | 507 |
|
---|
[4] | 508 | for (Item i : toCopy) {
|
---|
[427] | 509 | // Dont copy parts of a vector
|
---|
[1190] | 510 | if (i == null || !i.hasPermission(UserAppliedPermission.copy)) {
|
---|
[286] | 511 | continue;
|
---|
[1190] | 512 | }
|
---|
[427] | 513 |
|
---|
[70] | 514 | // BROOK
|
---|
| 515 | if (i instanceof WidgetCorner) { // dont add these
|
---|
| 516 | if (!widgets.contains(((WidgetCorner) i).getWidgetSource()))
|
---|
[1190] | 517 | {
|
---|
[70] | 518 | widgets.add(((WidgetCorner) i).getWidgetSource());
|
---|
| 519 | // BROOK
|
---|
[1190] | 520 | }
|
---|
[70] | 521 | } else if (i instanceof WidgetEdge) { // dont add these
|
---|
| 522 | // lines are recreated later
|
---|
| 523 | } else if (i instanceof Line) {
|
---|
| 524 | lines.add((Line) i);
|
---|
[108] | 525 | } else if (i instanceof XRayable) {
|
---|
[115] | 526 | xrayables.add((XRayable) i);
|
---|
[70] | 527 | } else {
|
---|
| 528 | if (i.isLineEnd()) {
|
---|
| 529 | lineEnds.add(i);
|
---|
| 530 | constraints.addAll(i.getConstraints());
|
---|
| 531 | } else {
|
---|
| 532 | singles.add(i);
|
---|
[4] | 533 | }
|
---|
| 534 | }
|
---|
| 535 | }
|
---|
[115] | 536 |
|
---|
| 537 | // Dont copy the other items that are part of the circle
|
---|
| 538 | for (XRayable x : xrayables) {
|
---|
[108] | 539 | Collection<Item> connected = x.getConnected();
|
---|
| 540 | singles.removeAll(connected);
|
---|
| 541 | lineEnds.removeAll(connected);
|
---|
| 542 | lines.removeAll(connected);
|
---|
[115] | 543 | Item xCopy = x.copy();
|
---|
| 544 | copies.addAll(xCopy.getConnected());
|
---|
| 545 | // Scale items that are from a vector frame
|
---|
| 546 | if (v != null) {
|
---|
| 547 | scaleItem(v, xCopy);
|
---|
| 548 | }
|
---|
[108] | 549 | }
|
---|
[115] | 550 |
|
---|
[70] | 551 | // copy all single items
|
---|
| 552 | for (Item i : singles) {
|
---|
[4] | 553 | Item copy = i.copy();
|
---|
[115] | 554 | Frame parent = i.getParent();
|
---|
| 555 | if (parent != null) {
|
---|
| 556 | // Items copied from overlay will be anchored onto the current
|
---|
| 557 | // frame
|
---|
| 558 | copy.setParent(parent);
|
---|
[4] | 559 | // if this is the frame name, make sure the frame is saved (in
|
---|
| 560 | // case it is a TDFC frame)
|
---|
[115] | 561 | if (i.isFrameName()) {
|
---|
| 562 | parent.setChanged(true);
|
---|
| 563 | }// check if the item is being copied from a vector
|
---|
| 564 | else if (v != null) {
|
---|
| 565 | // Find the vector this item is from
|
---|
| 566 | assert (v.Frame == parent);
|
---|
| 567 | scaleItem(v, copy);
|
---|
| 568 | }
|
---|
[4] | 569 | }
|
---|
| 570 | copies.add(copy);
|
---|
| 571 | }
|
---|
| 572 |
|
---|
| 573 | // replace line ends with their copies
|
---|
| 574 | // this is done here so that copied lines can still share end points
|
---|
| 575 | for (Item i : lineEnds) {
|
---|
[70] | 576 | // create a copy of the line end
|
---|
| 577 | Item copy = i.copy();
|
---|
| 578 | copy.removeAllLines();
|
---|
| 579 | copy.removeAllConstraints();
|
---|
[4] | 580 |
|
---|
[70] | 581 | if (extrude) {
|
---|
| 582 | Frame frame = i.getParentOrCurrentFrame();
|
---|
| 583 | Line newLine = new Line(i, copy, frame.getNextItemID());
|
---|
| 584 | // make sure overlay items are put back on the overlay
|
---|
| 585 | newLine.setParent(frame);
|
---|
| 586 | frame.addItem(newLine);
|
---|
| 587 | copies.add(newLine);
|
---|
[4] | 588 | }
|
---|
[70] | 589 | copies.add(copy);
|
---|
| 590 | lineEndMap.put(i, copy);
|
---|
[115] | 591 | // Scale items that are from a vector frame
|
---|
| 592 | if (v != null) {
|
---|
| 593 | scaleItem(v, copy);
|
---|
| 594 | }
|
---|
[4] | 595 | }
|
---|
| 596 |
|
---|
| 597 | // recreate lines
|
---|
[70] | 598 | for (Line line : lines) {
|
---|
| 599 | Line lineCopy = line.copy();
|
---|
[80] | 600 | // get the lineEnd we copied above if it is in the MAPPING
|
---|
[78] | 601 | Item originalLineEnd = line.getEndItem();
|
---|
| 602 | Item actualLineEnd = lineEndMap.get(originalLineEnd);
|
---|
[1190] | 603 | if (actualLineEnd == null) {
|
---|
[78] | 604 | lineCopy.setEndItem(originalLineEnd);
|
---|
[1190] | 605 | } else {
|
---|
[78] | 606 | lineCopy.setEndItem(actualLineEnd);
|
---|
[1190] | 607 | }
|
---|
[80] | 608 |
|
---|
[78] | 609 | Item originalLineStart = line.getStartItem();
|
---|
| 610 | Item actualLineStart = lineEndMap.get(originalLineStart);
|
---|
[1190] | 611 | if (actualLineStart == null) {
|
---|
[78] | 612 | lineCopy.setStartItem(originalLineStart);
|
---|
[1190] | 613 | } else {
|
---|
[78] | 614 | lineCopy.setStartItem(actualLineStart);
|
---|
[1190] | 615 | }
|
---|
[80] | 616 |
|
---|
[70] | 617 | copies.add(lineCopy);
|
---|
[4] | 618 | }
|
---|
| 619 |
|
---|
[70] | 620 | // recreate constraints
|
---|
| 621 | for (Constraint c : constraints) {
|
---|
| 622 | Item start = lineEndMap.get(c.getStart());
|
---|
| 623 | Item end = lineEndMap.get(c.getEnd());
|
---|
[1415] | 624 | int id = start.getParent().getNextItemID();
|
---|
[70] | 625 | if (start != null && end != null) {
|
---|
| 626 | new Constraint(start, end, id, c.getType());
|
---|
| 627 | }
|
---|
[4] | 628 | }
|
---|
| 629 |
|
---|
[10] | 630 | // BROOK
|
---|
[1102] | 631 | for (Widget iw : widgets) {
|
---|
[10] | 632 | try {
|
---|
[70] | 633 |
|
---|
[1102] | 634 | Widget icopy = iw.copy();
|
---|
[10] | 635 | copies.addAll(icopy.getItems());
|
---|
[70] | 636 |
|
---|
[10] | 637 | } catch (InteractiveWidgetNotAvailableException e) {
|
---|
| 638 | e.printStackTrace();
|
---|
[81] | 639 | } catch (InteractiveWidgetInitialisationFailedException e) {
|
---|
| 640 | e.printStackTrace();
|
---|
[10] | 641 | }
|
---|
[97] | 642 |
|
---|
[10] | 643 | }
|
---|
[427] | 644 |
|
---|
| 645 | // Make sure filled rectangles are shown filled on vector overlays
|
---|
[1190] | 646 | if (v != null) {
|
---|
[115] | 647 | EnclosedCheck(copies);
|
---|
[1190] | 648 | }
|
---|
[70] | 649 |
|
---|
[4] | 650 | return copies;
|
---|
| 651 | }
|
---|
| 652 |
|
---|
| 653 | /**
|
---|
| 654 | * Attempts to create a new line that starts from the given Item
|
---|
| 655 | * ('unreeling'). The Item must already have at least one line, and not be a
|
---|
| 656 | * line itself to be unreeled from.
|
---|
| 657 | *
|
---|
| 658 | * @param toUnreelFrom
|
---|
| 659 | * The Item that will be one end point of the new line
|
---|
| 660 | * @return A List containing the newly created Item and Line that unreel
|
---|
| 661 | * from the given Item, or null if this Item cannot be unreeled
|
---|
| 662 | * from.
|
---|
| 663 | */
|
---|
[97] | 664 | public static List<Item> UnreelLine(Item toUnreelFrom, boolean constrain) {
|
---|
[4] | 665 | // the Item must already have one line to be unreeled from
|
---|
[1190] | 666 | if (toUnreelFrom == null || toUnreelFrom.getLines().size() < 1) {
|
---|
[4] | 667 | return null;
|
---|
[1190] | 668 | }
|
---|
[4] | 669 |
|
---|
| 670 | List<Item> unreel = new ArrayList<Item>(2);
|
---|
| 671 | unreel.add(toUnreelFrom);
|
---|
| 672 | unreel.addAll(toUnreelFrom.getLines());
|
---|
[97] | 673 | return UnreelLine(unreel, constrain);
|
---|
[4] | 674 | }
|
---|
| 675 |
|
---|
| 676 | /**
|
---|
| 677 | * Attempts to create a new line that starts from the given list of Items
|
---|
| 678 | * ('unreeling'). The List must contain only one non-line Item. The non-line
|
---|
| 679 | * Item must already have at least one line to be unreeled from.
|
---|
| 680 | *
|
---|
| 681 | * @param toUnreel
|
---|
| 682 | * The List containing the Item that will be one end point of the
|
---|
| 683 | * new line
|
---|
| 684 | * @return A List of the newly created Item and Line that unreel from the
|
---|
| 685 | * Item in the given List, or null if this List cannot be unreeled
|
---|
| 686 | * from.
|
---|
| 687 | */
|
---|
[97] | 688 | public static List<Item> UnreelLine(List<Item> toUnreel, boolean constrain) {
|
---|
[4] | 689 | Item origEnd = null;
|
---|
| 690 | // find the end being unreeled from
|
---|
| 691 | for (Item item : toUnreel) {
|
---|
| 692 | // we dont want to unreel anything other than lines
|
---|
[115] | 693 | if (item.hasEnclosures()
|
---|
| 694 | || !(item.isLineEnd() || item instanceof Line)) {
|
---|
[4] | 695 | return null;
|
---|
| 696 | }
|
---|
[70] | 697 | // find the dot to unreel from
|
---|
| 698 | if (item.isLineEnd()) {
|
---|
[4] | 699 | // if there are multiple ends in the list, return
|
---|
[1190] | 700 | if (origEnd != null) {
|
---|
[4] | 701 | return null;
|
---|
[1190] | 702 | }
|
---|
[4] | 703 |
|
---|
| 704 | origEnd = item;
|
---|
| 705 | }
|
---|
| 706 | }
|
---|
| 707 |
|
---|
| 708 | // copy the original endpoint
|
---|
| 709 | Item copy = origEnd.copy();
|
---|
[115] | 710 | origEnd.setHighlightMode(HighlightMode.None);
|
---|
[1102] | 711 | origEnd.setHighlightColorToDefault();
|
---|
[4] | 712 | copy.removeAllLines();
|
---|
| 713 | copy.removeAllConstraints();
|
---|
| 714 |
|
---|
[427] | 715 | for (Line l : origEnd.getLines()) {
|
---|
[407] | 716 | l.invalidateAll();
|
---|
| 717 | }
|
---|
[427] | 718 |
|
---|
[4] | 719 | // create a new line
|
---|
[1102] | 720 | Frame currentFrame = DisplayController.getCurrentFrame();
|
---|
[97] | 721 | Line line = new Line(origEnd, copy, currentFrame.getNextItemID());
|
---|
| 722 | // if the previous line was constrained then make the new line
|
---|
| 723 | // constrained if it was a single line
|
---|
[108] | 724 | // TODO add later a diagonal constraint if getLines() == 3 or 4
|
---|
[97] | 725 | Collection<Constraint> constraints = origEnd.getConstraints();
|
---|
[1102] | 726 | if (constrain && constraints.size() > 0 && origEnd.getLines().size() == 2) {
|
---|
[97] | 727 | Integer type = null;
|
---|
| 728 | for (Constraint c : constraints) {
|
---|
| 729 | if (c.getType() == Constraint.HORIZONTAL) {
|
---|
| 730 | type = Constraint.VERTICAL;
|
---|
| 731 | } else if (c.getType() == Constraint.VERTICAL) {
|
---|
| 732 | type = Constraint.HORIZONTAL;
|
---|
[108] | 733 | }
|
---|
| 734 | if (c.getType() == Constraint.DIAGONAL_NEG) {
|
---|
[97] | 735 | type = Constraint.DIAGONAL_POS;
|
---|
| 736 | } else if (c.getType() == Constraint.DIAGONAL_POS) {
|
---|
| 737 | type = Constraint.DIAGONAL_NEG;
|
---|
| 738 | }
|
---|
| 739 | }
|
---|
| 740 | if (type != null) {
|
---|
[1102] | 741 | new Constraint(origEnd, copy, currentFrame.getNextItemID(), type);
|
---|
[97] | 742 | }
|
---|
| 743 | }
|
---|
| 744 |
|
---|
[70] | 745 | // copy.setFloating(true);
|
---|
[4] | 746 | origEnd.setArrowheadLength(0);
|
---|
[70] | 747 | // copy.setArrowheadLength(0);
|
---|
[4] | 748 |
|
---|
| 749 | List<Item> toReturn = new LinkedList<Item>();
|
---|
| 750 | toReturn.add(copy);
|
---|
| 751 | toReturn.add(line);
|
---|
| 752 | return toReturn;
|
---|
| 753 | }
|
---|
| 754 |
|
---|
[72] | 755 | public static void New() {
|
---|
[1415] | 756 | EnclosedCheck(DisplayController.getCurrentFrame().getSortedItems());
|
---|
[72] | 757 | }
|
---|
| 758 |
|
---|
| 759 | public static void Old() {
|
---|
[1415] | 760 | OldEnclosedCheck(DisplayController.getCurrentFrame().getSortedItems());
|
---|
[72] | 761 | }
|
---|
| 762 |
|
---|
[4] | 763 | /**
|
---|
[72] | 764 | * Updates the connectedToAnnotation flags for all items
|
---|
| 765 | */
|
---|
| 766 | public static void UpdateConnectedToAnnotations(Collection<Item> items) {
|
---|
| 767 | // get all lineEnds on the Frame
|
---|
| 768 | Collection<Item> lineEnds = new LinkedHashSet<Item>();
|
---|
| 769 | for (Item i : items) {
|
---|
| 770 | i.setConnectedToAnnotation(false);
|
---|
| 771 | if (i.isLineEnd()) {
|
---|
| 772 | lineEnds.add(i);
|
---|
| 773 | }
|
---|
| 774 | }
|
---|
| 775 |
|
---|
| 776 | // if there are no line endpoints on the Frame, then there can't be an
|
---|
| 777 | // enclosure
|
---|
[1190] | 778 | if (lineEnds.size() == 0) {
|
---|
[72] | 779 | return;
|
---|
[1190] | 780 | }
|
---|
[72] | 781 |
|
---|
| 782 | // Now find go through line ends and see if any are annotation items
|
---|
| 783 | while (lineEnds.size() > 0) {
|
---|
| 784 | Item item = lineEnds.iterator().next();
|
---|
| 785 | // If its an annotation item then set the flag for all its connected
|
---|
| 786 | // items
|
---|
| 787 | if (item.isAnnotation()) {
|
---|
| 788 | Collection<Item> connected = item.getAllConnected();
|
---|
[1190] | 789 | for (Item i : connected) {
|
---|
[72] | 790 | i.setConnectedToAnnotation(true);
|
---|
[1190] | 791 | }
|
---|
[72] | 792 | lineEnds.removeAll(connected);
|
---|
| 793 | }
|
---|
| 794 | lineEnds.remove(item);
|
---|
| 795 | }
|
---|
| 796 | }
|
---|
| 797 |
|
---|
| 798 | /**
|
---|
[4] | 799 | * Checks through all Lines and Dots on the current Frame to detect if any
|
---|
| 800 | * form an enclosure, which can then be used to manipulate items within the
|
---|
| 801 | * polygon. If an enclosure is found, then the dots will have their
|
---|
| 802 | * enclosure value set to true, and a List is created that contains all the
|
---|
| 803 | * Dots in the order they were processed. Actual calculation of the Polygon
|
---|
| 804 | * is done dynamically (to account for Dots being moved).
|
---|
| 805 | */
|
---|
[72] | 806 | public static void EnclosedCheck(Collection<Item> items) {
|
---|
| 807 | // get all lineEnds on the Frame
|
---|
| 808 | List<Item> lineEnds = new LinkedList<Item>();
|
---|
| 809 | for (Item i : items) {
|
---|
| 810 | if (i.isLineEnd()) {
|
---|
| 811 | i.setEnclosedList(null);
|
---|
| 812 | // Add line ends joined to 2 other lines
|
---|
[1190] | 813 | if (i.getLines().size() == 2) {
|
---|
[72] | 814 | lineEnds.add(i);
|
---|
[1190] | 815 | }
|
---|
[72] | 816 | }
|
---|
| 817 | }
|
---|
| 818 |
|
---|
| 819 | // if there are no line endpoints on the Frame, then there can't be an
|
---|
| 820 | // enclosure
|
---|
[1190] | 821 | if (lineEnds.size() == 0) {
|
---|
[72] | 822 | return;
|
---|
[1190] | 823 | }
|
---|
[72] | 824 |
|
---|
| 825 | // New approach
|
---|
| 826 | while (lineEnds.size() > 0) {
|
---|
| 827 | Item item = lineEnds.get(0);
|
---|
| 828 | // Get the lineEnds connected to this item
|
---|
| 829 | Collection<Item> connected = item.getAllConnected();
|
---|
| 830 | Collection<Item> connectedLineEnds = new LinkedHashSet<Item>();
|
---|
| 831 | for (Item itemToCheck : connected) {
|
---|
[1190] | 832 | if (itemToCheck.isLineEnd()) {
|
---|
[72] | 833 | connectedLineEnds.add(itemToCheck);
|
---|
[1190] | 834 | }
|
---|
[72] | 835 | }
|
---|
| 836 | // Check that all the line ends are in our lineEnds list
|
---|
| 837 | int oldSize = lineEnds.size();
|
---|
| 838 | // Remove all the items from our line ends list
|
---|
| 839 | lineEnds.removeAll(connectedLineEnds);
|
---|
| 840 | int newSize = lineEnds.size();
|
---|
| 841 | int connectedSize = connectedLineEnds.size();
|
---|
| 842 | // Check if all the connectedItems were in the lineEnds collection
|
---|
| 843 | if (oldSize == newSize + connectedSize) {
|
---|
| 844 | // Set them to be the enclosed list for each of the items
|
---|
| 845 | for (Item enclosedLineEnd : connectedLineEnds) {
|
---|
| 846 | enclosedLineEnd.setEnclosedList(connectedLineEnds);
|
---|
| 847 | }
|
---|
| 848 | }
|
---|
| 849 | }
|
---|
| 850 | }
|
---|
| 851 |
|
---|
| 852 | /**
|
---|
| 853 | * Checks through all Lines and Dots on the current Frame to detect if any
|
---|
| 854 | * form an enclosure, which can then be used to manipulate items within the
|
---|
| 855 | * polygon. If an enclosure is found, then the dots will have their
|
---|
| 856 | * enclosure value set to true, and a List is created that contains all the
|
---|
| 857 | * Dots in the order they were processed. Actual calculation of the Polygon
|
---|
| 858 | * is done dynamically (to account for Dots being moved).
|
---|
| 859 | */
|
---|
| 860 | public static void OldEnclosedCheck(Collection<Item> items) {
|
---|
[4] | 861 | _seen.clear();
|
---|
| 862 |
|
---|
[50] | 863 | // get all lineEnds on the Frame
|
---|
| 864 | List<Item> lineEnds = new ArrayList<Item>(0);
|
---|
[4] | 865 | for (Item i : items) {
|
---|
[50] | 866 | if (i.isLineEnd()) {
|
---|
| 867 | i.setEnclosedList(null);
|
---|
[4] | 868 |
|
---|
[1190] | 869 | if (i.getLines().size() == 2) {
|
---|
[50] | 870 | lineEnds.add(i);
|
---|
[1190] | 871 | }
|
---|
[4] | 872 | }
|
---|
| 873 | }
|
---|
| 874 |
|
---|
[70] | 875 | // if there are no line endpoints on the Frame, then there can't be an
|
---|
| 876 | // enclosure
|
---|
[1190] | 877 | if (lineEnds.size() == 0) {
|
---|
[4] | 878 | return;
|
---|
[1190] | 879 | }
|
---|
[4] | 880 |
|
---|
[70] | 881 | // TODO optimise this code!!
|
---|
[50] | 882 | // iterate through all the lineEnds
|
---|
| 883 | for (Item searchFor : lineEnds) {
|
---|
[4] | 884 | _seen.clear();
|
---|
| 885 |
|
---|
| 886 | for (Line l : searchFor.getLines()) {
|
---|
| 887 | _seen.add(l);
|
---|
| 888 | if (traverse(searchFor, l.getOppositeEnd(searchFor))) {
|
---|
[50] | 889 | _path.add(l.getOppositeEnd(searchFor));
|
---|
[4] | 890 |
|
---|
[1190] | 891 | for (Item i : _path) {
|
---|
[50] | 892 | i.setEnclosedList(_path);
|
---|
[1190] | 893 | }
|
---|
[4] | 894 |
|
---|
[50] | 895 | _path = new ArrayList<Item>(0);
|
---|
[4] | 896 |
|
---|
| 897 | break;
|
---|
| 898 | }
|
---|
| 899 | }
|
---|
| 900 | }
|
---|
| 901 | }
|
---|
| 902 |
|
---|
| 903 | private static List<Line> _seen = new ArrayList<Line>();
|
---|
| 904 |
|
---|
[50] | 905 | private static List<Item> _path = new ArrayList<Item>();
|
---|
[4] | 906 |
|
---|
[50] | 907 | private static boolean traverse(Item toFind, Item searchFrom) {
|
---|
[1190] | 908 | if (toFind == null || searchFrom == null || !searchFrom.isLineEnd()) {
|
---|
[4] | 909 | return false;
|
---|
[1190] | 910 | }
|
---|
[4] | 911 |
|
---|
[1190] | 912 | if (searchFrom.getLines().size() != 2) {
|
---|
[4] | 913 | return false;
|
---|
[1190] | 914 | }
|
---|
[4] | 915 |
|
---|
[1190] | 916 | if (toFind == searchFrom) {
|
---|
[4] | 917 | return true;
|
---|
[1190] | 918 | }
|
---|
[4] | 919 |
|
---|
| 920 | for (Line l : searchFrom.getLines()) {
|
---|
| 921 | if (!(_seen.contains(l))) {
|
---|
| 922 | _seen.add(l);
|
---|
| 923 | if (traverse(toFind, l.getOppositeEnd(searchFrom))) {
|
---|
[50] | 924 | _path.add(l.getOppositeEnd(searchFrom));
|
---|
[4] | 925 | return true;
|
---|
| 926 | }
|
---|
| 927 | }
|
---|
| 928 |
|
---|
| 929 | }
|
---|
| 930 |
|
---|
| 931 | return false;
|
---|
| 932 | }
|
---|
[115] | 933 |
|
---|
[121] | 934 | /**
|
---|
[427] | 935 | * Determines if an item is visible from a the current frame(s). If the item
|
---|
| 936 | * is free then it is considered visible.
|
---|
| 937 | *
|
---|
| 938 | * @param i
|
---|
| 939 | * The item to check
|
---|
[121] | 940 | * @return True if visible/free from given frame.
|
---|
| 941 | */
|
---|
| 942 | public static boolean isVisible(Item i) {
|
---|
[1102] | 943 | if (DisplayController.isTwinFramesOn()) {
|
---|
| 944 | if (!isVisible(DisplayController.getFrameOnSide(TwinFramesSide.LEFT), i)) {
|
---|
| 945 | return isVisible(DisplayController.getFrameOnSide(TwinFramesSide.RIGHT), i);
|
---|
[121] | 946 | } else {
|
---|
| 947 | return true;
|
---|
| 948 | }
|
---|
[427] | 949 | } else {
|
---|
[1102] | 950 | return isVisible(DisplayController.getCurrentFrame(), i);
|
---|
[121] | 951 | }
|
---|
| 952 | }
|
---|
| 953 |
|
---|
| 954 | /**
|
---|
[427] | 955 | * Determines if an item is visible from a given frame. If the item is free
|
---|
| 956 | * then it is considered visible.
|
---|
[121] | 957 | *
|
---|
[427] | 958 | * @param fromFrame
|
---|
| 959 | * The frame to check from.
|
---|
| 960 | * @param i
|
---|
| 961 | * The item to check
|
---|
[121] | 962 | * @return True if visible/free from given frame.
|
---|
| 963 | */
|
---|
[1102] | 964 | public static boolean isVisible(Frame fromFrame, Item i)
|
---|
| 965 | {
|
---|
[1190] | 966 | if (fromFrame == null) {
|
---|
| 967 | return false;
|
---|
| 968 | }
|
---|
[427] | 969 |
|
---|
[121] | 970 | Frame parent = i.getParent();
|
---|
[427] | 971 |
|
---|
[1102] | 972 | if (parent == fromFrame) {
|
---|
[427] | 973 | return true;
|
---|
[1102] | 974 | } else if (parent == null) {
|
---|
| 975 | return FreeItems.getInstance().contains(i) || FreeItems.getCursor().contains(i);
|
---|
| 976 | }
|
---|
[121] | 977 |
|
---|
| 978 | return fromFrame.getAllItems().contains(i) && i.isVisible();
|
---|
| 979 | }
|
---|
[427] | 980 |
|
---|
[1102] | 981 | public static AxisAlignedBoxBounds expandRectangle(AxisAlignedBoxBounds r, int n)
|
---|
| 982 | {
|
---|
[1190] | 983 | if (r == null) {
|
---|
| 984 | return null;
|
---|
| 985 | }
|
---|
[1102] | 986 |
|
---|
| 987 | return new AxisAlignedBoxBounds(r.getMinX() - (n >> 1), r.getMinY() - (n >> 1), r.getWidth() + n, r.getHeight() + n);
|
---|
[121] | 988 | }
|
---|
[427] | 989 |
|
---|
[115] | 990 | /*
|
---|
| 991 | * FrameMouseActions while (!copies.isEmpty()) { Iterator<Item> iterator =
|
---|
| 992 | * copies.iterator(); Item item = iterator.next(); // Dont paint annotation
|
---|
| 993 | * items for @v if (!item.isVisible() || item.isAnnotation()) {
|
---|
| 994 | * iterator.remove(); continue; }
|
---|
| 995 | *
|
---|
| 996 | * if (!(item instanceof Line)) { item.setThickness(item.getThickness() *
|
---|
| 997 | * scale); if (item instanceof XRayable || item.hasEnclosures()) {
|
---|
| 998 | * scaleItem(scale, defaultForeground, defaultBackground, origin.x,
|
---|
| 999 | * origin.y, item); items.add(item); copies.remove(item); } else {
|
---|
| 1000 | * Collection<Item> connected = item.getAllConnected(); // Get all the
|
---|
| 1001 | * connected items because we can only set the // thickness ONCE for (Item i :
|
---|
| 1002 | * connected) { scaleItem(scale, defaultForeground, defaultBackground,
|
---|
| 1003 | * origin.x, origin.y, i); } items.addAll(connected);
|
---|
| 1004 | * copies.removeAll(connected); } } else { iterator.remove(); } }
|
---|
| 1005 | */
|
---|
| 1006 |
|
---|
| 1007 | /**
|
---|
| 1008 | * @param scale
|
---|
| 1009 | * @param defaultForeground
|
---|
| 1010 | * @param defaultBackground
|
---|
| 1011 | * @param originX
|
---|
| 1012 | * @param originY
|
---|
| 1013 | * @param item
|
---|
| 1014 | */
|
---|
| 1015 | private static void scaleItem(Vector v, Item item) {
|
---|
| 1016 | Float scale = v.Scale;
|
---|
[1143] | 1017 | int originX = v.Origin.getX();
|
---|
| 1018 | int originY = v.Origin.getY();
|
---|
[1102] | 1019 | Colour defaultForeground = v.Foreground;
|
---|
| 1020 | Colour defaultBackground = v.Background;
|
---|
[450] | 1021 | UserAppliedPermission permission = v.permission;
|
---|
[737] | 1022 | // TODO should this be checking if the frame has the
|
---|
| 1023 | // same permissions as the vector
|
---|
| 1024 | // and if so don't set the item's permissions?
|
---|
| 1025 | item.setOverlayPermission(permission);
|
---|
[115] | 1026 |
|
---|
[427] | 1027 | // TODO encapsulate this somewhere inside of circle class!
|
---|
| 1028 | // if(item instanceof Circle){
|
---|
| 1029 | // scaleItem(v, ((Circle)item).getCenter());
|
---|
| 1030 | // }
|
---|
| 1031 |
|
---|
| 1032 | if (!(item instanceof Line)) {
|
---|
[115] | 1033 | if (item.getColor() == null) {
|
---|
| 1034 | item.setColor(defaultForeground);
|
---|
| 1035 | }
|
---|
| 1036 | if (item.getBackgroundColor() == null) {
|
---|
| 1037 | item.setBackgroundColor(defaultBackground);
|
---|
| 1038 | }
|
---|
| 1039 | if (item.getFillColor() == null) {
|
---|
| 1040 | item.setFillColor(defaultBackground);
|
---|
| 1041 | }
|
---|
[311] | 1042 |
|
---|
[450] | 1043 | if (permission.equals(UserAppliedPermission.none)) {
|
---|
[115] | 1044 | item.setLinkMark(false);
|
---|
| 1045 | item.setActionMark(false);
|
---|
| 1046 | }
|
---|
[427] | 1047 |
|
---|
[311] | 1048 | item.scale(scale, originX, originY);
|
---|
[115] | 1049 | }
|
---|
| 1050 | }
|
---|
[427] | 1051 |
|
---|
[365] | 1052 | /**
|
---|
| 1053 | * Extracts widgets from an item list.
|
---|
| 1054 | *
|
---|
| 1055 | * @param items
|
---|
[427] | 1056 | * Items to extract from. Must not be null.
|
---|
[365] | 1057 | *
|
---|
[427] | 1058 | * @return List of (unique)widgets in items. Never null.
|
---|
[365] | 1059 | */
|
---|
[1102] | 1060 | public static List<Widget> extractWidgets(List<Item> items) {
|
---|
[427] | 1061 | assert (items != null);
|
---|
| 1062 |
|
---|
[1102] | 1063 | List<Widget> iWidgets = new LinkedList<Widget>();
|
---|
[427] | 1064 |
|
---|
[365] | 1065 | for (Item i : items) {
|
---|
| 1066 | if (i instanceof WidgetEdge) {
|
---|
[427] | 1067 | WidgetEdge we = (WidgetEdge) i;
|
---|
[1190] | 1068 | if (!iWidgets.contains(we.getWidgetSource())) {
|
---|
[365] | 1069 | iWidgets.add(we.getWidgetSource());
|
---|
[1190] | 1070 | }
|
---|
[365] | 1071 | } else if (i instanceof WidgetCorner) {
|
---|
[427] | 1072 | WidgetCorner wc = (WidgetCorner) i;
|
---|
[1190] | 1073 | if (!iWidgets.contains(wc.getWidgetSource())) {
|
---|
[365] | 1074 | iWidgets.add(wc.getWidgetSource());
|
---|
[1190] | 1075 | }
|
---|
[365] | 1076 | }
|
---|
| 1077 | }
|
---|
[427] | 1078 |
|
---|
[365] | 1079 | return iWidgets;
|
---|
| 1080 | }
|
---|
[920] | 1081 |
|
---|
[922] | 1082 | /**
|
---|
| 1083 | * Wraps any text items to the size of their container, or the frame size if they have not container
|
---|
| 1084 | *
|
---|
| 1085 | * @param items A list of Items to wrap (non-Text items are ignored)
|
---|
| 1086 | */
|
---|
[920] | 1087 | public static void Justify(Collection<Item> items) {
|
---|
| 1088 | for (Item i : items) {
|
---|
| 1089 | if (i instanceof Text) {
|
---|
| 1090 | Collection<Item> enclosure = FrameUtils.getEnclosingLineEnds(i.getPosition());
|
---|
[922] | 1091 | ((Text)i).justify(false, enclosure != null ? enclosure.iterator().next().getEnclosedShape() : null);
|
---|
[920] | 1092 | }
|
---|
| 1093 | }
|
---|
| 1094 | }
|
---|
| 1095 |
|
---|
[922] | 1096 | /**
|
---|
| 1097 | * Recalculates containers on the frame, then wraps all text items
|
---|
| 1098 | *
|
---|
| 1099 | * @param frame
|
---|
| 1100 | */
|
---|
[1102] | 1101 | public static void Justify(Frame frame)
|
---|
| 1102 | {
|
---|
[1190] | 1103 | if (frame == null) {
|
---|
| 1104 | return;
|
---|
| 1105 | }
|
---|
[1415] | 1106 | EnclosedCheck(frame.getSortedItems());
|
---|
| 1107 | Justify(frame.getSortedItems());
|
---|
[920] | 1108 | }
|
---|
[4] | 1109 | }
|
---|