/******************************************************************************* Jimm - Mobile Messaging - J2ME ICQ clone Copyright (C) 2003-05 Jimm Project 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ******************************************************************************** File: src/jimm/Emotions.java Version: ###VERSION### Date: ###DATE### Author(s): Artyomov Denis *******************************************************************************/ package jimm.modules; // #sijapp cond.if (modules_SMILES is "true") # import jimmui.ContentActionListener; import jimmui.view.icons.*; import java.util.*; import java.io.*; import jimm.comm.*; import jimmui.view.smiles.SmileSelector; import jimmui.view.smiles.SmilesContent; import protocol.net.TcpSocket; public final class Emotions { private ImageList images; private int[] selEmotionsIndexes; private String[] selEmotionsWord; private String[] selEmotionsSmileNames; private String smileChars; private int[] textCorrIndexes; private String[] textCorrWords; private Emotions() {} public static final Emotions instance = new Emotions(); private static final int PARSER_NONE = 0; private static final int PARSER_NUMBER = 1; private static final int PARSER_MNAME = 2; private static final int PARSER_NAME = 3; private static final int PARSER_LONG_NAME = 4; private static final int PARSER_FIRST_SMILE = 5; private static final int PARSER_SMILE = 6; private void smileParser(String content, Vector<Object[]> textCorr, Vector<Object[]> selEmotions) { Integer curIndex = new Integer(0); String smileName = ""; String word = ""; int beginPos = 0; int state = PARSER_NONE; int len = content.length(); for (int i = 0; i <= len; ++i) { char ch = (i < len) ? content.charAt(i) : '\n'; if ('\r' == ch) continue; switch (state) { case PARSER_NONE: if ('"' == ch) { state = PARSER_LONG_NAME; beginPos = i + 1; } else if ((' ' == ch) || ('\n' == ch)) { } else { state = PARSER_NUMBER; beginPos = i; } break; case PARSER_NUMBER: if (' ' == ch) { state = PARSER_MNAME; smileName = content.substring(beginPos, i).trim(); beginPos = i + 1; try { Integer.parseInt(smileName); } catch (Exception e) { state = PARSER_FIRST_SMILE; } } break; case PARSER_MNAME: if ('"' == ch) { state = PARSER_LONG_NAME; beginPos = i + 1; } else if (' ' == ch) { } else { state = PARSER_NAME; beginPos = i; } break; case PARSER_NAME: if (' ' == ch) { state = PARSER_FIRST_SMILE; smileName = content.substring(beginPos, i).trim(); beginPos = i + 1; } break; case PARSER_LONG_NAME: if ('"' == ch) { state = PARSER_FIRST_SMILE; smileName = content.substring(beginPos, i).trim(); beginPos = i + 1; } break; case PARSER_FIRST_SMILE: switch (ch) { case ',': word = content.substring(beginPos, i).trim(); if (word.length() != 0) { state = PARSER_SMILE; selEmotions.addElement(new Object[] {curIndex, word, smileName}); textCorr.addElement(new Object[] {word, curIndex}); if (smileName.length() == 0) { smileName = word; } } beginPos = i + 1; break; case '\n': state = PARSER_NONE; word = content.substring(beginPos, i).trim(); if (word.length() != 0) { selEmotions.addElement(new Object[] {curIndex, word, smileName}); textCorr.addElement(new Object[] {word, curIndex}); if (smileName.length() == 0) { smileName = word; } } curIndex = new Integer(curIndex.intValue() + 1); break; } break; case PARSER_SMILE: switch (ch) { case ',': word = content.substring(beginPos, i).trim(); if ((0 < word.length()) && (word.length() < 30)) { textCorr.addElement(new Object[] {word, curIndex}); } beginPos = i + 1; break; case '\n': state = PARSER_NONE; word = content.substring(beginPos, i).trim(); if ((0 < word.length()) && (word.length() < 30)) { textCorr.addElement(new Object[] {word, curIndex}); } curIndex = new Integer(curIndex.intValue() + 1); break; } break; } } } public void load() { boolean loaded = false; try { loaded = loadAll(); } catch (Exception ignored) { } if (!loaded) { selEmotionsIndexes = null; selEmotionsWord = null; selEmotionsSmileNames = null; images = null; } } private ImageList loadIcons(int iconsSize) throws IOException { // #sijapp cond.if modules_ANISMILES is "true" # ImageList aniEmoImages = new AniImageList(); aniEmoImages.load("/smiles", iconsSize, iconsSize); if (0 < aniEmoImages.size()) { return aniEmoImages; } // #sijapp cond.end # ImageList emoImages = new ImageList(); emoImages.load("/smiles.png", iconsSize, iconsSize); return emoImages; } private boolean loadAll() { images = null; Vector<Object[]> textCorr = new Vector<Object[]>(); Vector<Object[]> selEmotions = new Vector<Object[]>(); // #sijapp cond.if modules_DEBUGLOG is "true"# jimm.Jimm.gc(); long mem = Runtime.getRuntime().freeMemory(); // #sijapp cond.end# // Load file "smiles.txt" InputStream stream = null; // #sijapp cond.if modules_ANISMILES is "true" # stream = jimm.Jimm.getResourceAsStream("/smiles/smiles.txt"); // #sijapp cond.end # if (null == stream) { stream = jimm.Jimm.getResourceAsStream("/smiles.txt"); } if (null == stream) { return false; } ImageList emoImages = null; try { DataInputStream dos = new DataInputStream(stream); // Read icon size int iconsSize = readIntFromStream(dos); emoImages = loadIcons(iconsSize); byte[] str = new byte[dos.available()]; TcpSocket.readFully(dos, str, 0, str.length); String content = StringUtils.utf8beByteArrayToString(str, 0, str.length); smileParser(content, textCorr, selEmotions); TcpSocket.close(dos); } catch (Exception ignored) { } TcpSocket.close(stream); if ((null == emoImages) || (0 == emoImages.size())) { return false; } // Write emotions data from vectors to arrays int size = selEmotions.size(); selEmotionsIndexes = new int[size]; selEmotionsWord = new String[size]; selEmotionsSmileNames = new String[size]; for (int i = 0; i < size; ++i) { Object[] data = (Object[])selEmotions.elementAt(i); selEmotionsIndexes[i] = ((Integer)data[0]).intValue(); selEmotionsWord[i] = (String)data[1]; selEmotionsSmileNames[i] = (String)data[2]; } size = textCorr.size(); textCorrWords = new String[size]; textCorrIndexes = new int[size]; StringBuilder firstChars = new StringBuilder(textCorr.size()); for (int i = 0; i < size; ++i) { Object[] data = (Object[])textCorr.elementAt(i); textCorrWords[i] = (String)data[0]; textCorrIndexes[i] = ((Integer)data[1]).intValue(); firstChars.append(textCorrWords[i].charAt(0)); } this.smileChars = firstChars.toString(); // #sijapp cond.if modules_DEBUGLOG is "true"# DebugLog.println("Emotions used (full): "+(mem - Runtime.getRuntime().freeMemory())); selEmotions.removeAllElements(); selEmotions = null; textCorr.removeAllElements(); textCorr = null; jimm.Jimm.gc(); DebugLog.println("Emotions used: "+(mem - Runtime.getRuntime().freeMemory())); // #sijapp cond.end# jimm.Jimm.gc(); images = emoImages; return true; } public static boolean isSupported() { return (null != instance.images); } public final boolean isEnabled() { return (null != images); } private int readIntFromStream(DataInputStream stream) throws IOException { int value = 0; byte digit = stream.readByte(); while (digit >= '0' && digit <= '9') { value = 10 * value + (digit - '0'); digit = stream.readByte(); } while (digit != '\n') { digit = stream.readByte(); } return value; } public int getSmile(String text, int pos) { int smileIndex = smileChars.indexOf(text.charAt(pos)); while (-1 != smileIndex) { if (text.startsWith(textCorrWords[smileIndex], pos)) { return smileIndex; } smileIndex = smileChars.indexOf(text.charAt(pos), smileIndex + 1); } return -1; } public Icon getSmileIcon(int smileIndex) { return images.iconAt(textCorrIndexes[smileIndex]); } public String getSmileText(int smileIndex) { return textCorrWords[smileIndex]; } /////////////////////////////////// // // // UI for emotion selection // // // /////////////////////////////////// static private SmileSelector sl; static public void selectEmotion(ContentActionListener listener) { if (!isSupported()) { return; } if (null == sl) { sl = new SmileSelector(instance.images, instance.selEmotionsSmileNames, instance.selEmotionsWord); } ((SmilesContent)sl.getContent()).setSelectionListener(listener); sl.show(); } } // #sijapp cond.end#