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)
169 api_char_list = auth.account.Characters()
171 for character in api_char_list.characters:
172 if character.characterID == char_id:
178 def char_id2name(self, char_id):
180 Takes a character ID and returns the character name associated with
182 The EVE API accepts a comma-separated list of IDs, but for now we
183 will just handle a single ID.
186 chars = self.cached_api.eve.CharacterName(ids=char_id).characters
187 name = chars[0].characterName
189 self.gui.report_error(str(e))
190 traceback.print_exc()
195 def char_name2id(self, name):
197 Takes the name of an EVE character and returns the characterID.
199 The EVE api accepts a comma separated list of names, but for now
200 we will just handle single names/
203 chars = self.cached_api.eve.CharacterID(names=name).characters
204 char_id = chars[0].characterID
205 char_name = chars[0].name
207 self.gui.report_error(str(e))
208 traceback.print_exc()
213 def get_chars_from_acct(self, uid):
215 Returns a list of characters associated with the provided user ID.
217 auth = self.get_auth(uid)
222 api_char_list = auth.account.Characters()
223 char_list = [char.name for char in api_char_list.characters]
225 self.gui.report_error(str(e))
226 traceback.print_exc()
231 def get_characters(self):
233 Returns a list of (character_name, image_path, uid) tuples from all the
234 accounts that are registered to mEveMon.
236 If there is an authentication issue, then instead of adding a valid
237 pair to the list, it appends an 'error message'
242 err_img = "/usr/share/mevemon/imgs/error.jpg"
244 placeholder_chars = ("Please check your API settings.", err_img, "0")
246 acct_dict = self.get_accounts()
248 return [placeholder_chars]
250 for uid in acct_dict.keys():
251 char_names = self.get_chars_from_acct(uid)
254 ui_char_list.append(placeholder_chars)
256 # append each char we get to the list we'll return to the
258 for char_name in char_names:
259 ui_char_list.append((char_name, self.get_portrait(char_name, 64) , uid) )
263 def get_portrait(self, char_name, size):
265 Returns the file path of the retrieved portrait
267 char_id = self.char_name2id(char_name)
269 return fetchimg.portrait_filename(char_id, size)
271 def get_skill_tree(self):
273 Returns an object from eveapi containing skill tree info
276 tree = self.cached_api.eve.SkillTree()
278 self.gui.report_error(str(e))
279 traceback.print_exc()
284 def get_skill_in_training(self, uid, char_id):
286 Returns an object from eveapi containing information about the
287 current skill in training
290 skill = self.get_auth(uid).character(char_id).SkillInTraining()
292 self.gui.report_error(str(e))
293 traceback.print_exc()
298 def connection_cb(self, connection, event, mgc):
300 I'm not sure why we need this, but connection.connect() won't work
301 without it, even empty.
306 def connect_to_network(self):
308 This will connect to the default network if avaliable, or pop up the
309 connection dialog to select a connection.
310 Running this when we start the program ensures we are connected to a
313 connection = conic.Connection()
315 connection.connect("connection-event", self.connection_cb, 0xAA55)
316 assert(connection.request_connection(conic.CONNECT_FLAG_NONE))
319 def get_sp(self, uid, char_id):
321 Adds up the SP for all known skills, then calculates the SP gained
322 from an in-training skill.
326 sheet = self.get_char_sheet(uid, char_id)
327 for skill in sheet.skills:
328 actual_sp += skill.skillpoints
330 live_sp = actual_sp + self.get_training_sp(uid, char_id)
334 def get_spps(self, uid, char_id):
336 Calculate and returns the skill points per hour for the given character.
338 skill = self.get_skill_in_training(uid, char_id)
340 if not skill.skillInTraining:
343 total_sp = skill.trainingDestinationSP - skill.trainingStartSP
344 total_time = skill.trainingEndTime - skill.trainingStartTime
346 spps = float(total_sp) / total_time
348 return (spps, skill.trainingStartTime)
350 def get_training_sp(self, uid, char_id):
352 returns the additional SP that the in-training skill has acquired
354 spps_tuple = self.get_spps(uid, char_id)
358 spps, start_time = spps_tuple
359 eve_time = time.time() #evetime is utc, right?
360 time_diff = eve_time - start_time
362 return (spps * time_diff)
365 if __name__ == "__main__":