/* * #%L * data-exporter * %% * Copyright (C) 2012 - 2013 http://www.brsanthu.com * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ package com.brsanthu.dataexporter; import java.util.ArrayList; import java.util.List; import com.brsanthu.dataexporter.model.AlignType; import com.brsanthu.dataexporter.util.Util; /** * Class used to align the text according to different alignment modes. This is completely independent * class and can be used in other applications. Sample usage is shown below. * * <pre> * public static void main(String[] args) { * TextAligner textAligner = new TextAligner(); * for (AlignType align : AlignType.values()) { * * System.out.println("<h1>" + align.toString() + "</h1>"); * List<String> list = (textAligner.align(15, 10, align, "Hello world is the common phrase used everywhere. In this sentense somewordsarereallyreallybig ones.")); * for (String string : list) { * System.out.println("|" + string + "|"); * } * System.out.println(""); * } * } * </pre> * which produces the following output * <pre> * <h1>TOP_LEFT</h1> * |Hello world is | * |the common | * |phrase used | * |everywhere. In | * |this sentense | * |somewordsarerea| * |llyreallybig | * |ones. | * | | * | | * * <h1>TOP_CENTER</h1> * |Hello world is | * | the common | * | phrase used | * |everywhere. In | * | this sentense | * |somewordsarerea| * | llyreallybig | * | ones. | * | | * | | * * <h1>TOP_RIGHT</h1> * | Hello world is| * | the common| * | phrase used| * | everywhere. In| * | this sentense| * |somewordsarerea| * | llyreallybig| * | ones.| * | | * | | * * <h1>MIDDLE_LEFT</h1> * | | * |Hello world | * |is the common | * |phrase used | * |everywhere. | * |In this sentense| * |somewordsarerea| * |llyreallybig | * |ones. | * | | * * <h1>MIDDLE_CENTER</h1> * | | * | Hello world | * | is the common | * | phrase used | * | everywhere. | * |In this sentense| * |somewordsarerea| * | llyreallybig | * | ones. | * | | * * <h1>MIDDLE_RIGHT</h1> * | | * | Hello world| * | is the common| * | phrase used| * | everywhere.| * |In this sentense| * |somewordsarerea| * | llyreallybig| * | ones.| * | | * * <h1>BOTTOM_LEFT</h1> * | | * | | * |Hello world | * |is the common | * |phrase used | * |everywhere. In | * |this sentense | * |somewordsarerea| * |llyreallybig | * |ones. | * * <h1>BOTTOM_CENTER</h1> * | | * | | * | Hello world | * | is the common | * | phrase used | * |everywhere. In | * | this sentense | * |somewordsarerea| * | llyreallybig | * | ones. | * * <h1>BOTTOM_RIGHT</h1> * | | * | | * | Hello world| * | is the common| * | phrase used| * | everywhere. In| * | this sentense| * |somewordsarerea| * | llyreallybig| * | ones.| * * </pre> * @author Santhosh Kumar */ public class TextAligner { public int getRowHeight(int width, String data, AlignType alignType) { List<String> alignedStrings = align(width, data.length(), alignType, data); int rowHeight = 0; for (String line : alignedStrings) { if (line.trim().length() > 0) { rowHeight++; } } return Math.max(1, rowHeight); } /** * Aligns the given text according to requested alignment and returns the list of strings. * * @param width width of the cell. Cannot be less than 0 * @param height height of the cell. Cannot be less than 0 * @param align alignment mode. * @param data string data to be aligned. Can be null and if so, assumed empty. * * @return returns the ArrayList of Strings, corresponding to aligned lines. */ public List<String> align(int width, int height, AlignType align, String data) { return align(width, height, align, data, " "); } public List<String> align(int width, int height, AlignType align, String data, String filler) { Util.checkForNotNull(align, "align"); if (height <= 0 || width <= 0) { throw new IllegalArgumentException("Height or width cannot be less than or equal to zero."); } if (data == null) { data = ""; } int totalChars = width * height; if (data.length() > totalChars) { throw new IllegalArgumentException("Data given (" + data.length() + " chars) is bigger than cell size of " + totalChars + " chars (width " + width + " x height " + height + ")"); } //If number of words are larger than height, compact to at least height. //Compacting happens starting at top, middle or bottom as requested List<String> compacted = new ArrayList<String>(); //If the data length is less than column width, then there is nothing to compact. //Issue# 1 if (data.length() <= width) { switch(align) { case TOP_CENTER: case TOP_LEFT: case TOP_RIGHT: compacted.add(data); for (int i = 0; i < height - 1; i++) { compacted.add(""); } break; case MIDDLE_CENTER: case MIDDLE_LEFT: case MIDDLE_RIGHT: int midwayIndex = (int) Math.ceil((float) height/2) - 1; if (midwayIndex >= height) { midwayIndex--; } for (int i = 0; i < midwayIndex; i++) { compacted.add(""); } compacted.add(data); for (int i = midwayIndex + 1; i < height; i++) { compacted.add(""); } break; case BOTTOM_CENTER: case BOTTOM_LEFT: case BOTTOM_RIGHT: for (int i = 0; i < height - 1; i++) { compacted.add(""); } compacted.add(data); break; } } else { //Split at the word boundary String[] words = data.split("\\s"); //Check if any word is bigger than the width. If so, split into multiple words. List<String> wordsFinal = new ArrayList<String>(); for (String word : words) { if (word.trim().length() >= width) { wordsFinal.addAll(splitWord(word, width)); } else { wordsFinal.add(word.trim()); } } StringBuilder sb = new StringBuilder(); int numerOfFillers = 0; switch (align) { case TOP_LEFT: case TOP_CENTER: case TOP_RIGHT: for (int i = 0; i < wordsFinal.size(); i++) { //See if this word could be joined with previous string and still fits //in the width if ((sb.length()==0?0: sb.length() + 1) + wordsFinal.get(i).length() <= width) { if (sb.length() > 0) { sb.append(" "); } sb.append(wordsFinal.get(i)); } else { compacted.add(sb.toString()); sb = new StringBuilder(); sb.append(wordsFinal.get(i)); } } if (sb.length() > 0) { compacted.add(sb.toString()); } //We may need to add filler lines at the end of the list. numerOfFillers = height - compacted.size(); for (int i = 0; i < numerOfFillers; i++) { compacted.add(""); } break; case MIDDLE_LEFT: case MIDDLE_CENTER: case MIDDLE_RIGHT: //Compact mid way towards beginning int midwayIndex = (int) Math.ceil((float) wordsFinal.size()/2); if (midwayIndex >= wordsFinal.size()) { midwayIndex--; } for (int i = midwayIndex; i >= 0; i--) { //See if this word could be joined with previous string and still fits //in the widths if (sb.length() + wordsFinal.get(i).length() <= width - 1) { if (sb.length() > 0) { sb.insert(0, " "); } sb.insert(0, wordsFinal.get(i)); } else { compacted.add(0, sb.toString()); sb = new StringBuilder(); sb.insert(0, wordsFinal.get(i)); } } if (sb.length() > 0) { compacted.add(0, sb.toString()); } sb = new StringBuilder(); //Compact mid way towards beginning for (int i = midwayIndex + 1; i < wordsFinal.size(); i++) { //See if this word could be joined with previous string and still fits //in the width if (sb.length() + wordsFinal.get(i).length() <= width) { if (sb.length() > 0) { sb.append(" "); } sb.append(wordsFinal.get(i)); } else { compacted.add(sb.toString()); sb = new StringBuilder(); sb.append(wordsFinal.get(i)); } } if (sb.length() > 0) { compacted.add(sb.toString()); } //We may need to add filler lines at beginning and as well at the end. numerOfFillers = Math.max(0, height - compacted.size()) / 2; for (int i = 0; i < numerOfFillers; i++) { compacted.add(0, ""); } numerOfFillers = height - compacted.size(); for (int i = 0; i < numerOfFillers; i++) { compacted.add(""); } break; case BOTTOM_LEFT: case BOTTOM_CENTER: case BOTTOM_RIGHT: for (int i = wordsFinal.size() - 1; i >= 0; i--) { //See if this word could be joined with previous string and still fits //in the widths if (sb.length() + wordsFinal.get(i).length() <= width - 1) { if (sb.length() > 0) { sb.insert(0, " "); } sb.insert(0, wordsFinal.get(i)); } else { compacted.add(0, sb.toString()); sb = new StringBuilder(); sb.insert(0, wordsFinal.get(i)); } } if (sb.length() > 0) { compacted.add(0, sb.toString()); } numerOfFillers = height - compacted.size(); for (int i = 0; i < numerOfFillers; i++) { compacted.add(0, ""); } break; } } List<String> aligned = new ArrayList<String>(); //Align Horizontal for (int i = 0; i < compacted.size(); i++) { int prefixCount = 0; int suffixCount = 0; String tempData = compacted.get(i); if (tempData == null) { tempData = ""; } switch (align) { case TOP_LEFT: case MIDDLE_LEFT: case BOTTOM_LEFT: suffixCount = width - tempData.length(); break; case TOP_CENTER: case MIDDLE_CENTER: case BOTTOM_CENTER: prefixCount = (width - tempData.length())/2; suffixCount = width - prefixCount - tempData.length(); break; case TOP_RIGHT: case MIDDLE_RIGHT: case BOTTOM_RIGHT: prefixCount = width - tempData.length(); break; } aligned.add(Util.createSpacer(prefixCount) + tempData + Util.createSpacer(suffixCount)); } return aligned; } private String substring(String data, int startIndex, int endIndex) { if (startIndex < 0) { startIndex = 0; } if (endIndex > data.length()) { endIndex = data.length(); } return data.substring(startIndex, endIndex); } private List<String> splitWord(String word, int width) { List<String> words = new ArrayList<String>(); int startIndex = 0; while (startIndex < word.length()) { words.add(substring(word, startIndex, startIndex + width).trim()); startIndex += width; } return words; } }