/** * Format.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.agents; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import org.expeditee.gui.DisplayController; import org.expeditee.gui.Frame; import org.expeditee.gui.FrameUtils; import org.expeditee.items.Item; import org.expeditee.items.Text; /** * A simple formatting agent that aligns all non-annotation Items on the given * Frame by the X and Y axis of the first Item on the Frame. This agent * separates the items into columns, the actual alignment is done by * FrameUtils.Align() * * @author jdm18 * */ public class Format extends DefaultAgent { // whether the Items could be formatted successfully private boolean _success = true; // adjustmen from the default format spacing private int _adjust = 0; public Format() { super(); } public Format(String param) { try { if (param.startsWith("+")) param = param.substring(1); _adjust = Integer.parseInt(param); } catch (Exception e) { e.printStackTrace(); } } @Override public Frame process(Frame start) { // TODO What will happen if user runs the SIMPLE form of this... // Does format box need to be disabled?!?! // Check the position of the cursor and only format stuff inside the // same box as the cursor Collection itemsToFormat = getItemsToFormat(start); List changedItems = new ArrayList(); ArrayList columnHeads = new ArrayList(); ArrayList> columns = new ArrayList>(); for (Text t : itemsToFormat) { int col = findColumn(columnHeads, t); // if this is the head of a new column if (col < 0) { columnHeads.add(t); columns.add(new ArrayList()); // otherwise the column for this item has already been // found set the column to be the one we just added... col = columns.size() - 1; } else columns.get(col).add(t); } // check for empty columns int[] clear = new int[columnHeads.size()]; for (int i = 0; i < columns.size(); i++) clear[i] = columns.get(i).size(); // remove empty columns for (int i = (clear.length - 1); i >= 0; i--) if (clear[i] == 0) { columns.remove(i); columnHeads.remove(i); } // if there are no columns to align, we are done if (columns.size() == 0) return null; // sort the column heads by X position Collections.sort(columnHeads, new Comparator() { public int compare(Item o1, Item o2) { return o1.getX() - o2.getX(); } }); // sort lists by their X axis Collections.sort(columns, new Comparator>() { public int compare(ArrayList o1, ArrayList o2) { if (o2.size() == 0) return -10; if (o1.size() == 0) return 10; Item i1 = o1.get(0); Item i2 = o2.get(0); return (i1.getX() - i2.getX()); } }); int res = FrameUtils.Align(columns.get(0), true, _adjust); _success = _success && (res >= 0); for (int i = 0; i < columns.size() - 1; i++) { List list = columns.get(i); int maxX = 0; int maxY = 0; for (Item it : list) { maxX = Math.max(maxX, it.getX() + it.getBoundsWidth()); maxY = Math.max(maxY, it.getY() + it.getBoundsHeight()); } int xCheck = maxX; for (Item it : columns.get(i + 1)) xCheck = Math.max(xCheck, maxX + /* item.getX() + */it.getBoundsWidth()); if (xCheck < DisplayController.getFramePaintAreaWidth()) { Item columnHead = columnHeads.get(i + 1); if (columnHead.getX() < maxX && columnHead.getY() < maxY) { if(columnHead.getX() != maxX && !changedItems.contains(columnHead)) { Item copy = columnHead.copy(); copy.setID(columnHead.getID()); changedItems.add(copy); } columnHead.setX(maxX); } for (Item it : columns.get(i + 1)) { if (it.getX() < maxX && it.getY() < maxY) { if(it.getX() != maxX && !changedItems.contains(it)) { Item copy = it.copy(); copy.setID(it.getID()); changedItems.add(copy); } it.setX(maxX); } } } res = FrameUtils.Align(columns.get(i + 1), true, _adjust, changedItems); _success = _success && (res >= 0); } // align all the separate columns /* * for(ArrayList l : columns){ int res = FrameUtils.Align(l, * true); _success = _success && (res >= 0); } */ start.setChanged(true); start.addToUndoMove(changedItems); DisplayController.requestRefresh(true); return null; } /** * Finds which column contains the given Item, and returns the index to the * column in the start & end lists. Returns -1 if no column is found that * contains the given Item. * * @param toFind * The Item to determine the correct column for * @return The index of the column in the lists, or -1 if no column is found */ private int findColumn(ArrayList columnHeads, Item toFind) { for (Item top : columnHeads) if (FrameUtils.inSameColumn(top, toFind)) return columnHeads.indexOf(top); return -1; } @Override protected void finalise(Frame start) { if (_success) overwriteMessage("Formatting complete."); } @Override protected void message(String message) { } @Override protected void overwriteMessage(String message) { } /** * Gets all the items that need to be formatted. If the user clicks in * freeSpace these are all items not enclosed by a rectangle. If the user is * formatting the items in a rectangle this is all the items in the * rectangle. * * @param start */ protected Collection getItemsToFormat(Frame start) { Collection itemsToFormat = FrameUtils.getCurrentTextItems(); // If the cursor is not inside a box... if (itemsToFormat.size() < 1) { // Add all the items that are in free space itemsToFormat = start.getBodyTextItems(true); // Remove all the enclosed items Collection seen = new HashSet(); for (Item i : start.getVisibleItems()) { if (!seen.contains(i) && i.isEnclosed()) { seen.addAll(i.getEnclosingDots()); itemsToFormat.removeAll(i.getEnclosedItems()); } } } return itemsToFormat; } }