# HG changeset patch # User Vladimir Vukicevic # Date 1198722676 28800 # Node ID 5029faa6f8dcf877c25c7290ddb7aba58c153769 # Parent 6cd2588ce0555efb9f975728ad0d3be99f3aeb95 added Market Order support; added start of EveDatabase diff -r 6cd2588ce0555efb9f975728ad0d3be99f3aeb95 -r 5029faa6f8dcf877c25c7290ddb7aba58c153769 build.xml --- a/build.xml Tue Dec 25 16:33:54 2007 -0800 +++ b/build.xml Wed Dec 26 18:31:16 2007 -0800 @@ -4,6 +4,7 @@ + @@ -11,7 +12,7 @@ - + diff -r 6cd2588ce0555efb9f975728ad0d3be99f3aeb95 -r 5029faa6f8dcf877c25c7290ddb7aba58c153769 src/org/mrrupert/eveberry/EveAPI.java --- a/src/org/mrrupert/eveberry/EveAPI.java Tue Dec 25 16:33:54 2007 -0800 +++ b/src/org/mrrupert/eveberry/EveAPI.java Wed Dec 26 18:31:16 2007 -0800 @@ -36,53 +36,76 @@ public class EveAPI { //static String kAPIPrefix = "http://api.eve-online.com"; - static String kAPIPrefix = "http://vlad.off.net/misc/eproxy.php"; + static String sAPIPrefix = "http://vlad.off.net/eve/eproxy.php"; + static String sURLSuffix = ";deviceside=true"; - static String kCharactersXMLURL = kAPIPrefix + "/account/Characters.xml.aspx"; - static String kSkillInTrainingXMLURL = kAPIPrefix + "/char/SkillInTraining.xml.aspx"; - static String kCharacterSheetXMLURL = kAPIPrefix + "/char/CharacterSheet.xml.aspx"; + static String kCharactersXMLURL = "/account/Characters.xml.aspx"; + static String kSkillInTrainingXMLURL = "/char/SkillInTraining.xml.aspx"; + static String kCharacterSheetXMLURL = "/char/CharacterSheet.xml.aspx"; + static String kMarketOrdersXMLURL = "/char/MarketOrders.xml.aspx"; static String kCharacterImageURL = "http://img.eve.is/serv.asp?s=64&c="; - static String kURLSuffix = ";deviceside=true"; + static String kDataServiceURL = "http://vlad.off.net/eve/eveDataService.php"; - public static EveCharacterList GetCharacters(String userid, String key) { + static void DoAPICall(String api, byte[] postBytes, DocHandler handler) + throws IOException, Exception + { + DoXMLPOSTCall(sAPIPrefix + api, postBytes, handler); + } + + static void DoXMLPOSTCall(String url, byte[] postBytes, DocHandler handler) + throws IOException, Exception + { HttpConnection http = null; OutputStream os = null; + EveBerry.debug("XMLPOSTCall: '" + url + "'"); + + http = (HttpConnection) Connector.open(url + sURLSuffix); + EveBerry.debug("AAA"); + http.setRequestMethod(HttpConnection.POST); + EveBerry.debug("AA"); + http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + http.setRequestProperty("Accept-Encoding", "gzip"); + + EveBerry.debug("A"); + if (postBytes != null) { + os = http.openOutputStream(); + os.write(postBytes); + } + EveBerry.debug("B"); + int rc = http.getResponseCode(); + if (rc != HttpConnection.HTTP_OK) { + throw new Exception("HTTP failure"); + } + EveBerry.debug("C"); + InputStream is; + String encoding = http.getHeaderField("Content-Encoding"); + if (encoding != null && encoding.indexOf("gzip") != -1) { + is = new GZIPInputStream(http.openInputStream()); + } else { + is = http.openInputStream(); + } + EveBerry.debug("D"); + QDParser sax = new QDParser(); + EveBerry.debug("before parse call"); + sax.parse(handler, new InputStreamReader(is)); + EveBerry.debug("after parse call"); + + http.close(); + } + + public static EveCharacterList GetCharacters(String userid, String key) { EveCharacterList retval = null; try { - http = (HttpConnection) Connector.open(kCharactersXMLURL + kURLSuffix); - http.setRequestMethod(HttpConnection.POST); - http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - http.setRequestProperty("Accept-Encoding", "gzip"); + retval = new EveCharacterList(); + DocHandler handler = new CharactersXMLHandler(retval); - EveBerry.debug("GetCharacters: '" + userid + "' key: '" + key + "'"); - - os = http.openOutputStream(); - os.write(("userID=" + userid + "&apiKey=" + key).getBytes()); - - int rc = http.getResponseCode(); - if (rc != HttpConnection.HTTP_OK) { - // er, what now? - return null; - } - - InputStream is; - if (http.getHeaderField("Content-Encoding").indexOf("gzip") != -1) { - is = new GZIPInputStream(http.openInputStream()); - } else { - is = http.openInputStream(); - } - - retval = new EveCharacterList(); - - QDParser sax = new QDParser(); - DocHandler handler = new CharactersXMLHandler(retval); - sax.parse(handler, new InputStreamReader(is)); - - http.close(); + DoAPICall(kCharactersXMLURL, + ("userID=" + userid + "&apiKey=" + key).getBytes(), + handler); } catch (Exception ex) { EveBerry.debug("Exception caught! " + ex); retval = null; @@ -92,40 +115,15 @@ } public static EveCharacterSheet GetCharacterSheet(String userid, String key, long charid) { - HttpConnection http = null; - OutputStream os = null; - EveCharacterSheet retval = null; try { - http = (HttpConnection) Connector.open(kCharacterSheetXMLURL + kURLSuffix); - http.setRequestMethod(HttpConnection.POST); - http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - http.setRequestProperty("Accept-Encoding", "gzip"); + retval = new EveCharacterSheet(); + DocHandler handler = new CharacterSheetXMLHandler(retval); - os = http.openOutputStream(); - os.write(("userID=" + userid + "&apiKey=" + key + "&characterID=" + charid).getBytes()); - - int rc = http.getResponseCode(); - if (rc != HttpConnection.HTTP_OK) { - // er, what now? - return null; - } - - InputStream is; - if (http.getHeaderField("Content-Encoding").indexOf("gzip") != -1) { - is = new GZIPInputStream(http.openInputStream()); - } else { - is = http.openInputStream(); - } - - retval = new EveCharacterSheet(); - - QDParser sax = new QDParser(); - DocHandler handler = new CharacterSheetXMLHandler(retval); - sax.parse(handler, new InputStreamReader(is)); - - http.close(); + DoAPICall(kCharacterSheetXMLURL, + ("userID=" + userid + "&apiKey=" + key + "&characterID=" + charid).getBytes(), + handler); } catch (Exception ex) { EveBerry.debug("Exception caught! " + ex); retval = null; @@ -135,42 +133,64 @@ } public static EveSkillInTraining GetSkillInTraining(String userid, String key, long charid) { - HttpConnection http = null; - OutputStream os = null; - EveSkillInTraining retval = null; try { - http = (HttpConnection) Connector.open(kSkillInTrainingXMLURL + kURLSuffix); - http.setRequestMethod(HttpConnection.POST); - http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - http.setRequestProperty("Accept-Encoding", "gzip"); + retval = new EveSkillInTraining(); + DocHandler handler = new SkillInTrainingXMLHandler(retval); - os = http.openOutputStream(); - os.write(("userID=" + userid + "&apiKey=" + key + "&characterID=" + charid).getBytes()); + DoAPICall(kSkillInTrainingXMLURL, + ("userID=" + userid + "&apiKey=" + key + "&characterID=" + charid).getBytes(), + handler); + } catch (Exception ex) { + EveBerry.debug("Exception caught! " + ex); + retval = null; + } - int rc = http.getResponseCode(); - if (rc != HttpConnection.HTTP_OK) { - // er, what now? - return null; + return retval; + } + + public static Vector GetCharacterMarketOrders(String userid, String key, long charid) { + Vector retval = null; + + try { + retval = new Vector(); + DocHandler handler = new MarketOrdersXMLHandler(retval); + + DoAPICall(kMarketOrdersXMLURL, + ("userID=" + userid + "&apiKey=" + key + "&characterID=" + charid).getBytes(), + handler); + } catch (Exception ex) { + EveBerry.debug("Exception caught! " + ex); + retval = null; + } + + return retval; + } + + public static Vector DataServiceIdLookup(String op, Vector ids) { + Vector retval = null; + + try { + retval = new Vector(); + DocHandler handler = new DataServiceIdLookupXMLHandler(retval); + + StringBuffer sb = new StringBuffer(); + sb.append("op="); + sb.append(op); + sb.append("&ids="); + for (int i = 0; i < ids.size(); i++) { + int id = ((Integer) ids.elementAt(i)).intValue(); + if (i != 0) + sb.append(","); + sb.append(id); } - InputStream is; - if (http.getHeaderField("Content-Encoding").indexOf("gzip") != -1) { - is = new GZIPInputStream(http.openInputStream()); - } else { - is = http.openInputStream(); - } - - retval = new EveSkillInTraining(); - - QDParser sax = new QDParser(); - DocHandler handler = new SkillInTrainingXMLHandler(retval); - sax.parse(handler, new InputStreamReader(is)); - - http.close(); + EveBerry.debug("before POST call"); + DoXMLPOSTCall(kDataServiceURL, sb.toString().getBytes(), handler); + EveBerry.debug("after POST call"); } catch (Exception ex) { - EveBerry.debug("Exception caught! " + ex); + EveBerry.debug("Exception caught! " + ex); retval = null; } @@ -182,7 +202,7 @@ try { long tstart = System.currentTimeMillis(); - HttpConnection http = (HttpConnection) Connector.open(kCharacterImageURL + charid + kURLSuffix); + HttpConnection http = (HttpConnection) Connector.open(kCharacterImageURL + charid + sURLSuffix); int len = (int) http.getLength(); ByteVector data = new ByteVector(len); @@ -529,6 +549,82 @@ } } + static class MarketOrdersXMLHandler extends GenericEveAPIHandler { + Vector mOrders; + + boolean mInResult; + boolean mInRowSet; + + public MarketOrdersXMLHandler(Vector v) { + mOrders = v; + mInResult = false; + mInRowSet = false; + } + + public void startElement(String tag, Hashtable attributes) + throws Exception + { + if (GenericStartElement(tag, attributes)) + return; + + if (!mInResult) { + if (tag.equalsIgnoreCase("result")) + mInResult = true; + return; + } + + if (!mInRowSet) { + if (tag.equalsIgnoreCase("rowset")) + mInRowSet = true; + return; + } + + if (tag.equalsIgnoreCase("row")) { + EveMarketOrder emo = new EveMarketOrder(); + emo.orderID = Long.parseLong((String) attributes.get("orderID")); + emo.charID = Long.parseLong((String) attributes.get("charID")); + emo.stationID = Integer.parseInt((String) attributes.get("stationID")); + emo.volEntered = Integer.parseInt((String) attributes.get("volEntered")); + emo.volRemaining = Integer.parseInt((String) attributes.get("volRemaining")); + emo.minVolume = Integer.parseInt((String) attributes.get("minVolume")); + emo.orderState = Integer.parseInt((String) attributes.get("orderState")); + emo.typeID = Integer.parseInt((String) attributes.get("typeID")); + emo.range = Integer.parseInt((String) attributes.get("range")); + emo.accountKey = Integer.parseInt((String) attributes.get("accountKey")); + emo.duration = Integer.parseInt((String) attributes.get("duration")); + emo.escrow = Double.parseDouble((String) attributes.get("escrow")); + emo.price = Double.parseDouble((String) attributes.get("price")); + emo.buyOrder = ((Integer.parseInt((String) attributes.get("bid"))) == 1); + emo.dateIssued = DateStringToSeconds((String) attributes.get("issued")); + + mOrders.addElement(emo); + } + } + + public void endElement(String tag) + throws Exception + { + if (GenericEndElement(tag)) + return; + + if (!mInResult) + return; + + if (tag.equalsIgnoreCase("result")) { + mInResult = false; + return; + } + + if (!mInRowSet) + return; + + if (tag.equalsIgnoreCase("rowset")) { + mInRowSet = false; + return; + } + } + } + static class SkillInTrainingXMLHandler extends GenericEveAPIHandler { EveSkillInTraining mSkill; @@ -538,7 +634,6 @@ public SkillInTrainingXMLHandler(EveSkillInTraining skill) { mSkill = skill; - mInResult = false; } @@ -604,4 +699,35 @@ } } } + + static class DataServiceIdLookupXMLHandler extends DefaultDocHandler { + Vector mVector; + boolean mInNameList; + + DataServiceIdLookupXMLHandler(Vector vec) { + mVector = vec; + mInNameList = false; + } + + public void startElement(String tag, Hashtable attributes) + throws Exception + { + if (tag.equalsIgnoreCase("typenames") || tag.equalsIgnoreCase("itemnames")) { + mInNameList = true; + return; + } + + if (mInNameList && tag.equalsIgnoreCase("name")) { + mVector.addElement(new Integer(Integer.parseInt((String) attributes.get("id")))); + mVector.addElement((String) attributes.get("value")); + } + } + + public void endElement(String tag) + throws Exception + { + if (tag.equalsIgnoreCase("typenames") || tag.equalsIgnoreCase("itemnames")) + mInNameList = false; + } + } } diff -r 6cd2588ce0555efb9f975728ad0d3be99f3aeb95 -r 5029faa6f8dcf877c25c7290ddb7aba58c153769 src/org/mrrupert/eveberry/EveBerry.java --- a/src/org/mrrupert/eveberry/EveBerry.java Tue Dec 25 16:33:54 2007 -0800 +++ b/src/org/mrrupert/eveberry/EveBerry.java Wed Dec 26 18:31:16 2007 -0800 @@ -156,26 +156,28 @@ EveCharacterManager.Manager().addListener(this); } - - //EveCharacterManager.Manager().addCharacter("test", "test", "Tester Alice", 0); - //EveCharacterManager.Manager().addCharacter("test", "test", "Tester Bob", 1); - //EveCharacterManager.Manager().addCharacter("test", "test", "Tester Frankindapinapolopoplogoposlotous Really Long Name", 2); } protected void makeMenu(Menu menu, int instance) { super.makeMenu(menu, instance); if (mCharacterList.getSelectedIndex() != -1) { - menu.add(new MenuItem("Update Character", 5, 5) { + menu.add(new MenuItem("Update Character", 0, 5) { public void run() { EveCharacterInfo eci = mCharacterList.charInfoAt(mCharacterList.getSelectedIndex()); EveBerryBackground.GetBackgroundRunnable().requestCharacterUpdate(eci); } }); - menu.addSeparator(); + menu.add(new MenuItem("View Market Orders", 1, 5) { + public void run() { + EveCharacterInfo eci = mCharacterList.charInfoAt(mCharacterList.getSelectedIndex()); + EveBerryMarketOrdersScreen screen = new EveBerryMarketOrdersScreen(eci); + EveBerry.sApp.pushScreen(screen); + } + }); - menu.add(new MenuItem("Remove Character", 20, 10) { + menu.add(new MenuItem("Remove Character", 2, 5) { public void run() { EveCharacterInfo eci = mCharacterList.charInfoAt(mCharacterList.getSelectedIndex()); EveCharacterManager.Manager().deleteCharacter(eci.ID); @@ -183,13 +185,14 @@ }); } - - menu.add(new MenuItem("Add Character", 10, 10) { + menu.add(new MenuItem("Add Character", 0, 10) { public void run() { EveEditCharacterScreen ecs = new EveEditCharacterScreen(); EveBerry.sApp.pushScreen(ecs); } }); + + menu.addSeparator(); } public boolean onClose() { diff -r 6cd2588ce0555efb9f975728ad0d3be99f3aeb95 -r 5029faa6f8dcf877c25c7290ddb7aba58c153769 src/org/mrrupert/eveberry/EveBerryBackground.java --- a/src/org/mrrupert/eveberry/EveBerryBackground.java Tue Dec 25 16:33:54 2007 -0800 +++ b/src/org/mrrupert/eveberry/EveBerryBackground.java Wed Dec 26 18:31:16 2007 -0800 @@ -49,6 +49,8 @@ class EveBerryBackground implements Runnable { static int ITEM_CHARACTER_UPDATE = 0; static int ITEM_CHARACTER_LIST_REQUEST = 1; + static int ITEM_CHARACTER_MARKET_ORDERS_REQUEST = 2; + static int ITEM_DATA_SERVICE_ID_NAME_LOOKUP = 3; static boolean sFinished = false; static EveBerryBackground sRunnable = null; @@ -142,6 +144,8 @@ if (wi.WorkType == ITEM_CHARACTER_UPDATE && wi.Item == eci) { + // note that this other listener won't be notified! + // XXX we should probably notify all listeners that are requesting a char update return; } } @@ -166,6 +170,59 @@ sRunnable.notify(); } + public synchronized void requestCharacterMarketOrders(EveCharacterInfo eci, + EveBerryBackgroundActionListener listener, + Object closure) + { + mWorkQueue.addElement(new WorkItem(ITEM_CHARACTER_MARKET_ORDERS_REQUEST, + eci, + listener, + closure)); + + // tell the thread to wake up + if (sRunnable != null) + sRunnable.notify(); + } + + public synchronized void requestDataServiceLookup(String op, + int id, + EveBerryBackgroundActionListener listener, + Object closure) + { + boolean alreadyHad = false; + + // check if we already have an item for this in the work queue + for (int i = 0; i < mWorkQueue.size(); i++) { + WorkItem wi = (WorkItem) mWorkQueue.elementAt(i); + if (wi.WorkType == ITEM_DATA_SERVICE_ID_NAME_LOOKUP) { + Vector obs = (Vector) wi.Item; + if (((String) obs.elementAt(0)) == op) { + Vector v = (Vector) obs.elementAt(1); + v.addElement(new Integer(id)); + alreadyHad = true; + break; + } + } + } + + // no? + if (!alreadyHad) { + Vector obs = new Vector(); + obs.addElement(op); + Vector v = new Vector(); + v.addElement(new Integer(id)); + obs.addElement(v); + + mWorkQueue.addElement(new WorkItem(ITEM_DATA_SERVICE_ID_NAME_LOOKUP, + obs, + listener, + closure)); + } + + if (sRunnable != null) + sRunnable.notify(); + } + public void run() { mRunning = true; @@ -203,7 +260,32 @@ wi.Listener.onActionComplete(ecl, wi.Closure); }}); } - } + } else if (wi.WorkType == ITEM_CHARACTER_MARKET_ORDERS_REQUEST) { + EveCharacterInfo eci = (EveCharacterInfo) wi.Item; + + final Vector orders = EveAPI.GetCharacterMarketOrders(eci.UserID, eci.UserKey, eci.ID); + + if (wi.Listener != null) { + EveBerry.sApp.invokeLater(new Runnable() { + public void run() { + wi.Listener.onActionComplete(orders, wi.Closure); + }}); + } + } else if (wi.WorkType == ITEM_DATA_SERVICE_ID_NAME_LOOKUP) { + Vector args = (Vector) wi.Item; + + String op = (String) args.elementAt(0); + Vector ids = (Vector) args.elementAt(1); + + final Vector result = EveAPI.DataServiceIdLookup(op, ids); + + if (wi.Listener != null) { + EveBerry.sApp.invokeLater(new Runnable() { + public void run() { + wi.Listener.onActionComplete(result, wi.Closure); + }}); + } + } } mWorkQueue.removeAllElements(); diff -r 6cd2588ce0555efb9f975728ad0d3be99f3aeb95 -r 5029faa6f8dcf877c25c7290ddb7aba58c153769 src/org/mrrupert/eveberry/EveBerryMarketOrdersScreen.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/mrrupert/eveberry/EveBerryMarketOrdersScreen.java Wed Dec 26 18:31:16 2007 -0800 @@ -0,0 +1,102 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is EveBerry. + * + * The Initial Developer of the Original Code is + * Vladimir Vukicevic + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +package org.mrrupert.eveberry; + +import net.rim.device.api.ui.*; +import net.rim.device.api.ui.component.*; +import net.rim.device.api.ui.container.*; +import net.rim.device.api.i18n.*; +import net.rim.device.api.system.*; +import net.rim.device.api.notification.*; +import net.rim.device.api.collection.util.*; + +import java.util.*; + +/** + * + * @author vladimir + */ +public class EveBerryMarketOrdersScreen extends MainScreen +{ + EveCharacterInfo mChar; + EveMarketOrderListField mSellOrderList; + EveMarketOrderListField mBuyOrderList; + + public EveBerryMarketOrdersScreen(EveCharacterInfo forCharacter) { + super(DEFAULT_MENU | DEFAULT_CLOSE); + mChar = forCharacter; + + setTitle(new LabelField(mChar.Name + "'s Market Orders", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH)); + + // stick a label here while we load + add(new LabelField("Loading...", LabelField.USE_ALL_WIDTH)); + + EveBerryBackgroundActionListener listener = new EveBerryBackgroundActionListener() { + public void onActionComplete(Object result, Object token) { + Vector orders = (Vector) result; + EveBerryMarketOrdersScreen screen = (EveBerryMarketOrdersScreen) token; + + screen.setOrders(orders); + } + }; + + EveBerryBackground.GetBackgroundRunnable().requestCharacterMarketOrders(mChar, listener, this); + } + + void setOrders(Vector orders) { + deleteAll(); + + if (orders == null || orders.size() == 0) { + add(new LabelField("No orders.", LabelField.USE_ALL_WIDTH)); + return; + } + + mBuyOrderList = new EveMarketOrderListField(); + mSellOrderList = new EveMarketOrderListField(); + + for (int i = 0; i < orders.size(); i++) { + EveMarketOrder order = (EveMarketOrder) orders.elementAt(i); + if (order.buyOrder) + mBuyOrderList.addOrder(order); + else + mSellOrderList.addOrder(order); + } + + Field f; + + f = new LabelField("Sell Orders", LabelField.USE_ALL_WIDTH); + f.setFont(f.getFont().derive(Font.BOLD)); + add(f); + add(mSellOrderList); + + add(new SeparatorField()); + + f = new LabelField("Buy Orders", LabelField.USE_ALL_WIDTH); + f.setFont(f.getFont().derive(Font.BOLD)); + add(f); + add(mBuyOrderList); + } +} + diff -r 6cd2588ce0555efb9f975728ad0d3be99f3aeb95 -r 5029faa6f8dcf877c25c7290ddb7aba58c153769 src/org/mrrupert/eveberry/EveCharacterListField.java --- a/src/org/mrrupert/eveberry/EveCharacterListField.java Tue Dec 25 16:33:54 2007 -0800 +++ b/src/org/mrrupert/eveberry/EveCharacterListField.java Wed Dec 26 18:31:16 2007 -0800 @@ -43,7 +43,7 @@ public EveCharacterInfo CharacterInfo; - Font mFont; + Font mFont, mBoldFont; int mCharNameWidth, mFontHeight; boolean mDidLayout; @@ -54,8 +54,9 @@ protected void layout(int width, int height) { mFont = getFont(); + mBoldFont = mFont.derive(Font.BOLD); mFontHeight = mFont.getHeight(); - mCharNameWidth = mFont.getAdvance(CharacterInfo.Name); + mCharNameWidth = mBoldFont.getAdvance(CharacterInfo.Name); setExtent(Math.min(width, getPreferredWidth()), Math.min(height, getPreferredHeight())); @@ -138,7 +139,9 @@ } // draw the character name + g.setFont(mBoldFont); g.drawText(CharacterInfo.Name, 0, 0, DrawStyle.ELLIPSIS, nameWidth); + g.setFont(mFont); // draw the time remaining if (timeLeftWidth != 0) @@ -199,7 +202,8 @@ if (numRows > 2) { g.translate(0, mFontHeight); - drawFinishTime(g); + if (CharacterInfo.SkillInTraining != null) + drawFinishTime(g); /* if (numRows > 3) @@ -219,19 +223,11 @@ } void drawFinishTime(Graphics g) { - Date d = new Date(CharacterInfo.SkillEndTime * 1000); - Calendar c = Calendar.getInstance(); - c.setTime(d); - - DateFormat df = DateFormat.getInstance(DateFormat.DATE_LONG | DateFormat.TIME_SHORT); - StringBuffer sb = new StringBuffer(); - df.format(c, sb, null); - - g.drawText(sb.toString(), 0, 0); + g.drawText(EveUtils.FormatTimestamp(CharacterInfo.SkillEndTime), 0, 0); } void drawBalance(Graphics g) { - String s = FormatDouble(CharacterInfo.Balance) + " ISK"; + String s = EveUtils.FormatDouble(CharacterInfo.Balance) + " ISK"; g.drawText(s, 0, 0); } @@ -239,9 +235,9 @@ String s; if (CharacterInfo.SkillInTraining != null) - s = FormatLong(CharacterInfo.SkillPoints + (CharacterInfo.getTrainingCurrentSP() - CharacterInfo.SkillStartSP)) + " SP"; + s = EveUtils.FormatLong(CharacterInfo.SkillPoints + (CharacterInfo.getTrainingCurrentSP() - CharacterInfo.SkillStartSP)) + " SP"; else - s = FormatLong(CharacterInfo.SkillPoints) + " SP"; + s = EveUtils.FormatLong(CharacterInfo.SkillPoints) + " SP"; g.drawText(s, 0, 0); } @@ -268,78 +264,6 @@ g.popContext(); } - static String FormatPad3(long lv, boolean pad) { - if (!pad || lv >= 100) - return Long.toString(lv); - if (lv >= 10) - return "0" + lv; - return "00" + lv; - } - - // this should be elsewhere - static String FormatLong(long lval) { - boolean zeroes = false; - - String sval = ""; - if (lval >= 1000000000000L) { - long left = lval % 1000000000000L; - sval += (lval / 1000000000000L) + ","; - lval = left; - zeroes = true; - } - - if (lval >= 1000000000) { - long left = lval % 1000000000; - sval += FormatPad3(lval / 1000000000L, zeroes) + ","; - lval = left; - zeroes = true; - } else if (zeroes) { - sval += "000,"; - } - - if (lval >= 1000000) { - long left = lval % 1000000; - sval += FormatPad3(lval / 1000000L, zeroes) + ","; - lval = left; - zeroes = true; - } else if (zeroes) { - sval += "000,"; - } - - if (lval >= 1000) { - long left = lval % 1000; - sval += FormatPad3(lval / 1000L, zeroes) + ","; - lval = left; - zeroes = true; - } else if (zeroes) { - sval += "000,"; - } - - if (lval > 0) { - sval += FormatPad3(lval, zeroes); - } else if (zeroes) { - sval += "000"; - } else { - sval += "0"; - } - - return sval; - } - - static String FormatDouble(double d) { - long lval = (long) d; - long frac = (long) ((double)((d - lval) * 100)); - - String sval = FormatLong(lval); - if (frac > 0) { - sval += "." + frac; - } else { - sval += ".00"; - } - - return sval; - } - } class EveCharacterListField extends ListField @@ -406,9 +330,9 @@ int index, int y, int width) { EveCharacterListField elf = (EveCharacterListField) listField; - EveCharacterField layout = elf.charFieldAt(index); + EveCharacterField field = elf.charFieldAt(index); - layout.drawRow(graphics, 0, y, width, elf.getRowHeight()); + field.drawRow(graphics, 0, y, width, elf.getRowHeight()); } public int getPreferredWidth(ListField listField) { diff -r 6cd2588ce0555efb9f975728ad0d3be99f3aeb95 -r 5029faa6f8dcf877c25c7290ddb7aba58c153769 src/org/mrrupert/eveberry/EveDatabase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/mrrupert/eveberry/EveDatabase.java Wed Dec 26 18:31:16 2007 -0800 @@ -0,0 +1,197 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is EveBerry. + * + * The Initial Developer of the Original Code is + * Vladimir Vukicevic + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +package org.mrrupert.eveberry; + +import net.rim.device.api.i18n.*; +import net.rim.device.api.system.*; +import net.rim.device.api.notification.*; +import net.rim.device.api.collection.util.*; +import net.rim.device.api.util.*; + +import java.util.*; + +interface EveDatabaseReplyListener { + static final int TYPENAME = 1; + static final int OBJECTNAME = 2; + + public void onResult(int lookupType, int id, String name); +} + +class ExpirableString implements Persistable { + public String value; + public long lastUsed; + + public ExpirableString(String v) { + value = v; + lastUsed = System.currentTimeMillis(); + } + + public void bump() { + lastUsed = System.currentTimeMillis(); + } +} + +public class EveDatabase + implements EveBerryBackgroundActionListener +{ + static EveDatabase sInstance; + + public static EveDatabase getInstance() { + if (sInstance == null) + sInstance = new EveDatabase(); + + return sInstance; + } + + IntHashtable mTypeHash; + IntHashtable mObjectHash; + + IntHashtable mTypeLookupListeners; + IntHashtable mObjectLookupListeners; + + public EveDatabase() { + mTypeHash = new IntHashtable(); + mObjectHash = new IntHashtable(); + + mTypeLookupListeners = new IntHashtable(); + mObjectLookupListeners = new IntHashtable(); + } + + + public String getTypeName(int typeID) { + ExpirableString es = (ExpirableString) mTypeHash.get(typeID); + if (es == null) + return null; + + return es.value; + } + + public String getObjectName(int objectID) { + ExpirableString es = (ExpirableString) mObjectHash.get(objectID); + if (es == null) + return null; + + return es.value; + } + + public void lookupTypeName(int typeID, EveDatabaseReplyListener listener) { + final int id = typeID; + if (mObjectHash.containsKey(typeID)) { + final String s = ((ExpirableString) mTypeHash.get(id)).value; + final EveDatabaseReplyListener l = listener; + + EveBerry.sApp.invokeLater(new Runnable() { + public void run() { + l.onResult(EveDatabaseReplyListener.TYPENAME, id, s); + }}); + return; + } + + Vector lv; + if (mTypeLookupListeners.containsKey(id)) { + lv = (Vector) mTypeLookupListeners.get(id); + } else { + lv = new Vector(); + mTypeLookupListeners.put(id, lv); + } + lv.addElement(listener); + + EveBerryBackground.GetBackgroundRunnable().requestDataServiceLookup("typeNameLookup", + id, + this, + "typeNameLookup"); + } + + public void lookupObjectName(int objectID, EveDatabaseReplyListener listener) { + final int id = objectID; + if (mObjectHash.containsKey(objectID)) { + final String s = ((ExpirableString) mObjectHash.get(id)).value; + final EveDatabaseReplyListener l = listener; + + EveBerry.sApp.invokeLater(new Runnable() { + public void run() { + l.onResult(EveDatabaseReplyListener.OBJECTNAME, id, s); + }}); + return; + } + + Vector lv; + if (mObjectLookupListeners.containsKey(id)) { + lv = (Vector) mObjectLookupListeners.get(id); + } else { + lv = new Vector(); + mObjectLookupListeners.put(id, lv); + } + lv.addElement(listener); + + EveBerryBackground.GetBackgroundRunnable().requestDataServiceLookup("itemNameLookup", + id, + this, + "itemNameLookup"); + } + + // the incoming results from the background thread + public void onActionComplete(Object result, Object token) { + if (result == null) { + EveBerry.debug("EveDatabase got a null result! Things will be wacky..."); + return; + } + + Vector v = (Vector) result; + IntHashtable hash; + IntHashtable listeners; + final int ltype; + + if (((String) token) == "typeNameLookup") { + hash = mTypeHash; + listeners = mTypeLookupListeners; + ltype = EveDatabaseReplyListener.TYPENAME; + } else { + hash = mObjectHash; + listeners = mObjectLookupListeners; + ltype = EveDatabaseReplyListener.OBJECTNAME; + } + + for (int i = 0; i < v.size(); i+= 2) { + final int id = ((Integer) v.elementAt(i)).intValue(); + final String name = (String) v.elementAt(i+1); + + hash.put(id, new ExpirableString(name)); + + if (listeners.containsKey(id)) { + // someone's waiting for this result + Vector lv = (Vector) listeners.remove(id); + for (int j = 0; j < lv.size(); j++) { + final EveDatabaseReplyListener listener = (EveDatabaseReplyListener) lv.elementAt(j); + + EveBerry.sApp.invokeLater(new Runnable() { + public void run() { + listener.onResult(ltype, id, name); + }}); + } + } + } + } +} diff -r 6cd2588ce0555efb9f975728ad0d3be99f3aeb95 -r 5029faa6f8dcf877c25c7290ddb7aba58c153769 src/org/mrrupert/eveberry/EveMarketOrder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/mrrupert/eveberry/EveMarketOrder.java Wed Dec 26 18:31:16 2007 -0800 @@ -0,0 +1,58 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is EveBerry. + * + * The Initial Developer of the Original Code is + * Vladimir Vukicevic + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +package org.mrrupert.eveberry; + +import net.rim.device.api.ui.*; +import net.rim.device.api.ui.component.*; +import net.rim.device.api.ui.container.*; +import net.rim.device.api.i18n.*; +import net.rim.device.api.system.*; +import net.rim.device.api.util.*; +import net.rim.device.api.collection.util.*; + +import java.util.*; + +class EveMarketOrder implements Persistable +{ + public long orderID; + public long charID; + public int stationID; + public int volEntered; + public int volRemaining; + public int minVolume; + public int orderState; + + public int typeID; + public int range; + public int accountKey; + public int duration; // in days, apparently + + public double escrow; + public double price; + + public boolean buyOrder; + + public long dateIssued; +} diff -r 6cd2588ce0555efb9f975728ad0d3be99f3aeb95 -r 5029faa6f8dcf877c25c7290ddb7aba58c153769 src/org/mrrupert/eveberry/EveMarketOrderListField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/mrrupert/eveberry/EveMarketOrderListField.java Wed Dec 26 18:31:16 2007 -0800 @@ -0,0 +1,267 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is EveBerry. + * + * The Initial Developer of the Original Code is + * Vladimir Vukicevic + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +package org.mrrupert.eveberry; + +import net.rim.device.api.ui.*; +import net.rim.device.api.ui.component.*; +import net.rim.device.api.ui.container.*; +import net.rim.device.api.i18n.*; +import net.rim.device.api.system.*; + +import net.rim.device.api.collection.util.*; + +import java.util.*; +import java.lang.*; + +// Large Armor Repairer II +// Jita V - Moon IX - Something Station Somewhere +// 12/99 - 1,152,874 ISK each +// Expires: Jun 12 2007, 15:45p + +class EveMarketOrderField + extends Field + implements EveDatabaseReplyListener +{ + public static int SHOW_LOCATION = 1; // show the location or not; + int mDisplayFlags = 0; + + public EveMarketOrder MarketOrder; + + Font mFont; + int mFontHeight; + boolean mDidLayout; + + boolean mDidRequestTypeName; + boolean mDidRequestStationName; + + static int NumLinesForFlags(int flags) { + int lines = 2; + if ((flags & SHOW_LOCATION) != 0) + lines++; + + return lines; + } + + public EveMarketOrderField(EveMarketOrder emo, int flags) { + MarketOrder = emo; + mDidLayout = false; + mDisplayFlags = flags; + + mDidRequestTypeName = false; + mDidRequestStationName = false; + } + + protected void layout(int width, int height) { + mFont = getFont(); + mFontHeight = mFont.getHeight(); + + setExtent(Math.min(width, getPreferredWidth()), + Math.min(height, getPreferredHeight())); + + mDidLayout = true; + } + + public int getPreferredWidth() { + // we want this thing to be as wide as possible + return 640; + } + + public int getPreferredHeight() { + int fheight = mFontHeight * NumLinesForFlags(mDisplayFlags); + + // 2 pixels for 1px of padding above and below the rendered area + return fheight + 2; + } + + protected void paint(Graphics g) { + int w = getWidth(); + int h = getHeight(); + StringBuffer sb; + String s; + + // bar to the side + if (MarketOrder.buyOrder) { + //g.setColor(Color.YELLOW); + g.setColor(0xaaaaaa); + } else { + //g.setColor(Color.GREEN); + g.setColor(0xaaaaaa); + } + g.fillRect(1, 1, 4, h - 2); + w -= 5; + + g.setColor(Color.BLACK); + + // row: item name + g.translate(6, 1); + + String itemName = EveDatabase.getInstance().getTypeName(MarketOrder.typeID); + if (itemName == null) { + if (!mDidRequestTypeName) { + EveDatabase.getInstance().lookupTypeName(MarketOrder.typeID, this); + mDidRequestTypeName = true; + } + itemName = "Looking up item name..."; + } + + g.setFont(mFont.derive(Font.BOLD)); + g.drawText(itemName, 0, 0, DrawStyle.ELLIPSIS, w-2); + g.setFont(mFont); + + // station name, if enabled + if ((mDisplayFlags & SHOW_LOCATION) != 0) { + g.translate(0, mFontHeight); + + String stationName = EveDatabase.getInstance().getObjectName(MarketOrder.stationID); + if (stationName == null) { + if (!mDidRequestStationName) { + EveDatabase.getInstance().lookupObjectName(MarketOrder.stationID, this); + mDidRequestStationName = true; + } + stationName = "Looking up station name..."; + } + + g.drawText(stationName, 0, 0, DrawStyle.ELLIPSIS, w-2); + } + + // row: 12/99 @ 1,152,372 ISK date issued on right side + g.translate(0, mFontHeight); + s = Long.toString(MarketOrder.volRemaining) + "/" + Long.toString(MarketOrder.volEntered) + " @ " + EveUtils.FormatDouble(MarketOrder.price) + " ISK"; + g.drawText(s, 0, 0); + g.drawText(EveUtils.FormatTimestamp(MarketOrder.dateIssued), w - 2, 0, DrawStyle.TOP | DrawStyle.LEFT); + } + + // Causes the fields within this row manager to be layed out then + // painted. + public void drawRow(Graphics g, int x, int y, int width, int height) + { + if (!mDidLayout) { + layout(width, height); + } + + // Place this row manager within its enclosing list. + setPosition(x, y); + + // Apply a translating/clipping transformation to the graphics + // context so that this row paints in the right area. + g.pushRegion(getExtent()); + paint(g); + g.popContext(); + } + + // Database reply listener + public void onResult(int lookupType, int id, String name) { + // this field may have been removed/whatever'd before we got a chance + // to get the result; make sure to not blow up! + Manager m = getManager(); + if (m == null) + EveBerry.debug("field's manager is null!"); + + // this is a bit of a hack; the market screen might not be topmost by the time + // a name query comes back. But, this isn't going to hurt anything. + EveBerry.sApp.getActiveScreen().invalidate(); + } +} + +class EveMarketOrderListField extends ListField +{ + Vector mRows; + int mFieldDisplayFlags; + + public EveMarketOrderListField() { + mFieldDisplayFlags = 0; + + mRows = new Vector(); + setRowHeight(getFont().getHeight()*EveMarketOrderField.NumLinesForFlags(mFieldDisplayFlags) + 2); + setSize(0); + setCallback(RENDERER); + + mFieldDisplayFlags = 0; + } + + public void setFieldDisplayFlags(int newFlags) { + + } + + public EveMarketOrder marketOrderAt(int index) { + return marketOrderFieldAt(index).MarketOrder; + } + + EveMarketOrderField marketOrderFieldAt(int index) { + return (EveMarketOrderField) mRows.elementAt(index); + } + + public void addOrder(EveMarketOrder emo) { + EveMarketOrderField field = new EveMarketOrderField(emo, 0); + + mRows.addElement(field); + setSize(mRows.size()); + } + + private static final ListFieldCallback RENDERER = new ListFieldCallback() + { + public void drawListRow(ListField listField, Graphics graphics, + int index, int y, int width) + { + EveMarketOrderListField list = (EveMarketOrderListField) listField; + EveMarketOrderField field = list.marketOrderFieldAt(index); + + field.drawRow(graphics, 0, y, width, list.getRowHeight()); + } + + public int getPreferredWidth(ListField listField) { + EveMarketOrderListField list = (EveMarketOrderListField) listField; + int w = 0; + + for (int i = 0; i < list.mRows.size(); i++) { + int pw = list.marketOrderFieldAt(i).getPreferredWidth(); + if (w < pw) + w = pw; + } + + return w; + } + + public Object get(ListField listField, int index) { + EveMarketOrderListField list = (EveMarketOrderListField) listField; + return list.marketOrderFieldAt(index).MarketOrder; + } + + // prefix searching is not supported + public int indexOfList(ListField listField, String prefix, int start) + { + EveMarketOrderListField list = (EveMarketOrderListField) listField; + + /* + for (int i = start; i < list.mRows.size(); i++) { + if (list.marketOrderFieldAt(i).MarketOrder.ItemNameName.startsWith(prefix)) + return i; + } + */ + + return -1; + } + }; +} diff -r 6cd2588ce0555efb9f975728ad0d3be99f3aeb95 -r 5029faa6f8dcf877c25c7290ddb7aba58c153769 src/org/mrrupert/eveberry/EveUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/mrrupert/eveberry/EveUtils.java Wed Dec 26 18:31:16 2007 -0800 @@ -0,0 +1,121 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is EveBerry. + * + * The Initial Developer of the Original Code is + * Vladimir Vukicevic + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +package org.mrrupert.eveberry; + +import net.rim.device.api.ui.*; +import net.rim.device.api.ui.component.*; +import net.rim.device.api.ui.container.*; +import net.rim.device.api.i18n.*; +import net.rim.device.api.system.*; + +import net.rim.device.api.collection.util.*; + +import java.util.*; +import java.lang.*; + +final class EveUtils +{ + public static String FormatLong(long lval) { + boolean zeroes = false; + + String sval = ""; + if (lval >= 1000000000000L) { + long left = lval % 1000000000000L; + sval += (lval / 1000000000000L) + ","; + lval = left; + zeroes = true; + } + + if (lval >= 1000000000) { + long left = lval % 1000000000; + sval += EveUtils.FormatLongPad3(lval / 1000000000L, zeroes) + ","; + lval = left; + zeroes = true; + } else if (zeroes) { + sval += "000,"; + } + + if (lval >= 1000000) { + long left = lval % 1000000; + sval += EveUtils.FormatLongPad3(lval / 1000000L, zeroes) + ","; + lval = left; + zeroes = true; + } else if (zeroes) { + sval += "000,"; + } + + if (lval >= 1000) { + long left = lval % 1000; + sval += EveUtils.FormatLongPad3(lval / 1000L, zeroes) + ","; + lval = left; + zeroes = true; + } else if (zeroes) { + sval += "000,"; + } + + if (lval > 0) { + sval += EveUtils.FormatLongPad3(lval, zeroes); + } else if (zeroes) { + sval += "000"; + } else { + sval += "0"; + } + + return sval; + } + + static String FormatLongPad3(long lv, boolean pad) { + if (!pad || lv >= 100) + return Long.toString(lv); + if (lv >= 10) + return "0" + lv; + return "00" + lv; + } + + public static String FormatDouble(double d) { + long lval = (long) d; + long frac = (long) ((double)((d - lval) * 100)); + + String sval = FormatLong(lval); + if (frac > 0) { + sval += "." + frac; + } else { + sval += ".00"; + } + + return sval; + } + + public static String FormatTimestamp(long t) { + Date d = new Date(t * 1000); + Calendar c = Calendar.getInstance(); + c.setTime(d); + + DateFormat df = DateFormat.getInstance(DateFormat.DATE_LONG | DateFormat.TIME_SHORT); + StringBuffer sb = new StringBuffer(); + df.format(c, sb, null); + return sb.toString(); + } +}