[210] | 1 | /*
|
---|
| 2 | * cognet chat app
|
---|
| 3 | *
|
---|
| 4 | * Copyright 2003, Brian Swetland <swetland@frotz.net>
|
---|
| 5 | * See LICENSE for redistribution terms
|
---|
| 6 | *
|
---|
| 7 | * Derived from:
|
---|
| 8 | *
|
---|
| 9 | * @(#)ChatHistory.java 1.0 01/03/23
|
---|
| 10 | *
|
---|
| 11 | * Copyright 2000 by Danger Research, Inc.
|
---|
| 12 | * 165 University Avenue, Palo Alto, CA 94301
|
---|
| 13 | * All rights reserved.
|
---|
| 14 | * See SAMPLE_CODE_LICENSE for redistribution terms.
|
---|
| 15 | *
|
---|
| 16 | */
|
---|
| 17 |
|
---|
| 18 | package org.twodot.cognet;
|
---|
| 19 |
|
---|
| 20 | import danger.ui.*;
|
---|
| 21 | import danger.util.LineBreaker;
|
---|
| 22 | import java.util.Enumeration;
|
---|
| 23 |
|
---|
| 24 | public class ChatHistory extends View
|
---|
| 25 | {
|
---|
| 26 | public
|
---|
| 27 | ChatHistory(int inSizeLimit, Engine e)
|
---|
| 28 | {
|
---|
| 29 | Rect r;
|
---|
| 30 |
|
---|
| 31 | mPlainFont = Font.findSystemFont();
|
---|
| 32 | mBoldFont = Font.findSystemFont();
|
---|
| 33 |
|
---|
| 34 | mAscent = mBoldFont.getAscent() + mBoldFont.getDescent();
|
---|
| 35 | mLineHeight = mAscent + kLeading - 2;
|
---|
| 36 |
|
---|
| 37 | mLimit = inSizeLimit;
|
---|
| 38 |
|
---|
| 39 | setSize(20, 10);
|
---|
| 40 | engine = e;
|
---|
| 41 |
|
---|
| 42 | tag_bitmap = engine.app.bm_tag;
|
---|
| 43 | tag_width = tag_bitmap.getWidth();
|
---|
| 44 | tag_height = tag_bitmap.getHeight();
|
---|
| 45 | tag_font = Font.findFont("Bort7");
|
---|
| 46 | }
|
---|
| 47 |
|
---|
| 48 | Bitmap tag_bitmap;
|
---|
| 49 | int tag_width, tag_height;
|
---|
| 50 | Font tag_font;
|
---|
| 51 |
|
---|
| 52 |
|
---|
| 53 | public void
|
---|
| 54 | paint(Pen inPen)
|
---|
| 55 | {
|
---|
| 56 |
|
---|
| 57 | Rect r = getBounds();
|
---|
| 58 | int i, x, y;
|
---|
| 59 | ChatLine index = mBottomDisplayLine;
|
---|
| 60 |
|
---|
| 61 | //* Clear the area
|
---|
| 62 | if(mCurrentSelection != 0){
|
---|
| 63 | inPen.setColor(Color.GRAY10);
|
---|
| 64 | } else {
|
---|
| 65 | inPen.setColor(Color.WHITE);
|
---|
| 66 | }
|
---|
| 67 | inPen.fillRect(r);
|
---|
| 68 |
|
---|
| 69 | inPen.setColor(Color.BLACK);
|
---|
| 70 |
|
---|
| 71 | x = r.left;
|
---|
| 72 | y = mLineHeight * (mNumDisplayLines - 1);
|
---|
| 73 | y += mAscent;
|
---|
| 74 | y += r.top;
|
---|
| 75 |
|
---|
| 76 | SmileyEngine smiley = new SmileyEngine(mPlainFont);
|
---|
| 77 | inPen.setFont(mPlainFont);
|
---|
| 78 | //* Draw the individual lines
|
---|
| 79 | while ((y > r.top) && (null != index)) {
|
---|
| 80 | // if (engine.app.doSmileys)
|
---|
| 81 | smiley.drawString(x,y,index.mText, inPen);
|
---|
| 82 | // else
|
---|
| 83 | // inPen.drawText(x, y, index.mText);
|
---|
| 84 |
|
---|
| 85 | y -= mLineHeight;
|
---|
| 86 | index = index.mPrev;
|
---|
| 87 | }
|
---|
| 88 |
|
---|
| 89 | y = 0;
|
---|
| 90 | x = r.right - tag_width;
|
---|
| 91 |
|
---|
| 92 |
|
---|
| 93 | inPen.setColor(Color.BLACK);
|
---|
| 94 |
|
---|
| 95 | Enumeration enum = engine.alerts.keys();
|
---|
| 96 | while (enum.hasMoreElements()) {
|
---|
| 97 | inPen.setFont(tag_font);
|
---|
| 98 | inPen.drawBitmap(x, y, tag_bitmap);
|
---|
| 99 | inPen.drawText(x + 3, y + 9, ((Character) enum.nextElement()).toString());
|
---|
| 100 | y += tag_height;
|
---|
| 101 | }
|
---|
| 102 | }
|
---|
| 103 |
|
---|
| 104 | public void
|
---|
| 105 | setSize(int inWidth, int inHeight)
|
---|
| 106 | {
|
---|
| 107 | Rect r;
|
---|
| 108 |
|
---|
| 109 | super.setSize(inWidth, inHeight);
|
---|
| 110 |
|
---|
| 111 | mPlainLineBreaker = new LineBreaker("", mPlainFont, inWidth - 8, 0);
|
---|
| 112 | mBoldLineBreaker = new LineBreaker("", mBoldFont, inWidth - 8, 0);
|
---|
| 113 |
|
---|
| 114 | r = getBounds();
|
---|
| 115 | r.inset(kBorder);
|
---|
| 116 |
|
---|
| 117 | mNumDisplayLines = r.getHeight() / mLineHeight;
|
---|
| 118 | }
|
---|
| 119 |
|
---|
| 120 | public void
|
---|
| 121 | AddChannel(String inText) {
|
---|
| 122 | AddLines(inText, 0);
|
---|
| 123 | }
|
---|
| 124 |
|
---|
| 125 | public void
|
---|
| 126 | AddSent(String inText) {
|
---|
| 127 | AddLines(inText, 3);
|
---|
| 128 | }
|
---|
| 129 |
|
---|
| 130 | public void
|
---|
| 131 | AddPrivate(String inText) {
|
---|
| 132 | AddLines(inText, 1);
|
---|
| 133 | }
|
---|
| 134 |
|
---|
| 135 | public void
|
---|
| 136 | AddServer(String inText) {
|
---|
| 137 | AddLines(inText, 2);
|
---|
| 138 | }
|
---|
| 139 |
|
---|
| 140 |
|
---|
| 141 | void AddLines(String inText, int glyph) {
|
---|
| 142 | if (engine.app.doSmileys)
|
---|
| 143 | AddLinesIcon(inText, glyph);
|
---|
| 144 | else
|
---|
| 145 | AddLinesPlain(inText, glyph);
|
---|
| 146 | }
|
---|
| 147 |
|
---|
| 148 | private void AddLinesPlain(String inText, int glyph)
|
---|
| 149 | {
|
---|
| 150 | int firstChar = 0, lastChar = 0;
|
---|
| 151 | boolean firstLine = true;
|
---|
| 152 | LineBreaker lineBreaker;
|
---|
| 153 |
|
---|
| 154 | //* If we're scrolled up then we need to mark this line as the first
|
---|
| 155 | //* incoming line that we missed;
|
---|
| 156 | if (0 == mCurrentSelection)
|
---|
| 157 | mFirstMissed = false;
|
---|
| 158 |
|
---|
| 159 | //* Pick the right line breaker depending on the font
|
---|
| 160 | lineBreaker = mPlainLineBreaker;
|
---|
| 161 |
|
---|
| 162 | lineBreaker.setText(inText);
|
---|
| 163 |
|
---|
| 164 | while (lastChar < inText.length())
|
---|
| 165 | {
|
---|
| 166 | String s;
|
---|
| 167 | ChatLine line;
|
---|
| 168 |
|
---|
| 169 | lastChar = lineBreaker.nextLineBreak(firstChar);
|
---|
| 170 |
|
---|
| 171 | s = inText.substring(firstChar, lastChar);
|
---|
| 172 | line = new ChatLine(s, glyph, firstLine, mFirstMissed);
|
---|
| 173 | AddLine(line, glyph);
|
---|
| 174 |
|
---|
| 175 | firstLine = false;
|
---|
| 176 | mFirstMissed = false;
|
---|
| 177 |
|
---|
| 178 | firstChar = lastChar;
|
---|
| 179 | }
|
---|
| 180 |
|
---|
| 181 | TrimForLength();
|
---|
| 182 | }
|
---|
| 183 |
|
---|
| 184 |
|
---|
| 185 | private void AddLinesIcon(String inText, int glyph)
|
---|
| 186 | {
|
---|
| 187 | int firstChar = 0, lastChar = 0;
|
---|
| 188 | boolean firstLine = true;
|
---|
| 189 | //LineBreaker lineBreaker;
|
---|
| 190 | SmileyEngine smileyEngine;
|
---|
| 191 |
|
---|
| 192 | //* If we're scrolled up then we need to mark this line as the first
|
---|
| 193 | //* incoming line that we missed;
|
---|
| 194 | if (0 == mCurrentSelection)
|
---|
| 195 | mFirstMissed = false;
|
---|
| 196 |
|
---|
| 197 | //* Pick the right line breaker depending on the font
|
---|
| 198 | //lineBreaker = mPlainLineBreaker;
|
---|
| 199 |
|
---|
| 200 | //lineBreaker.setText(inText);
|
---|
| 201 | if (inText.startsWith("<::::>")) {
|
---|
| 202 | // server flag
|
---|
| 203 | inText = SmileyEngine.ICON_FLAG + inText.substring(6);
|
---|
| 204 | }
|
---|
| 205 | if (inText.startsWith("<*>")) {
|
---|
| 206 | // cognet++ message
|
---|
| 207 | inText = SmileyEngine.ICON_COG + inText.substring(3);
|
---|
| 208 | }
|
---|
| 209 | if (inText.startsWith("* ")) {
|
---|
| 210 | // action flag
|
---|
| 211 | inText = SmileyEngine.ICON_BULLET + inText.substring(1);
|
---|
| 212 | }
|
---|
| 213 | if (inText.startsWith("<-> ")) {
|
---|
| 214 | // info flag
|
---|
| 215 | inText = SmileyEngine.ICON_INFO + inText.substring(3);
|
---|
| 216 | }
|
---|
| 217 |
|
---|
| 218 | smileyEngine = new SmileyEngine(mPlainFont, inText);
|
---|
| 219 | String strLine;
|
---|
| 220 |
|
---|
| 221 |
|
---|
| 222 | while ((strLine = smileyEngine.getNext(getWidth() - 8)) != null)
|
---|
| 223 | {
|
---|
| 224 | String s;
|
---|
| 225 | ChatLine line;
|
---|
| 226 |
|
---|
| 227 | line = new ChatLine(strLine, glyph, firstLine, mFirstMissed);
|
---|
| 228 | AddLine(line, glyph);
|
---|
| 229 |
|
---|
| 230 | firstLine = false;
|
---|
| 231 | mFirstMissed = false;
|
---|
| 232 |
|
---|
| 233 | }
|
---|
| 234 |
|
---|
| 235 | TrimForLength();
|
---|
| 236 | }
|
---|
| 237 |
|
---|
| 238 | public void
|
---|
| 239 | AddLine(ChatLine inLine, int glyph)
|
---|
| 240 | {
|
---|
| 241 | Rect r = getBounds();
|
---|
| 242 | int numLines;
|
---|
| 243 | ChatLine line;
|
---|
| 244 | boolean atBottom = false;
|
---|
| 245 |
|
---|
| 246 | if (mBottomDisplayLine == mTail)
|
---|
| 247 | atBottom = true;
|
---|
| 248 |
|
---|
| 249 | mNumLines++;
|
---|
| 250 | mTextSize += inLine.mText.length();
|
---|
| 251 |
|
---|
| 252 | r.inset(kBorder);
|
---|
| 253 | numLines = r.getHeight() / mLineHeight;
|
---|
| 254 |
|
---|
| 255 | if (null == mHead)
|
---|
| 256 | {
|
---|
| 257 | mHead = inLine;
|
---|
| 258 | mBottomDisplayLine = inLine;
|
---|
| 259 | mTail = inLine;
|
---|
| 260 |
|
---|
| 261 | return;
|
---|
| 262 | }
|
---|
| 263 |
|
---|
| 264 | mTail.mNext = inLine;
|
---|
| 265 | inLine.mPrev = mTail;
|
---|
| 266 | mTail = inLine;
|
---|
| 267 |
|
---|
| 268 | if (atBottom /* || output */)
|
---|
| 269 | {
|
---|
| 270 | mCurrentSelection = 0;
|
---|
| 271 | mBottomDisplayLine = mTail;
|
---|
| 272 | }
|
---|
| 273 | else
|
---|
| 274 | {
|
---|
| 275 | mCurrentSelection++;
|
---|
| 276 | }
|
---|
| 277 | }
|
---|
| 278 |
|
---|
| 279 | void
|
---|
| 280 | TrimForLength()
|
---|
| 281 | {
|
---|
| 282 | while (mTextSize > mLimit)
|
---|
| 283 | {
|
---|
| 284 | if (mNumDisplayLines >= (mNumLines - mCurrentSelection))
|
---|
| 285 | {
|
---|
| 286 | mCurrentSelection--;
|
---|
| 287 | mBottomDisplayLine = mBottomDisplayLine.mNext;
|
---|
| 288 | }
|
---|
| 289 |
|
---|
| 290 | mTextSize -= mHead.mText.length();
|
---|
| 291 |
|
---|
| 292 | mHead.mNext.mPrev = null;
|
---|
| 293 | mHead = mHead.mNext;
|
---|
| 294 |
|
---|
| 295 | mNumLines--;
|
---|
| 296 | }
|
---|
| 297 | }
|
---|
| 298 |
|
---|
| 299 | void
|
---|
| 300 | ScrollUp()
|
---|
| 301 | {
|
---|
| 302 | if ((mNumLines - mCurrentSelection) <= mNumDisplayLines)
|
---|
| 303 | return;
|
---|
| 304 |
|
---|
| 305 | mCurrentSelection++;
|
---|
| 306 | mBottomDisplayLine = mBottomDisplayLine.mPrev;
|
---|
| 307 |
|
---|
| 308 | mFirstMissed = true;
|
---|
| 309 | }
|
---|
| 310 |
|
---|
| 311 | void
|
---|
| 312 | ScrollDown()
|
---|
| 313 | {
|
---|
| 314 | if (mCurrentSelection == 0)
|
---|
| 315 | return;
|
---|
| 316 |
|
---|
| 317 | mCurrentSelection--;
|
---|
| 318 | mBottomDisplayLine = mBottomDisplayLine.mNext;
|
---|
| 319 |
|
---|
| 320 | if (0 == mCurrentSelection)
|
---|
| 321 | mFirstMissed = false;
|
---|
| 322 | }
|
---|
| 323 |
|
---|
| 324 | public void
|
---|
| 325 | Clear() {
|
---|
| 326 | mTextSize = 0;
|
---|
| 327 | mNumLines = 0;
|
---|
| 328 | mCurrentSelection = 0;
|
---|
| 329 | mHead = null;
|
---|
| 330 | mTail = null;
|
---|
| 331 | mBottomDisplayLine = null;
|
---|
| 332 | mFirstMissed = false;
|
---|
| 333 | }
|
---|
| 334 |
|
---|
| 335 | void setPlainFont(Font f) {
|
---|
| 336 | Clear();
|
---|
| 337 | mPlainFont = f;
|
---|
| 338 | mAscent = mPlainFont.getAscent() + mPlainFont.getDescent();
|
---|
| 339 | mLineHeight = mAscent + kLeading - 2;
|
---|
| 340 | mNumDisplayLines = getHeight() / mLineHeight;
|
---|
| 341 | }
|
---|
| 342 |
|
---|
| 343 | void setEmoticons(boolean onOff) {
|
---|
| 344 | Clear();
|
---|
| 345 | engine.app.doSmileys = onOff;
|
---|
| 346 | }
|
---|
| 347 |
|
---|
| 348 | private int mLimit;
|
---|
| 349 | private int mTextSize;
|
---|
| 350 | private int mNumDisplayLines;
|
---|
| 351 |
|
---|
| 352 | private int mNumLines;
|
---|
| 353 | private int mCurrentSelection;
|
---|
| 354 |
|
---|
| 355 | private int mAscent;
|
---|
| 356 | private int mLineHeight;
|
---|
| 357 |
|
---|
| 358 | private ChatLine mHead;
|
---|
| 359 | private ChatLine mBottomDisplayLine;
|
---|
| 360 | private ChatLine mTail;
|
---|
| 361 |
|
---|
| 362 | private Font mPlainFont;
|
---|
| 363 | private Font mBoldFont;
|
---|
| 364 |
|
---|
| 365 | private LineBreaker mPlainLineBreaker;
|
---|
| 366 | private LineBreaker mBoldLineBreaker;
|
---|
| 367 |
|
---|
| 368 | private boolean mFirstMissed;
|
---|
| 369 |
|
---|
| 370 | static final int kBorder = 2;
|
---|
| 371 | static final int kLeading = 2;
|
---|
| 372 | Engine engine;
|
---|
| 373 | }
|
---|
| 374 |
|
---|
| 375 | class ChatLine
|
---|
| 376 | {
|
---|
| 377 | public
|
---|
| 378 | ChatLine(String inText, int glyph, boolean inFirstLine, boolean inFirstMissed)
|
---|
| 379 | {
|
---|
| 380 | mText = inText;
|
---|
| 381 | mGlyph = glyph;
|
---|
| 382 | mFirstLine = inFirstLine;
|
---|
| 383 | mFirstMissed = inFirstMissed;
|
---|
| 384 | }
|
---|
| 385 |
|
---|
| 386 | String mText;
|
---|
| 387 | int mGlyph;
|
---|
| 388 | boolean mFirstLine;
|
---|
| 389 | boolean mFirstMissed;
|
---|
| 390 |
|
---|
| 391 | ChatLine mPrev;
|
---|
| 392 | ChatLine mNext;
|
---|
| 393 | }
|
---|