001 /* 002 * Copyright (C) 2012 eXo Platform SAS. 003 * 004 * This is free software; you can redistribute it and/or modify it 005 * under the terms of the GNU Lesser General Public License as 006 * published by the Free Software Foundation; either version 2.1 of 007 * the License, or (at your option) any later version. 008 * 009 * This software is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public 015 * License along with this software; if not, write to the Free 016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 018 */ 019 020 package org.crsh.text; 021 022 import java.io.IOException; 023 import java.io.Serializable; 024 import java.util.Iterator; 025 import java.util.LinkedList; 026 027 public class ScreenBuffer implements Iterable<Object>, Serializable, Screenable { 028 029 /** . */ 030 private final LinkedList<Object> chunks; 031 032 /** . */ 033 private Style current; 034 035 /** . */ 036 private Style next; 037 038 /** Where we flush. */ 039 private final ScreenContext out; 040 041 public ScreenBuffer() { 042 this.chunks = new LinkedList<Object>(); 043 this.current = Style.style(); 044 this.next = Style.style(); 045 this.out = null; 046 } 047 048 public ScreenBuffer(ScreenContext out) { 049 this.chunks = new LinkedList<Object>(); 050 this.current = Style.style(); 051 this.next = Style.style(); 052 this.out = out; 053 } 054 055 public Iterator<Object> iterator() { 056 return chunks.iterator(); 057 } 058 059 public void format(Format format, Appendable appendable) throws IOException { 060 format.begin(appendable); 061 for (Object chunk : this) { 062 if (chunk instanceof Style) { 063 format.write((Style)chunk, appendable); 064 } else if (chunk instanceof CLS) { 065 format.cls(appendable); 066 } else { 067 format.write((CharSequence)chunk, appendable); 068 } 069 } 070 format.end(appendable); 071 } 072 073 public ScreenBuffer append(Iterable<?> data) throws NullPointerException { 074 for (Object o : data) { 075 append(o); 076 } 077 return this; 078 } 079 080 public ScreenBuffer append(Object... data) throws NullPointerException { 081 for (Object o : data) { 082 append(o); 083 } 084 return this; 085 } 086 087 public ScreenBuffer cls() { 088 chunks.addLast(CLS.INSTANCE); 089 return this; 090 } 091 092 public ScreenBuffer append(Style style) throws NullPointerException { 093 next = next.merge(style); 094 return this; 095 } 096 097 @Override 098 public ScreenBuffer append(char c) throws IOException { 099 return append(Character.toString(c)); 100 } 101 102 public ScreenBuffer append(CharSequence s) { 103 if (s.length() > 0) { 104 if (!next.equals(current)) { 105 if (!Style.style().equals(next)) { 106 chunks.addLast(next); 107 } 108 current = next; 109 next = Style.style(); 110 } 111 chunks.addLast(s); 112 } 113 return this; 114 } 115 116 public ScreenBuffer append(CharSequence s, int start, int end) { 117 if (end != start) { 118 if (start != 0 || end != s.length()) { 119 s = s.subSequence(start, end); 120 } 121 append(s); 122 } 123 return this; 124 } 125 126 public void flush() throws IOException { 127 if (out != null) { 128 for (Object chunk : chunks) { 129 if (chunk instanceof CLS) { 130 out.cls(); 131 } else if (chunk instanceof CharSequence) { 132 out.append((CharSequence)chunk); 133 } else { 134 out.append((Style)chunk); 135 } 136 } 137 } 138 chunks.clear(); 139 if (out != null) { 140 out.flush(); 141 } 142 } 143 144 public ScreenBuffer append(ScreenBuffer s) throws NullPointerException { 145 for (Object chunk : s.chunks) { 146 append(chunk); 147 } 148 if (s.next != null && !s.next.equals(Style.style())) { 149 append(s.next); 150 } 151 return this; 152 } 153 154 public ScreenBuffer append(Object o) throws NullPointerException { 155 if (o == null) { 156 throw new NullPointerException("No null accepted"); 157 } 158 if (o instanceof ScreenBuffer) { 159 append((ScreenBuffer)o); 160 } else if (o instanceof Style) { 161 append((Style)o); 162 } else if (o instanceof CharSequence){ 163 append(((CharSequence)o)); 164 } else if (o instanceof CLS) { 165 cls(); 166 } else { 167 append(o.toString()); 168 } 169 return this; 170 } 171 172 public boolean contains(Object o) { 173 return toString().contains(o.toString()); 174 } 175 176 public boolean isEmpty() { 177 return chunks.isEmpty(); 178 } 179 180 public void clear() { 181 chunks.clear(); 182 } 183 184 @Override 185 public int hashCode() { 186 return toString().hashCode(); 187 } 188 189 @Override 190 public boolean equals(Object obj) { 191 if (obj == this) { 192 return true; 193 } 194 if (obj instanceof ScreenBuffer) { 195 ScreenBuffer that = (ScreenBuffer)obj; 196 return toString().equals(that.toString()); 197 } 198 return false; 199 } 200 201 @Override 202 public String toString() { 203 StringBuilder sb = new StringBuilder(); 204 try { 205 format(Format.TEXT, sb); 206 } 207 catch (IOException ignore) { 208 } 209 return sb.toString(); 210 } 211 }