3 # mEveMon - A character monitor for EVE Online
4 # Copyright (c) 2010 Ryan and Danny Campbell, and the mEveMon Team
6 # mEveMon is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # mEveMon is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 from eveapi import eveapi
30 #conic is used for connection handling
32 #import socket for handling socket exceptions
35 # we will store our preferences in gconf
38 #ugly hack to check maemo version. any better way?
39 if hasattr(hildon, "StackableWindow"):
40 from ui.fremantle import gui
42 from ui.diablo import gui
46 The controller class for mEvemon. The intent is to help
47 abstract the EVE API and settings code from the UI code.
51 about_name = 'mEveMon'
52 about_text = ('Mobile character monitor for EVE Online')
53 about_authors = ['Ryan Campbell <campbellr@gmail.com>',
54 'Danny Campbell <danny.campbell@gmail.com>']
56 about_website = 'http://mevemon.garage.maemo.org'
60 GCONF_DIR = "/apps/maemo/mevemon"
63 self.program = hildon.Program()
64 self.program.__init__()
65 self.gconf = gnome.gconf.client_get_default()
66 #NOTE: remove this after a few releases
67 self.update_settings()
68 self.connect_to_network()
69 self.cached_api = eveapi.EVEAPIConnection( cacheHandler = \
70 apicache.cache_handler(debug=False))
71 self.gui = gui.mEveMonUI(self)
77 def quit(self, *args):
80 def update_settings(self):
82 Update from the old pre 0.3 settings to the new settings layout.
83 We should remove this eventually, once no one is using pre-0.3 mEveMon
85 uid = self.gconf.get_string("%s/eve_uid" % self.GCONF_DIR)
88 key = self.gconf.get_string("%s/eve_api_key" % self.GCONF_DIR)
89 self.add_account(uid, key)
90 self.gconf.unset("%s/eve_uid" % self.GCONF_DIR)
91 self.gconf.unset("%s/eve_api_key" % self.GCONF_DIR)
94 def get_accounts(self):
96 Returns a dictionary containing uid:api_key pairs gathered from gconf
99 entries = self.gconf.all_entries("%s/accounts" % self.GCONF_DIR)
101 for entry in entries:
102 key = os.path.basename(entry.get_key())
103 value = entry.get_value().to_string()
104 accounts[key] = value
108 def get_api_key(self, uid):
110 Returns the api key associated with the given uid.
112 return self.gconf.get_string("%s/accounts/%s" % (self.GCONF_DIR, uid)) or ''
114 def remove_account(self, uid):
116 Removes the provided uid key from gconf
118 self.gconf.unset("%s/accounts/%s" % (self.GCONF_DIR, uid))
120 def add_account(self, uid, api_key):
122 Adds the provided uid:api_key pair to gconf.
124 self.gconf.set_string("%s/accounts/%s" % (self.GCONF_DIR, uid), api_key)
126 def get_auth(self, uid):
128 Returns an authentication object to be used for eveapi calls
129 that require authentication.
131 api_key = self.get_api_key(uid)
134 auth = self.cached_api.auth(userID=uid, apiKey=api_key)
136 self.gui.report_error(str(e))
137 traceback.print_exc()
142 def get_char_sheet(self, uid, char_id):
144 Returns an object containing information about the character specified
145 by the provided character ID.
148 sheet = self.get_auth(uid).character(char_id).CharacterSheet()
150 self.gui.report_error(str(e))
151 # TODO: we should really have a logger that logs this error somewhere
152 traceback.print_exc()
157 def charid2uid(self, char_id):
159 Takes a character ID and returns the user ID of the account containing
162 Returns None if the character isn't found in any of the registered accounts.
165 acct_dict = self.get_accounts()
167 for uid, api_key in acct_dict.items():
168 auth = self.cached_api.auth(userID=uid, apiKey=api_key)
170 api_char_list = auth.account.Characters()
171 characters = api_char_list.characters
175 for character in characters:
176 if character.characterID == char_id:
182 def char_id2name(self, char_id):
184 Takes a character ID and returns the character name associated with
186 The EVE API accepts a comma-separated list of IDs, but for now we
187 will just handle a single ID.
190 chars = self.cached_api.eve.CharacterName(ids=char_id).characters
191 name = chars[0].characterName
193 self.gui.report_error(str(e))
194 traceback.print_exc()
199 def char_name2id(self, name):
201 Takes the name of an EVE character and returns the characterID.
203 The EVE api accepts a comma separated list of names, but for now
204 we will just handle single names/
207 chars = self.cached_api.eve.CharacterID(names=name).characters
208 char_id = chars[0].characterID
209 char_name = chars[0].name
211 self.gui.report_error(str(e))
212 traceback.print_exc()
217 def get_chars_from_acct(self, uid):
219 Returns a list of characters associated with the provided user ID.
221 auth = self.get_auth(uid)
226 api_char_list = auth.account.Characters()
227 char_list = [char.name for char in api_char_list.characters]
229 self.gui.report_error(str(e))
230 traceback.print_exc()
235 def get_characters(self):
237 Returns a list of (character_name, image_path, uid) tuples from all the
238 accounts that are registered to mEveMon.
240 If there is an authentication issue, then instead of adding a valid
241 pair to the list, it appends an 'error message'
246 err_img = "/usr/share/mevemon/imgs/error.jpg"
247 err_txt = "Problem fetching info for account"
249 placeholder_chars = (err_txt, err_img, None)
251 acct_dict = self.get_accounts()
253 return [placeholder_chars]
255 for uid in acct_dict.keys():
256 char_names = self.get_chars_from_acct(uid)
259 ui_char_list.append((err_txt + "\t(UID: %s)" % uid, err_img, None))
261 # append each char we get to the list we'll return to the
263 for char_name in char_names:
264 ui_char_list.append((char_name, self.get_portrait(char_name, 64) , uid) )
268 def get_portrait(self, char_name, size):
270 Returns the file path of the retrieved portrait
272 char_id = self.char_name2id(char_name)
274 return fetchimg.portrait_filename(char_id, size)
276 def get_skill_tree(self):
278 Returns an object from eveapi containing skill tree info
281 tree = self.cached_api.eve.SkillTree()
283 self.gui.report_error(str(e))
284 traceback.print_exc()
289 def get_skill_in_training(self, uid, char_id):
291 Returns an object from eveapi containing information about the
292 current skill in training
295 skill = self.get_auth(uid).character(char_id).SkillInTraining()
297 self.gui.report_error(str(e))
298 traceback.print_exc()
303 def connection_cb(self, connection, event, mgc):
305 I'm not sure why we need this, but connection.connect() won't work
306 without it, even empty.
311 def connect_to_network(self):
313 This will connect to the default network if avaliable, or pop up the
314 connection dialog to select a connection.
315 Running this when we start the program ensures we are connected to a
318 connection = conic.Connection()
320 connection.connect("connection-event", self.connection_cb, 0xAA55)
321 assert(connection.request_connection(conic.CONNECT_FLAG_NONE))
324 def get_sp(self, uid, char_id):
326 Adds up the SP for all known skills, then calculates the SP gained
327 from an in-training skill.
331 sheet = self.get_char_sheet(uid, char_id)
332 for skill in sheet.skills:
333 actual_sp += skill.skillpoints
335 live_sp = actual_sp + self.get_training_sp(uid, char_id)
339 def get_spps(self, uid, char_id):
341 Calculate and returns the skill points per hour for the given character.
343 skill = self.get_skill_in_training(uid, char_id)
345 if not skill.skillInTraining:
348 total_sp = skill.trainingDestinationSP - skill.trainingStartSP
349 total_time = skill.trainingEndTime - skill.trainingStartTime
351 spps = float(total_sp) / total_time
353 return (spps, skill.trainingStartTime)
355 def get_training_sp(self, uid, char_id):
357 returns the additional SP that the in-training skill has acquired
359 spps_tuple = self.get_spps(uid, char_id)
363 spps, start_time = spps_tuple
364 eve_time = time.time() #evetime is utc, right?
365 time_diff = eve_time - start_time
367 return (spps * time_diff)
370 if __name__ == "__main__":