Example #1
0
	def run(self):
		cache = Cache()
		lastCall = 0
		wait = 300  # time between 2 requests in ms
		while True:
			try:
				# Block waiting for addChatEntry() to enqueue something
				chatEntry = self.queue.get()
				charname = chatEntry.message.user
				avatar = None
				if charname == "VINTEL":
					with open(resourcePath("vi/ui/res/logo_small.png"), "rb") as f:
						avatar = f.read()
				if not avatar:
					avatar = cache.getAvatar(charname)
				if not avatar:
					diffLastCall = time.time() - lastCall
					if diffLastCall < wait:
						time.sleep((wait - diffLastCall) / 1000.0)
					avatar = evegate.getAvatarForPlayer(charname)
					lastCall = time.time()
					if avatar:
						cache.putAvatar(charname, avatar)
				if avatar:
					self.emit(SIGNAL("avatar_update"), chatEntry, avatar)
			except Exception as e:
				print "An error in the AvatarFindThread : {0}".format(str(e))
Example #2
0
 def run(self):
     cache = Cache()
     lastCall = 0
     wait = 300  # time between 2 requests in ms
     while True:
         try:
             # Block waiting for addChatEntry() to enqueue something
             chatEntry = self.queue.get()
             if not self.active:
                 return
             charname = chatEntry.message.user
             logging.debug("AvatarFindThread getting avatar for %s" % charname)
             avatar = None
             if charname == "VINTEL":
                 with open(resourcePath("vi/ui/res/logo_small.png"), "rb") as f:
                     avatar = f.read()
             if not avatar:
                 avatar = cache.getAvatar(charname)
                 if avatar:
                     logging.debug("AvatarFindThread found cached avatar for %s" % charname)
             if not avatar:
                 diffLastCall = time.time() - lastCall
                 if diffLastCall < wait:
                     time.sleep((wait - diffLastCall) / 1000.0)
                 avatar = evegate.getAvatarForPlayer(charname)
                 lastCall = time.time()
                 if avatar:
                     cache.putAvatar(charname, avatar)
             if avatar:
                 logging.debug("AvatarFindThread emit avatar_update for %s" % charname)
                 self.emit(SIGNAL("avatar_update"), chatEntry, avatar)
         except Exception as e:
             logging.error("Error in AvatarFindThread : %s", e)
Example #3
0
def namesToIds(names):
    """ Uses the EVE API to convert a list of names to ids_to_names
        names: list of names
        returns a dict: key=name, value=id
    """
    if len(names) == 0:
        return {}
    data = {}
    apiCheckNames = set()
    cache = Cache()

    # do we have allready something in the cache?
    for name in names:
        cacheKey = "_".join(("id", "name", name))
        id = cache.getFromCache(cacheKey)
        if id:
            data[name] = id
        else:
            apiCheckNames.add(name)

    try:
        # not in cache? asking the EVE API
        if len(apiCheckNames) > 0:
            # writing the cache
            for name in apiCheckNames:
                data[name] = charnameToId(name)
                cacheKey = "_".join(("id", "name", name))
                cache.putIntoCache(cacheKey, data[name], 60 * 60 * 24 * 365)
    except Exception as e:
        logging.error("Exception during namesToIds: %s", e)
    return data
Example #4
0
def getCorpIdsForCharId(char_id, use_outdated=True):
    """Returns a list with the ids if the corporation history of a charId
    returns a list of only the corp ids
    """
    cache_key = "_".join(("corp_history_id_", str(char_id)))
    cache = Cache()
    corp_ids = cache.getFromCache(cache_key, use_outdated)
    if corp_ids is not None:
        corp_ids = eval(corp_ids)
    else:
        try:
            char_id = int(char_id)
            url = "https://esi.evetech.net/latest/characters/{id}/corporationhistory/?datasource=tranquility".format(
                id=char_id
            )
            response = requests.get(url)
            response.raise_for_status()
            corp_ids = response.json()
            cache.putIntoCache(cache_key, response.text, 86400)
        except requests.exceptions.RequestException as e:
            # We get a 400 when we pass non-pilot names for KOS check so fail silently for that one only
            if e.response.status_code != 400:
                logging.error("Exception during getCharInfoForCharId: %s", str(e))
    id_list = list()
    for elem in corp_ids:
        id_list.append(elem["corporation_id"])
    return id_list
Example #5
0
def charNameToId(name, use_outdated=False):
    """Uses the EVE API to convert a character name to their ID"""
    cache_key = "_".join(("name", "id", name))
    cache = Cache()
    cached_id = cache.getFromCache(cache_key, use_outdated)
    if cached_id:
        return cached_id
    else:
        url = "https://esi.evetech.net/latest/search/?categories=character&datasource=tranquility&language=en-us&search={iname}&strict=true"
        response = requests.get(url.format(iname=name))
        response.raise_for_status()
        content = response.json()
        if "character" in content.keys():
            for idFound in content["character"]:
                url = "https://esi.evetech.net/latest/characters/{id}/?datasource=tranquility".format(
                    id=idFound
                )
                response = requests.get(url.format(name))
                response.raise_for_status()
                details = response.json()
                if "name" in details.keys():
                    name_found = details["name"]
                    if name_found.lower() == name.lower():
                        cache.putIntoCache(cache_key, idFound, 60 * 60 * 24 * 365)
                        return idFound
    return None
Example #6
0
    def addChatEntry(self, chatEntry, clearCache=False):
        try:
            if clearCache:
                cache = Cache()
                cache.removeAvatar(chatEntry.message.user)

            # Enqeue the data to be picked up in run()
            self.queue.put(chatEntry)
        except Exception as e:
            logging.error("Error in AvatarFindThread: %s", e)
Example #7
0
	def addChatEntry(self, chatEntry, clearCache=False):
		try:
			if clearCache:
				cache = Cache()
				cache.removeAvatar(chatEntry.message.user)

			# Enqeue the data to be picked up in run()
			self.queue.put(chatEntry)
		except Exception as e:
			print "An error in the AvatarFindThread: ", str(e)
Example #8
0
 def __init__(self, parent):
     QtGui.QDialog.__init__(self, parent)
     uic.loadUi(resourcePath("vi/ui/RegionChooser.ui"), self)
     self.connect(self.cancelButton, SIGNAL("clicked()"), self.accept)
     self.connect(self.saveButton, SIGNAL("clicked()"), self.saveClicked)
     cache = Cache()
     regionName = cache.getFromCache("region_name")
     if not regionName:
         regionName = u"Providence"
     self.regionNameField.setPlainText(regionName)
Example #9
0
	def __init__(self, parent):
		QtGui.QDialog.__init__(self, parent)
		uic.loadUi(resourcePath("vi/ui/RegionChooser.ui"), self)
		self.connect(self.cancelButton, Qt.SIGNAL("clicked()"), self.accept)
		self.connect(self.saveButton, Qt.SIGNAL("clicked()"), self.saveClicked)
		cache = Cache()
		regionName = cache.getFromCache("region_name")
		if not regionName:
			regionName = u"Providence"
		self.regionNameField.setPlainText(regionName)
Example #10
0
    def addChatEntry(self, chatEntry, clearCache=False):
        try:
            if clearCache:
                cache = Cache()
                cache.removeAvatar(chatEntry.message.user)

            # Enqeue the data to be picked up in run()
            self.queue.put(chatEntry)
        except Exception as e:
            logging.error("Error in AvatarFindThread: %s", e)
Example #11
0
 def __init__(self, parent):
     QtWidgets.QDialog.__init__(self, parent)
     uic.loadUi(resource_stream(__name__, "RegionChooser.ui"), self)
     self.cancelButton.clicked.connect(self.accept)
     self.saveButton.clicked.connect(self.saveClicked)
     cache = Cache()
     regionName = cache.getFromCache("region_name")
     if not regionName:
         regionName = u"Providence"
     self.regionNameField.setPlainText(regionName)
Example #12
0
 def __init__(self, parent):
     QtWidgets.QDialog.__init__(self, parent)
     uic.loadUi(resource_stream(__name__, "ChatroomsChooser.ui"), self)
     self.defaultButton.clicked.connect(self.setDefaults)
     self.cancelButton.clicked.connect(self.accept)
     self.saveButton.clicked.connect(self.saveClicked)
     cache = Cache()
     roomnames = cache.getFromCache("room_names")
     if not roomnames:
         roomnames = u"TheCitadel,North Provi Intel,North Catch Intel,North Querious Intel"
     self.roomnamesField.setPlainText(roomnames)
Example #13
0
 def __init__(self):
     self.sounds = {}
     self.worker = QThread()
     # self.speach_engine = QTextToSpeech()
     cache = Cache()
     self.setSoundFile(
         "alarm", "178032__zimbot__redalert-klaxon-sttos-recreated.wav")
     vol = cache.getFromCache("soundsetting.volume")
     if vol:
         self.setSoundVolume(float(vol))
     self.loadSoundFiles()
Example #14
0
 def __init__(self, parent):
     QtGui.QDialog.__init__(self, parent)
     uic.loadUi(resourcePath("vi/ui/ChatroomsChooser.ui"), self)
     self.connect(self.defaultButton, SIGNAL("clicked()"), self.setDefaults)
     self.connect(self.cancelButton, SIGNAL("clicked()"), self.accept)
     self.connect(self.saveButton, SIGNAL("clicked()"), self.saveClicked)
     cache = Cache()
     roomnames = cache.getFromCache("room_names")
     if not roomnames:
         roomnames = u"TheCitadel,North Provi Intel,4THINTEL"
     self.roomnamesField.setPlainText(roomnames)
Example #15
0
	def __init__(self, parent):
		QtGui.QDialog.__init__(self, parent)
		uic.loadUi(resourcePath("vi/ui/ChatroomsChooser.ui"), self)
		self.connect(self.defaultButton, Qt.SIGNAL("clicked()"), self.setDefaults)
		self.connect(self.cancelButton, Qt.SIGNAL("clicked()"), self.accept)
		self.connect(self.saveButton, Qt.SIGNAL("clicked()"), self.saveClicked)
		cache = Cache()
		roomnames = cache.getFromCache("room_names")
		if not roomnames:
			roomnames = u"TheCitadel,North Provi Intel,North Catch Intel"
		self.roomnamesField.setPlainText(roomnames)
Example #16
0
 def __init__(self, parent):
     QDialog.__init__(self, parent)
     uic.loadUi(resource_path("vi/ui/ChatroomsChooser.ui"), self)
     self.default_button.clicked.connect(self.set_defaults)
     self.cancel_button.clicked.connect(self.accept)
     self.save_button.clicked.connect(self.save_clicked)
     cache = Cache()
     roomnames = cache.get_from_cache("roomnames")
     if not roomnames:
         roomnames = u"TheCitadel, North Provi Intel"
     self.roomnames_field.setPlainText(roomnames)
Example #17
0
 def __init__(self, parent):
     QDialog.__init__(self, parent)
     uic.loadUi(resource_path("vi/ui/RegionChooser.ui"), self)
     self.default_button.clicked.connect(self.set_defaults)
     self.cancel_button.clicked.connect(self.accept)
     self.save_button.clicked.connect(self.save_clicked)
     cache = Cache()
     regionname = cache.get_from_cache("regionname")
     if not regionname:
         regionname = u"Providence"
     self.regionname_field.setPlainText(regionname)
Example #18
0
def getAllRegions(use_outdated=False):
    """Uses the EVE API to get the list of all region ids"""
    cache = Cache()
    all_systems = cache.getFromCache("universe_regions", use_outdated)
    if all_systems is not None:
        return eval(all_systems)
    else:
        url = "https://esi.evetech.net/latest/universe/regions/?datasource=tranquility"
        response = requests.get(url)
        response.raise_for_status()
        content = response.json()
        cache.putIntoCache("universe_regions", str(content), 60 * 60 * 24 * 365)
        return content
Example #19
0
def getConstellationInformation(constellation_id: int, use_outdated=False):
    cache_key = "_".join(("universe", "constellations", str(constellation_id)))
    cache = Cache()
    cached_id = cache.getFromCache(cache_key, use_outdated)
    if cached_id:
        return eval(cached_id)
    else:
        req = "https://esi.evetech.net/latest/universe/constellations/{}/?datasource=tranquility&language=en".format(
            constellation_id
        )
        res_constellation = requests.get(req)
        res_constellation.raise_for_status()
        cache.putIntoCache(cache_key, res_constellation.text)
        return res_constellation.json()
Example #20
0
def getCampaigns(use_outdated=False):
    """builds a list of reinforced campaigns for IHUB  and TCU dicts cached 60s"""
    cache = Cache()
    cache_key = "campaigns"
    result = cache.getFromCache(cache_key, use_outdated)
    if result:
        campaigns_list = json.loads(result)
    else:
        req = "https://esi.evetech.net/latest/sovereignty/campaigns/?datasource=tranquility"
        result = requests.get(req)
        result.raise_for_status()
        cache.putIntoCache(cache_key, result.text, 60)  # 5 seconds from esi
        campaigns_list = result.json()
    return campaigns_list
Example #21
0
def getIncursions(use_outdated=False):
    """builds a list of incursion dicts cached 300s"""
    cache = Cache()
    cache_key = "incursions"
    result = cache.getFromCache(cache_key, use_outdated)
    if result:
        incursion_list = json.loads(result)
    else:
        req = "https://esi.evetech.net/latest/incursions/?datasource=tranquility"
        result = requests.get(req)
        result.raise_for_status()
        cache.putIntoCache(cache_key, result.text, 300)
        incursion_list = result.json()
    return incursion_list
Example #22
0
def getAlliances(alliance_id, use_outdated=True):
    """gets the alliance from allicance id"""
    cache_key = "_".join(("alliance", str(alliance_id)))
    cache = Cache()
    cached_id = cache.getFromCache(cache_key, use_outdated)
    if cached_id:
        return eval(cached_id)
    else:
        req = "https://esi.evetech.net/latest/alliances/{}/?datasource=tranquility".format(
            alliance_id
        )
        res_system = requests.get(req)
        res_system.raise_for_status()
        cache.putIntoCache(cache_key, res_system.text, 3600)
        return res_system.json()
Example #23
0
def getSolarSystemInformation(system_id, use_outdated=False):
    """gets the solar system info from system id"""
    cache_key = "_".join(("universe", "systems", str(system_id)))
    cache = Cache()
    cached_id = cache.getFromCache(cache_key, use_outdated)
    if cached_id:
        return eval(cached_id)
    else:
        req = "https://esi.evetech.net/latest/universe/systems/{}/?datasource=tranquility&language=en".format(
            system_id
        )
        res_system = requests.get(req)
        res_system.raise_for_status()
        cache.putIntoCache(cache_key, res_system.text)
        return res_system.json()
Example #24
0
def namesToIds(names, use_outdated=False):
    """Uses the EVE API to convert a list of names to ids_to_names
    names: list of names
    returns a dict: key=name, value=id
    """
    if len(names) == 0:
        return {}
    data = {}
    api_check_names = set()
    cache = Cache()
    # do we have already something in the cache?
    for name in names:
        cache_key = "_".join(("id", "name", name))
        id_from_cache = cache.getFromCache(cache_key, use_outdated)
        if id_from_cache:
            data[name] = id_from_cache
        else:
            api_check_names.add(name)

    try:
        # not in cache? asking the EVE API
        if len(api_check_names) > 0:
            list_of_name = ""
            for name in names:
                if list_of_name != "":
                    list_of_name = list_of_name + ","
                list_of_name = list_of_name + '"{}"'.format(name)
            url = "https://esi.evetech.net/latest/universe/ids/?datasource=tranquility"
            response = requests.post(url, data="[{}]".format(list_of_name))
            response.raise_for_status()
            content = response.json()
            if "characters" in content.keys():
                for char in content["characters"]:
                    data[char["name"]] = char["id"]
            if "systems" in content.keys():
                for system in content["systems"]:
                    data[system["name"]] = system["id"]
            if "regions" in content.keys():
                for region in content["regions"]:
                    data[region["name"]] = region["id"]

            # writing the cache
            for name in data:
                cache_key = "_".join(("id", "name", name))
                cache.putIntoCache(cache_key, data[name], 60 * 60 * 24 * 365)
    except Exception as e:
        logging.error("Exception during namesToIds: %s", e)
    return data
Example #25
0
def getPlayerSovereignty(
    use_outdated=False, fore_refresh=True, show_npc=True, callback=None
):
    seq = 0

    def update_callback(seq):
        if callable(callback):
            icons = ["▁", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃"]
            seq += 1
            if seq >= len(icons):
                seq = 0
            callback(f"updating alliance and system database {icons[seq]}")
        return seq

    cache_key = "player_sovereignty"
    cache = Cache()
    cached_result = cache.getFromCache(cache_key, use_outdated)
    if cached_result and not fore_refresh:
        return json.loads(cached_result)
    else:
        player_sov = dict()
        npc_sov = dict()
        list_of_all_alliances = list()
        list_of_all_factions = list()
        for sov in getSovereignty(use_outdated, fore_refresh):
            if len(sov) > 2:
                player_sov[str(sov["system_id"])] = sov
            elif show_npc and len(sov) > 1:
                list_of_all_factions.append(sov["faction_id"])
                npc_sov[str(sov["system_id"])] = sov
        for sov in player_sov.values():
            if "alliance_id" in sov.keys():
                alli_id = sov["alliance_id"]
                sov["ticker"] = getAlliances(alli_id)["ticker"]
            seq = update_callback(seq)

        if show_npc:
            npc_list = idsToNames(list_of_all_factions)
            for sov in npc_sov.values():
                if "faction_id" in sov.keys():
                    faction_id = sov["faction_id"]
                    sov["ticker"] = npc_list[faction_id]
                seq = update_callback(seq)

            player_sov.update(npc_sov)

        cache.putIntoCache(cache_key, json.dumps(player_sov), 3600)
        return player_sov
Example #26
0
 def saveClicked(self):
     text = six.text_type(self.regionNameField.toPlainText())
     text = dotlan.convertRegionName(text)
     self.regionNameField.setPlainText(text)
     correct = False
     try:
         url = dotlan.Map.DOTLAN_BASIC_URL.format(text)
         content = requests.get(url).text
         if u"not found" in content:
             correct = False
             # Fallback -> ships vintel with this map?
             try:
                 with open(resourcePath("vi/ui/res/mapdata/{0}.svg".format(text))) as _:
                     correct = True
             except Exception as e:
                 logging.error(e)
                 correct = False
             if not correct:
                 QMessageBox.warning(self, u"No such region!", u"I can't find a region called '{0}'".format(text))
         else:
             correct = True
     except Exception as e:
         QMessageBox.critical(self, u"Something went wrong!", u"Error while testing existing '{0}'".format(str(e)))
         logging.error(e)
         correct = False
     if correct:
         Cache().putIntoCache("region_name", text, 60 * 60 * 24 * 365)
         self.accept()
         self.emit(SIGNAL("new_region_chosen"))
Example #27
0
def getSovereignty(use_outdated=False, fore_refresh=False):
    """builds a list of reinforced campaigns for hubs and tcus dicts cached 60s
    https://esi.evetech.net/ui/?version=latest#/Sovereignty/get_sovereignty_map
    """
    cache = Cache()
    cache_key = "sovereignty"
    result = cache.getFromCache(cache_key, use_outdated)
    if result and not fore_refresh:
        campaigns_list = json.loads(result)
    else:
        req = "https://esi.evetech.net/latest/sovereignty/map/?datasource=tranquility"
        result = requests.get(req)
        result.raise_for_status()
        cache.putIntoCache(cache_key, result.text, 3600)
        campaigns_list = result.json()
    return campaigns_list
Example #28
0
    def run(self):
        cache = Cache()
        last_call = 0
        wait = 300  # time between 2 requests in ms
        while True:
            try:
                chatentry = self.q.get()
                charname = chatentry.message.user
                avatar = None

                logging.debug('loading avatar for {0}'.format(charname))

                if charname == "VINTEL":
                    logging.debug('fetching VINTEL avatar')
                    with open(resource_path("vi/ui/res/logo_small.png"), "rb") as f:
                        avatar = f.read()

                if not avatar:
                    logging.debug('getting avatar from cache')
                    avatar = cache.get_avatar(charname)

                if not avatar:
                    diff_last_call = time.time() - last_call
                    if diff_last_call < wait:
                        time.sleep((wait - diff_last_call) / 1000.0)

                    logging.debug('getting avatar from evegate')

                    avatar = evegate.get_avatar_for_player(charname)
                    last_call = time.time()

                    if avatar:
                        logging.debug('saving avatar from evegate to cache')
                        cache.put_avatar(charname, avatar)

                if avatar:
                    if isinstance(avatar, str):
                        self.avatar_update.emit(chatentry, eval(avatar))
                    elif isinstance(avatar, bytes):
                        self.avatar_update.emit(chatentry, avatar)
                    else:
                        logging.warning('unknown avatar object type {0}'.format(type(avatar)))

            except Exception as e:
                print("An error in the avatar-find-thread:", str(e))
Example #29
0
def idsToNames(ids, use_outdated=False):
    """Returns the names for ids
    ids = iterable list of ids
    returns a dict key = id, value = name
    """
    data = {}
    if len(ids) == 0:
        return data
    api_check_ids = set()
    cache = Cache()

    # something already in the cache?
    for checked_id in ids:
        cache_key = "_".join(("name", "id", str(checked_id)))
        name = cache.getFromCache(cache_key, use_outdated)
        if name:
            data[checked_id] = name
        else:
            api_check_ids.add(checked_id)
    if len(api_check_ids) == 0:
        return data

    try:
        list_of_ids = ""
        for checked_id in api_check_ids:
            if list_of_ids != "":
                list_of_ids = list_of_ids + ","
            list_of_ids = list_of_ids + str(checked_id)
        url = "https://esi.evetech.net/latest/universe/names/?datasource=tranquility"
        response = requests.post(url, data="[{}]".format(list_of_ids))
        response.raise_for_status()
        content = response.json()
        if len(content) > 0:
            for elem in content:
                data[elem["id"]] = elem["name"]
            # and writing into cache
            for checked_id in api_check_ids:
                cache_key = "_".join(("name", "id", str(checked_id)))
                if checked_id in data.keys():
                    cache.putIntoCache(
                        cache_key, data[int(checked_id)], 60 * 60 * 24 * 365
                    )
    except Exception as e:
        logging.error("Exception during idsToNames: %s", e)
    return data
Example #30
0
 def setSoundFile(self, mask, filename):
     if mask in self.SOUNDS.keys():
         if filename == "":
             filename = "178032__zimbot__redalert-klaxon-sttos-recreated.wav"
         self.SOUNDS[mask] = filename
         self.sounds[mask] = QSoundEffect()
         url = QUrl.fromLocalFile(self.SOUNDS[mask])
         self.sounds[mask].setSource(url)
         Cache().putIntoCache("soundsetting.{}".format(mask), filename)
         self.loadSoundFiles()
Example #31
0
 def save_clicked(self):
     text = str(self.regionname_field.toPlainText())
     text = dotlan.convert_regionname(text)
     self.regionname_field.setPlainText(text)
     correct = False
     try:
         url = dotlan.Map.DOTLAN_BASIC_URL.format(text)
         content = requests.get(url).text
         # request = urllib.request.urlopen(url)
         # content = request.read()
         if u"not found" in content:
             correct = False
             # Fallback -> ships vintel with this map?
             try:
                 with open(
                         resource_path("vi/ui/res/mapdata/{0}.svg".format(
                             text))) as _:
                     correct = True
             except Exception as e:
                 print(str(e))
                 correct = False
             if not correct:
                 QMessageBox.warning(
                     None, u"No such region!",
                     u"I can't find a region called '{0}'".format(text),
                     QMessageBox.Ok)
         else:
             correct = True
     except Exception as e:
         QMessageBox.critical(
             None, u"Something went wrong!",
             u"Error while testing existing '{0}'".format(str(e)),
             QMessageBox.Ok)
         correct = False
     if correct:
         c = Cache()
         c.put_into_cache("regionname", text, 60 * 60 * 24 * 365)
         QMessageBox.information(
             None, u"VINTEL needs restart",
             u"Region was changed, you need to restart VINTEL!",
             QMessageBox.Ok)
         self.accept()
Example #32
0
 def set_jumpbridges(self, url):
     if url is None:
         url = ""
     try:
         data = []
         if url != "":
             content = requests.get(url).text
             for line in content.split("\n"):
                 parts = line.strip().split()
                 if len(parts) == 3:
                     data.append(parts)
         else:
             data = drachenjaeger.get_jumpbridge_data(
                 self.dotlan.region.lower())
         self.dotlan.set_jumpbridges(data)
         c = Cache()
         c.put_into_cache("jumpbridge_url", url, 60 * 60 * 24 * 365 * 8)
     except Exception as e:
         QMessageBox.warning(None, "Loading jumpbridges failed!",
                             "Error: {0}".format(str(e)), QMessageBox.Ok)
Example #33
0
def getCharinfoForCharId(charId):
    cacheKey = u"_".join(("playerinfo_id_", six.text_type(charId)))
    cache = Cache()
    soup = cache.getFromCache(cacheKey)
    if soup is not None:
        soup = BeautifulSoup(soup, 'html.parser')
    else:
        try:
            charId = int(charId)
            url = "https://api.eveonline.com/eve/CharacterInfo.xml.aspx"
            content = requests.get(url, params={'characterID': charId}).text
            soup = BeautifulSoup(content, 'html.parser')
            cacheUntil = datetime.datetime.strptime(soup.select("cacheduntil")[0].text, "%Y-%m-%d %H:%M:%S")
            diff = cacheUntil - currentEveTime()
            cache.putIntoCache(cacheKey, str(soup), diff.seconds)
        except requests.exceptions.RequestException as e:
            # We get a 400 when we pass non-pilot names for KOS check so fail silently for that one only
            if (e.response.status_code != 400):
                logging.error("Exception during getCharinfoForCharId: %s", str(e))
    return soup
Example #34
0
 def run(self):
     cache = Cache()
     lastCall = 0
     wait = 300  # time between 2 requests in ms
     while True:
         try:
             # Block waiting for addChatEntry() to enqueue something
             chatEntry = self.queue.get()
             if not self.active:
                 return
             charname = chatEntry.message.user
             logging.debug("AvatarFindThread getting avatar for %s" %
                           charname)
             avatar = None
             if charname == "VINTEL":
                 with open(
                         resource_filename(__name__,
                                           "ui/res/logo_small.png"),
                         "rb") as f:
                     avatar = f.read()
             if not avatar:
                 avatar = cache.getAvatar(charname)
                 if avatar:
                     logging.debug(
                         "AvatarFindThread found cached avatar for %s" %
                         charname)
             if not avatar:
                 diffLastCall = time.time() - lastCall
                 if diffLastCall < wait:
                     time.sleep((wait - diffLastCall) / 1000.0)
                 avatar = evegate.getAvatarForPlayer(charname)
                 lastCall = time.time()
                 if avatar:
                     cache.putAvatar(charname, avatar)
             if avatar:
                 logging.debug(
                     "AvatarFindThread emit avatar_update for %s" %
                     charname)
                 self.avatar_update.emit(chatEntry, avatar)
         except Exception as e:
             logging.error("Error in AvatarFindThread : %s", e)
Example #35
0
def getCharinfoForCharId(charId):
	cacheKey = u"_".join(("playerinfo_id_", unicode(charId)))
	cache = Cache()
	soup = cache.getFromCache(cacheKey)
	if soup is not None:
		soup = BeautifulSoup(soup, 'html.parser')
	else:
		try:
			charId = int(charId)
			url = "https://api.eveonline.com/eve/CharacterInfo.xml.aspx"
			data = urllib.urlencode({"characterID": charId})
			content = urllib2.urlopen(url=url, data=data).read()
			soup = BeautifulSoup(content, 'html.parser')
			cacheUntil = datetime.datetime.strptime(soup.select("cacheduntil")[0].text, "%Y-%m-%d %H:%M:%S")
			diff = cacheUntil - currentEveTime()
			cache.putIntoCache(cacheKey, str(soup), diff.seconds)
		except urllib2.HTTPError as e:
			# We get a 400 when we pass non-pilot names for KOS check so fail silently for that one only
			if (e.code != 400):
				print "Exception during getCharinfoForCharId: {0}".format(str(e))
	return soup
Example #36
0
def getJumpbridgeData(region):
    try:
        cacheKey = "jb_" + region
        cache = Cache()
        data = cache.getFromCache(cacheKey)

        if data:
            data = json.loads(data)
        else:
            data = []
            url = "https://s3.amazonaws.com/vintel-resources/{region}_jb.txt"
            resp = requests.get(url.format(region=region))
            for line in resp.iter_lines(decode_unicode=True):
                splits = line.strip().split()
                if len(splits) == 3:
                    data.append(splits)
            cache.putIntoCache(cacheKey, json.dumps(data), 60 * 60 * 12)
        return data
    except Exception as e:
        logging.error("Getting Jumpbridgedata failed with: %s", e)
        return []
Example #37
0
def getJumpbridgeData(region):
    try:
        cacheKey = "jb_" + region
        cache = Cache()
        data = cache.getFromCache(cacheKey)

        if data:
            data = json.loads(data)
        else:
            data = []
            url = "https://s3.amazonaws.com/vintel-resources/{region}_jb.txt"
            resp = requests.get(url.format(region=region))
            for line in resp.iter_lines(decode_unicode=True):
                splits = line.strip().split()
                if len(splits) == 3:
                    data.append(splits)
            cache.putIntoCache(cacheKey, json.dumps(data), 60 * 60 * 12)
        return data
    except Exception as e:
        logging.error("Getting Jumpbridgedata failed with: %s", e)
        return []
Example #38
0
def getCharinfoForCharId(charId):
    cacheKey = u"_".join(("playerinfo_id_", six.text_type(charId)))
    cache = Cache()
    soup = cache.getFromCache(cacheKey)
    if soup is not None:
        soup = BeautifulSoup(soup, 'html.parser')
    else:
        try:
            charId = int(charId)
            url = "https://api.eveonline.com/eve/CharacterInfo.xml.aspx"
            content = requests.get(url, params={'characterID': charId}).text
            soup = BeautifulSoup(content, 'html.parser')
            cacheUntil = datetime.datetime.strptime(
                soup.select("cacheduntil")[0].text, "%Y-%m-%d %H:%M:%S")
            diff = cacheUntil - currentEveTime()
            cache.putIntoCache(cacheKey, str(soup), diff.seconds)
        except requests.exceptions.RequestException as e:
            # We get a 400 when we pass non-pilot names for KOS check so fail silently for that one only
            if (e.response.status_code != 400):
                logging.error("Exception during getCharinfoForCharId: %s",
                              str(e))
    return soup
Example #39
0
def namesToIds(names):
    """ Uses the EVE API to convert a list of names to ids_to_names
        names: list of names
        returns a dict: key=name, value=id
    """
    if len(names) == 0:
        return {}
    data = {}
    apiCheckNames = set()
    cache = Cache()

    # do we have allready something in the cache?
    for name in names:
        cacheKey = "_".join(("id", "name", name))
        id = cache.getFromCache(cacheKey)
        if id:
            data[name] = id
        else:
            apiCheckNames.add(name)

    try:
        # not in cache? asking the EVE API
        if len(apiCheckNames) > 0:
            url = "https://api.eveonline.com/eve/CharacterID.xml.aspx"
            content = requests.get(url,
                                   params={
                                       'names': ','.join(apiCheckNames)
                                   }).text
            soup = BeautifulSoup(content, 'html.parser')
            rowSet = soup.select("rowset")[0]
            for row in rowSet.select("row"):
                data[row["name"]] = row["characterid"]
            # writing the cache
            for name in apiCheckNames:
                cacheKey = "_".join(("id", "name", name))
                cache.putIntoCache(cacheKey, data[name], 60 * 60 * 24 * 365)
    except Exception as e:
        logging.error("Exception during namesToIds: %s", e)
    return data
Example #40
0
def idsToNames(ids):
	""" Returns the names for ids
		ids = iterable list of ids
		returns a dict key = id, value = name
	"""
	data = {}
	if len(ids) == 0:
		return data
	apiCheckIds = set()
	cache = Cache()

	# something allready in the cache?
	for id in ids:
		cacheKey = u"_".join(("name", "id", unicode(id)))
		name = cache.getFromCache(cacheKey)
		if name:
			data[id] = name
		else:
			apiCheckIds.add(id)

	try:
		# call the EVE-Api for those entries we didn't have in the cache
		url = "https://api.eveonline.com/eve/CharacterName.xml.aspx"
		if len(apiCheckIds) > 0:
			requestData = urllib.urlencode({"ids": ",".join(apiCheckIds)})
			request = urllib2.urlopen(url=url, data=requestData)
			content = request.read()
			soup = BeautifulSoup(content, 'html.parser')
			rowSet = soup.select("rowset")[0]
			for row in rowSet.select("row"):
				data[row["characterid"]] = row["name"]
			# and writing into cache
			for id in apiCheckIds:
				cacheKey = u"_".join(("name", "id", unicode(id)))
				cache.putIntoCache(cacheKey, data[id], 60 * 60 * 24 * 365)
	except Exception as e:
		print "Exception during idsToNames: {0}".format(str(e))

	return data
Example #41
0
def getJumpbridgeData(region):
	try:
		cacheKey = "jb_" + region
		cache = Cache()
		data = cache.getFromCache(cacheKey)

		if data:
			data = json.loads(data)
		else:
			data = []
			url = "https://s3.amazonaws.com/vintel-resources/{region}_jb.txt"
			request = urllib2.urlopen(url.format(region=region))
			content = request.read()
			for line in content.split("\n"):
				splits = line.strip().split()
				if len(splits) == 3:
					data.append(splits)
			cache.putIntoCache(cacheKey, json.dumps(data), 60*60*24)
		return data
	except Exception as e:
		print("Getting Jumpbridgedata failed with: {0}".format(str(e)))
		return []
Example #42
0
def namesToIds(names):
	""" Uses the EVE API to convert a list of names to ids_to_names
		names: list of names
		returns a dict: key=name, value=id
	"""
	if len(names) == 0:
		return {}
	data = {}
	apiCheckNames = set()
	cache = Cache()

	# do we have allready something in the cache?
	for name in names:
		cacheKey = "_".join(("id", "name", name))
		id = cache.getFromCache(cacheKey)
		if id:
			data[name] = id
		else:
			apiCheckNames.add(name)

	try:
		# not in cache? asking the EVE API
		if len(apiCheckNames) > 0:
			url = "https://api.eveonline.com/eve/CharacterID.xml.aspx"
			requestData = urllib.urlencode({"names": u",".join(apiCheckNames)})
			request = urllib2.urlopen(url=url, data=requestData)
			content = request.read()
			soup = BeautifulSoup(content, 'html.parser')
			rowSet = soup.select("rowset")[0]
			for row in rowSet.select("row"):
				data[row["name"]] = row["characterid"]
			# writing the cache
			for name in apiCheckNames:
				cacheKey = "_".join(("id", "name", name))
				cache.putIntoCache(cacheKey, data[name], 60 * 60 * 24 * 365)
	except Exception as e:
		print "Exception during namesToIds: {0}".format(str(e))
	return data
Example #43
0
	def __init__(self, region, svgFile=None):
		self.region = region
		cache = Cache()
		self.outdatedCacheError = None

		if not svgFile:
			# want map from dotlan. Is it in the cache?
			svg = cache.getFromCache("map_" + self.region)
		else:
			svg = svgFile

		if not svg:
			try:
				svg = self._getSvgFromDotlan(self.region)
				cache.putIntoCache("map_" + self.region, svg, evegate.secondsTillDowntime() + 60*60)
			except Exception as e:
				self.outdatedCacheError = e
				svg = cache.getFromCache("map_" + self.region, True)
				if not svg:
					t = "No Map in cache, nothing from dotlan. Must give up "\
						"because this happened:\n{0} {1}\n\nThis could be a "\
						"temporary problem (like dotlan is not reachable), or "\
						"everythig went to hell. Sorry. This makes no sense "\
						"without the map.\n\nRemember the site for possible "\
						"updates: https://github.com/Xanthos-Eve/vintel"\
						.format(type(e), unicode(e))
					raise DotlanException(t)
		# and now creating soup from the svg
		self.soup = BeautifulSoup(svg, 'html.parser')
		self.systems = self._extractSystemsFromSoup(self.soup)
		self.systemsById = {}
		for system in self.systems.values():
			self.systemsById[system.systemId] = system
		self._prepareSvg(self.soup, self.systems)
		self._connectNeighbours()
		self._jumpMapsVisible = False
		self._statisticsVisible = False
		self.marker = self.soup.select("#select_marker")[0]
Example #44
0
def idsToNames(ids):
    """ Returns the names for ids
        ids = iterable list of ids
        returns a dict key = id, value = name
    """
    data = {}
    if len(ids) == 0:
        return data
    apiCheckIds = set()
    cache = Cache()

    # something allready in the cache?
    for id in ids:
        cacheKey = u"_".join(("name", "id", six.text_type(id)))
        name = cache.getFromCache(cacheKey)
        if name:
            data[id] = name
        else:
            apiCheckIds.add(six.text_type(id))

    try:
        # call the EVE-Api for those entries we didn't have in the cache
        url = "https://api.eveonline.com/eve/CharacterName.xml.aspx"
        if len(apiCheckIds) > 0:
            content = requests.get(url, params={'ids': ','.join(apiCheckIds)}).text
            soup = BeautifulSoup(content, 'html.parser')
            rowSet = soup.select("rowset")[0]
            for row in rowSet.select("row"):
                data[row["characterid"]] = row["name"]
            # and writing into cache
            for id in apiCheckIds:
                cacheKey = u"_".join(("name", "id", six.text_type(id)))
                cache.putIntoCache(cacheKey, data[id], 60 * 60 * 24 * 365)
    except Exception as e:
        logging.error("Exception during idsToNames: %s", e)

    return data
Example #45
0
    def __init__(self, args):
        super(Application, self).__init__(args)

        # Set up paths
        chatLogDirectory = ""
        if len(sys.argv) > 1:
            chatLogDirectory = sys.argv[1]

        if not os.path.exists(chatLogDirectory):
            if sys.platform.startswith("darwin"):
                chatLogDirectory = os.path.join(os.path.expanduser("~"), "Library", "Application Support", "Eve Online",
                                          "p_drive", "User", "My Documents", "EVE", "logs", "Chatlogs")
            elif sys.platform.startswith("linux"):
                chatLogDirectory = os.path.join(os.path.expanduser("~"), "EVE", "logs", "Chatlogs")
            elif sys.platform.startswith("win32") or sys.platform.startswith("cygwin"):
                import ctypes.wintypes
                buf = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH)
                ctypes.windll.shell32.SHGetFolderPathW(0, 5, 0, 0, buf)
                documentsPath = buf.value
                chatLogDirectory = os.path.join(documentsPath, "EVE", "logs", "Chatlogs")
        if not os.path.exists(chatLogDirectory):
            # None of the paths for logs exist, bailing out
            QMessageBox.critical(None, "No path to Logs", "No logs found at: " + chatLogDirectory, "Quit")
            sys.exit(1)

        # Setting local directory for cache and logging
        vintelDirectory = os.path.join(os.path.dirname(os.path.dirname(chatLogDirectory)), "vintel")
        if not os.path.exists(vintelDirectory):
            os.mkdir(vintelDirectory)
        cache.Cache.PATH_TO_CACHE = os.path.join(vintelDirectory, "cache-2.sqlite3")

        vintelLogDirectory = os.path.join(vintelDirectory, "logs")
        if not os.path.exists(vintelLogDirectory):
            os.mkdir(vintelLogDirectory)

        splash = QtGui.QSplashScreen(QtGui.QPixmap(resourcePath("vi/ui/res/logo.png")))

        vintelCache = Cache()
        logLevel = vintelCache.getFromCache("logging_level")
        if not logLevel:
            logLevel = logging.WARN
        backGroundColor = vintelCache.getFromCache("background_color")
        if backGroundColor:
            self.setStyleSheet("QWidget { background-color: %s; }" % backGroundColor)

        splash.show()
        self.processEvents()

        # Setup logging for console and rotated log files
        formatter = logging.Formatter('%(asctime)s| %(message)s', datefmt='%m/%d %I:%M:%S')
        rootLogger = logging.getLogger()
        rootLogger.setLevel(level=logLevel)

        logFilename = vintelLogDirectory + "/output.log"
        fileHandler = RotatingFileHandler(maxBytes=(1048576*5), backupCount=7, filename=logFilename, mode='a')
        fileHandler.setFormatter(formatter)
        rootLogger.addHandler(fileHandler)

        consoleHandler = StreamHandler()
        consoleHandler.setFormatter(formatter)
        rootLogger.addHandler(consoleHandler)

        logging.critical("")
        logging.critical("------------------- Vintel %s starting up -------------------", version.VERSION)
        logging.critical("")
        logging.debug("Looking for chat logs at: %s", chatLogDirectory)
        logging.debug("Cache maintained here: %s", cache.Cache.PATH_TO_CACHE)
        logging.debug("Writing logs to: %s", vintelLogDirectory)

        trayIcon = systemtray.TrayIcon(self)
        trayIcon.show()
        self.mainWindow = viui.MainWindow(chatLogDirectory, trayIcon, backGroundColor)
        self.mainWindow.show()
        self.mainWindow.raise_()
        splash.finish(self.mainWindow)
Example #46
0
File: viui.py Project: 3vi1/vintel
class MainWindow(QtGui.QMainWindow):


    def __init__(self, pathToLogs, trayIcon, backGroundColor):

        QtGui.QMainWindow.__init__(self)
        self.cache = Cache()

        if backGroundColor:
            self.setStyleSheet("QWidget { background-color: %s; }" % backGroundColor)
        uic.loadUi(resourcePath('vi/ui/MainWindow.ui'), self)
        self.setWindowTitle("Vintel " + vi.version.VERSION + "{dev}".format(dev="-SNAPSHOT" if vi.version.SNAPSHOT else ""))
        self.taskbarIconQuiescent = QtGui.QIcon(resourcePath("vi/ui/res/logo_small.png"))
        self.taskbarIconWorking = QtGui.QIcon(resourcePath("vi/ui/res/logo_small_green.png"))
        self.setWindowIcon(self.taskbarIconQuiescent)
        self.setFocusPolicy(QtCore.Qt.StrongFocus)

        self.pathToLogs = pathToLogs
        self.mapTimer = QtCore.QTimer(self)
        self.connect(self.mapTimer, QtCore.SIGNAL("timeout()"), self.updateMapView)
        self.clipboardTimer = QtCore.QTimer(self)
        self.oldClipboardContent = ""
        self.trayIcon = trayIcon
        self.trayIcon.activated.connect(self.systemTrayActivated)
        self.clipboard = QtGui.QApplication.clipboard()
        self.clipboard.clear(mode=self.clipboard.Clipboard)
        self.alarmDistance = 0
        self.lastStatisticsUpdate = 0
        self.chatEntries = []
        self.frameButton.setVisible(False)
        self.scanIntelForKosRequestsEnabled = True
        self.initialMapPosition = None
        self.mapPositionsDict = {}

        # Load user's toon names
        self.knownPlayerNames = self.cache.getFromCache("known_player_names")
        if self.knownPlayerNames:
            self.knownPlayerNames = set(self.knownPlayerNames.split(","))
        else:
            self.knownPlayerNames = set()
            diagText = "Vintel scans EVE system logs and remembers your characters as they change systems.\n\nSome features (clipboard KOS checking, alarms, etc.) may not work until your character(s) have been registered. Change systems, with each character you want to monitor, while Vintel is running to remedy this."
            QtGui.QMessageBox.warning(None, "Known Characters not Found", diagText, "Ok")

        # Set up user's intel rooms
        roomnames = self.cache.getFromCache("room_names")
        if roomnames:
            roomnames = roomnames.split(",")
        else:
            roomnames = (u"TheCitadel", u"North Provi Intel", u"North Catch Intel", "North Querious Intel")
            self.cache.putIntoCache("room_names", u",".join(roomnames), 60 * 60 * 24 * 365 * 5)
        self.roomnames = roomnames

        # Disable the sound UI if sound is not available
        if not SoundManager().soundAvailable:
            self.changeSound(disable=True)
        else:
            self.changeSound()

        # Set up Transparency menu - fill in opacity values and make connections
        self.opacityGroup = QtGui.QActionGroup(self.menu)
        for i in (100, 80, 60, 40, 20):
            action = QtGui.QAction("Opacity {0}%".format(i), None, checkable=True)
            if i == 100:
                action.setChecked(True)
            action.opacity = i / 100.0
            self.connect(action, QtCore.SIGNAL("triggered()"), self.changeOpacity)
            self.opacityGroup.addAction(action)
            self.menuTransparency.addAction(action)

        #
        # Platform specific UI resizing - we size items in the resource files to look correct on the mac,
        # then resize other platforms as needed
        #
        if sys.platform.startswith("win32") or sys.platform.startswith("cygwin"):
            font = self.statisticsButton.font()
            font.setPointSize(8)
            self.statisticsButton.setFont(font)
            self.jumpbridgesButton.setFont(font)
        elif sys.platform.startswith("linux"):
            pass

        self.wireUpUIConnections()
        self.recallCachedSettings()
        self.setupThreads()
        self.setupMap(True)


    def paintEvent(self, event):
        opt = QStyleOption()
        opt.initFrom(self)
        painter = QPainter(self)
        self.style().drawPrimitive(QStyle.PE_Widget, opt,  painter, self)


    def recallCachedSettings(self):
        try:
            self.cache.recallAndApplySettings(self, "settings")
        except Exception as e:
            logging.error(e)
            # todo: add a button to delete the cache / DB
            self.trayIcon.showMessage("Settings error", "Something went wrong loading saved state:\n {0}".format(str(e)), 1)


    def wireUpUIConnections(self):
        # Wire up general UI connections
        self.connect(self.clipboard, Qt.SIGNAL("changed(QClipboard::Mode)"), self.clipboardChanged)
        self.connect(self.autoScanIntelAction, Qt.SIGNAL("triggered()"), self.changeAutoScanIntel)
        self.connect(self.kosClipboardActiveAction, Qt.SIGNAL("triggered()"), self.changeKosCheckClipboard)
        self.connect(self.zoomInButton, Qt.SIGNAL("clicked()"), self.zoomMapIn)
        self.connect(self.zoomOutButton, Qt.SIGNAL("clicked()"), self.zoomMapOut)
        self.connect(self.statisticsButton, Qt.SIGNAL("clicked()"), self.changeStatisticsVisibility)
        self.connect(self.jumpbridgesButton, Qt.SIGNAL("clicked()"), self.changeJumpbridgesVisibility)
        self.connect(self.chatLargeButton, Qt.SIGNAL("clicked()"), self.chatLarger)
        self.connect(self.chatSmallButton, Qt.SIGNAL("clicked()"), self.chatSmaller)
        self.connect(self.infoAction, Qt.SIGNAL("triggered()"), self.showInfo)
        self.connect(self.showChatAvatarsAction, Qt.SIGNAL("triggered()"), self.changeShowAvatars)
        self.connect(self.alwaysOnTopAction, Qt.SIGNAL("triggered()"), self.changeAlwaysOnTop)
        self.connect(self.chooseChatRoomsAction, Qt.SIGNAL("triggered()"), self.showChatroomChooser)
        self.connect(self.catchRegionAction, Qt.SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.catchRegionAction))
        self.connect(self.providenceRegionAction, Qt.SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.providenceRegionAction))
        self.connect(self.queriousRegionAction, Qt.SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.queriousRegionAction))
        self.connect(self.providenceCatchRegionAction, Qt.SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.providenceCatchRegionAction))
        self.connect(self.providenceCatchCompactRegionAction, Qt.SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.providenceCatchCompactRegionAction))
        self.connect(self.chooseRegionAction, Qt.SIGNAL("triggered()"), self.showRegionChooser)
        self.connect(self.showChatAction, Qt.SIGNAL("triggered()"), self.changeChatVisibility)
        self.connect(self.soundSetupAction, Qt.SIGNAL("triggered()"), self.showSoundSetup)
        self.connect(self.activateSoundAction, Qt.SIGNAL("triggered()"), self.changeSound)
        self.connect(self.useSpokenNotificationsAction, Qt.SIGNAL("triggered()"), self.changeUseSpokenNotifications)
        self.connect(self.trayIcon, Qt.SIGNAL("alarm_distance"), self.changeAlarmDistance)
        self.connect(self.framelessWindowAction, Qt.SIGNAL("triggered()"), self.changeFrameless)
        self.connect(self.trayIcon, Qt.SIGNAL("change_frameless"), self.changeFrameless)
        self.connect(self.frameButton, Qt.SIGNAL("clicked()"), self.changeFrameless)
        self.connect(self.quitAction, Qt.SIGNAL("triggered()"), self.close)
        self.connect(self.trayIcon, Qt.SIGNAL("quit"), self.close)
        self.connect(self.jumpbridgeDataAction, Qt.SIGNAL("triggered()"), self.showJumbridgeChooser)
        self.mapView.page().scrollRequested.connect(self.mapPositionChanged)


    def setupThreads(self):
        # Set up threads and their connections
        self.avatarFindThread = AvatarFindThread()
        self.connect(self.avatarFindThread, QtCore.SIGNAL("avatar_update"), self.updateAvatarOnChatEntry)
        self.avatarFindThread.start()

        self.kosRequestThread = KOSCheckerThread()
        self.connect(self.kosRequestThread, Qt.SIGNAL("kos_result"), self.showKosResult)
        self.kosRequestThread.start()

        self.filewatcherThread = filewatcher.FileWatcher(self.pathToLogs)
        self.connect(self.filewatcherThread, QtCore.SIGNAL("file_change"), self.logFileChanged)
        self.filewatcherThread.start()

        self.versionCheckThread = amazon_s3.NotifyNewVersionThread()
        self.versionCheckThread.connect(self.versionCheckThread, Qt.SIGNAL("newer_version"), self.notifyNewerVersion)
        self.versionCheckThread.start()

        self.statisticsThread = MapStatisticsThread()
        self.connect(self.statisticsThread, Qt.SIGNAL("statistic_data_update"), self.updateStatisticsOnMap)
        self.statisticsThread.start()
        # statisticsThread is blocked until first call of requestStatistics


    def setupMap(self, initialize=False):
        self.mapTimer.stop()
        self.filewatcherThread.paused = True

        logging.info("Finding map file")
        regionName = self.cache.getFromCache("region_name")
        if not regionName:
            regionName = "Providence"
        svg = None
        try:
            with open(resourcePath("vi/ui/res/mapdata/{0}.svg".format(regionName))) as svgFile:
                svg = svgFile.read()
        except Exception as e:
            pass

        try:
            self.dotlan = dotlan.Map(regionName, svg)
        except dotlan.DotlanException as e:
            logging.error(e)
            QtGui.QMessageBox.critical(None, "Error getting map", six.text_type(e), "Quit")
            sys.exit(1)

        if self.dotlan.outdatedCacheError:
            e = self.dotlan.outdatedCacheError
            diagText = "Something went wrong getting map data. Proceeding with older cached data. " \
                       "Check for a newer version and inform the maintainer.\n\nError: {0} {1}".format(type(e), six.text_type(e))
            logging.warn(diagText)
            QtGui.QMessageBox.warning(None, "Using map from cache", diagText, "Ok")


        # Load the jumpbridges
        logging.critical("Load jump bridges")
        self.setJumpbridges(self.cache.getFromCache("jumpbridge_url"))
        self.systems = self.dotlan.systems
        logging.critical("Creating chat parser")
        self.chatparser = chatparser.ChatParser(self.pathToLogs, self.roomnames, self.systems)

        # Menus - only once
        if initialize:
            logging.critical("Initializing contextual menus")

            # Add a contextual menu to the mapView
            def mapContextMenuEvent(event):
                #if QApplication.activeWindow() or QApplication.focusWidget():
                self.mapView.contextMenu.exec_(self.mapToGlobal(QPoint(event.x(), event.y())))
            self.mapView.contextMenuEvent = mapContextMenuEvent
            self.mapView.contextMenu = self.trayIcon.contextMenu()

            # Clicking links
            self.mapView.connect(self.mapView, Qt.SIGNAL("linkClicked(const QUrl&)"), self.mapLinkClicked)

            # Also set up our app menus
            if not regionName:
                self.providenceCatchRegionAction.setChecked(True)
            elif regionName.startswith("Providencecatch"):
                self.providenceCatchRegionAction.setChecked(True)
            elif regionName.startswith("Catch"):
                self.catchRegionAction.setChecked(True)
            elif regionName.startswith("Providence"):
                self.providenceRegionAction.setChecked(True)
            elif regionName.startswith("Querious"):
                self.queriousRegionAction.setChecked(True)
            else:
                self.chooseRegionAction.setChecked(True)
        self.jumpbridgesButton.setChecked(False)
        self.statisticsButton.setChecked(False)

        # Update the new map view, then clear old statistics from the map and request new
        logging.critical("Updating the map")
        self.updateMapView()
        self.setInitialMapPositionForRegion(regionName)
        self.mapTimer.start(MAP_UPDATE_INTERVAL_MSECS)
        # Allow the file watcher to run now that all else is set up
        self.filewatcherThread.paused = False
        logging.critical("Map setup complete")


    # def eventFilter(self, obj, event):
    #     if event.type() == QtCore.QEvent.WindowDeactivate:
    #         self.enableContextMenu(False)
    #         return True
    #     elif event.type() == QtCore.QEvent.WindowActivate:
    #         self.enableContextMenu(True)
    #         return True
    #     return False


    def startClipboardTimer(self):
        """
            Start a timer to check the keyboard for changes and kos check them,
            first initializing the content so we dont kos check from random content
        """
        self.oldClipboardContent = tuple(six.text_type(self.clipboard.text()))
        self.connect(self.clipboardTimer, QtCore.SIGNAL("timeout()"), self.clipboardChanged)
        self.clipboardTimer.start(CLIPBOARD_CHECK_INTERVAL_MSECS)


    def stopClipboardTimer(self):
        if self.clipboardTimer:
           self.disconnect(self.clipboardTimer, QtCore.SIGNAL("timeout()"), self.clipboardChanged)
           self.clipboardTimer.stop()


    def closeEvent(self, event):
        """
            Persisting things to the cache before closing the window
        """
        # Known playernames
        if self.knownPlayerNames:
            value = ",".join(self.knownPlayerNames)
            self.cache.putIntoCache("known_player_names", value, 60 * 60 * 24 * 30)

        # Program state to cache (to read it on next startup)
        settings = ((None, "restoreGeometry", str(self.saveGeometry())), (None, "restoreState", str(self.saveState())),
                    ("splitter", "restoreGeometry", str(self.splitter.saveGeometry())),
                    ("splitter", "restoreState", str(self.splitter.saveState())),
                    ("mapView", "setZoomFactor", self.mapView.zoomFactor()),
                    (None, "changeChatFontSize", ChatEntryWidget.TEXT_SIZE),
                    (None, "changeOpacity", self.opacityGroup.checkedAction().opacity),
                    (None, "changeAlwaysOnTop", self.alwaysOnTopAction.isChecked()),
                    (None, "changeShowAvatars", self.showChatAvatarsAction.isChecked()),
                    (None, "changeAlarmDistance", self.alarmDistance),
                    (None, "changeSound", self.activateSoundAction.isChecked()),
                    (None, "changeChatVisibility", self.showChatAction.isChecked()),
                    (None, "loadInitialMapPositions", self.mapPositionsDict),
                    (None, "setSoundVolume", SoundManager().soundVolume),
                    (None, "changeFrameless", self.framelessWindowAction.isChecked()),
                    (None, "changeUseSpokenNotifications", self.useSpokenNotificationsAction.isChecked()),
                    (None, "changeKosCheckClipboard", self.kosClipboardActiveAction.isChecked()),
                    (None, "changeAutoScanIntel", self.scanIntelForKosRequestsEnabled))
        self.cache.putIntoCache("settings", str(settings), 60 * 60 * 24 * 30)

        # Stop the threads
        try:
            SoundManager().quit()
            self.avatarFindThread.quit()
            self.avatarFindThread.wait()
            self.filewatcherThread.quit()
            self.filewatcherThread.wait()
            self.kosRequestThread.quit()
            self.kosRequestThread.wait()
            self.versionCheckThread.quit()
            self.versionCheckThread.wait()
            self.statisticsThread.quit()
            self.statisticsThread.wait()
        except Exception:
            pass
        self.trayIcon.hide()
        event.accept()


    def notifyNewerVersion(self, newestVersion):
        self.trayIcon.showMessage("Newer Version", ("An update is available for Vintel.\nhttps://github.com/Xanthos-Eve/vintel"), 1)

    def changeChatVisibility(self, newValue=None):
        if newValue is None:
            newValue = self.showChatAction.isChecked()
        self.showChatAction.setChecked(newValue)
        self.chatbox.setVisible(newValue)

    def changeKosCheckClipboard(self, newValue=None):
        if newValue is None:
            newValue = self.kosClipboardActiveAction.isChecked()
        self.kosClipboardActiveAction.setChecked(newValue)
        if newValue:
            self.startClipboardTimer()
        else:
            self.stopClipboardTimer()

    def changeAutoScanIntel(self, newValue=None):
        if newValue is None:
            newValue = self.autoScanIntelAction.isChecked()
        self.autoScanIntelAction.setChecked(newValue)
        self.scanIntelForKosRequestsEnabled = newValue

    def changeUseSpokenNotifications(self, newValue=None):
        if SoundManager().platformSupportsSpeech():
            if newValue is None:
                newValue = self.useSpokenNotificationsAction.isChecked()
            self.useSpokenNotificationsAction.setChecked(newValue)
            SoundManager().setUseSpokenNotifications(newValue)
        else:
            self.useSpokenNotificationsAction.setChecked(False)
            self.useSpokenNotificationsAction.setEnabled(False)

    def changeOpacity(self, newValue=None):
        if newValue is not None:
            for action in self.opacityGroup.actions():
                if action.opacity == newValue:
                    action.setChecked(True)
        action = self.opacityGroup.checkedAction()
        self.setWindowOpacity(action.opacity)

    def changeSound(self, newValue=None, disable=False):
        if disable:
            self.activateSoundAction.setChecked(False)
            self.activateSoundAction.setEnabled(False)
            self.soundSetupAction.setEnabled(False)
            #self.soundButton.setEnabled(False)
            QtGui.QMessageBox.warning(None, "Sound disabled",
                                      "The lib 'pyglet' which is used to play sounds cannot be found, ""so the soundsystem is disabled.\nIf you want sound, please install the 'pyglet' library. This warning will not be shown again.",
                                      "OK")
        else:
            if newValue is None:
                newValue = self.activateSoundAction.isChecked()
            self.activateSoundAction.setChecked(newValue)
            SoundManager().soundActive = newValue

    def changeAlwaysOnTop(self, newValue=None):
        if newValue is None:
            newValue = self.alwaysOnTopAction.isChecked()
        self.hide()
        self.alwaysOnTopAction.setChecked(newValue)
        if newValue:
            self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
        else:
            self.setWindowFlags(self.windowFlags() & (~QtCore.Qt.WindowStaysOnTopHint))
        self.show()

    def changeFrameless(self, newValue=None):
        if newValue is None:
            newValue = not self.frameButton.isVisible()
        self.hide()
        if newValue:
            self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
            self.changeAlwaysOnTop(True)
        else:
            self.setWindowFlags(self.windowFlags() & (~QtCore.Qt.FramelessWindowHint))
        self.menubar.setVisible(not newValue)
        self.frameButton.setVisible(newValue)
        self.framelessWindowAction.setChecked(newValue)

        for cm in TrayContextMenu.instances:
            cm.framelessCheck.setChecked(newValue)
        self.show()

    def changeShowAvatars(self, newValue=None):
        if newValue is None:
            newValue = self.showChatAvatarsAction.isChecked()
        self.showChatAvatarsAction.setChecked(newValue)
        ChatEntryWidget.SHOW_AVATAR = newValue
        for entry in self.chatEntries:
            entry.avatarLabel.setVisible(newValue)

    def changeChatFontSize(self, newSize):
        if newSize:
            for entry in self.chatEntries:
                entry.changeFontSize(newSize)
            ChatEntryWidget.TEXT_SIZE = newSize


    def chatSmaller(self):
        newSize = ChatEntryWidget.TEXT_SIZE - 1
        self.changeChatFontSize(newSize)


    def chatLarger(self):
        newSize = ChatEntryWidget.TEXT_SIZE + 1
        self.changeChatFontSize(newSize)


    def changeAlarmDistance(self, distance):
        self.alarmDistance = distance
        for cm in TrayContextMenu.instances:
            for action in cm.distanceGroup.actions():
                if action.alarmDistance == distance:
                    action.setChecked(True)
        self.trayIcon.alarmDistance = distance


    def changeJumpbridgesVisibility(self):
        newValue = self.dotlan.changeJumpbridgesVisibility()
        self.jumpbridgesButton.setChecked(newValue)
        self.updateMapView()


    def changeStatisticsVisibility(self):
        newValue = self.dotlan.changeStatisticsVisibility()
        self.statisticsButton.setChecked(newValue)
        self.updateMapView()
        if newValue:
            self.statisticsThread.requestStatistics()


    def clipboardChanged(self, mode=0):
        if not (mode == 0 and self.kosClipboardActiveAction.isChecked() and self.clipboard.mimeData().hasText()):
            return
        content = six.text_type(self.clipboard.text())
        contentTuple = tuple(content)
        # Limit redundant kos checks
        if contentTuple != self.oldClipboardContent:
            parts = tuple(content.split("\n"))
            knownPlayers = self.knownPlayerNames
            for part in parts:
                # Make sure user is in the content (this is a check of the local system in Eve).
                # also, special case for when you have no knonwnPlayers (initial use)
                if not knownPlayers or part in knownPlayers:
                    self.trayIcon.setIcon(self.taskbarIconWorking)
                    self.kosRequestThread.addRequest(parts, "clipboard", True)
                    break
            self.oldClipboardContent = contentTuple


    def mapLinkClicked(self, url):
        systemName = six.text_type(url.path().split("/")[-1]).upper()
        system = self.systems[str(systemName)]
        sc = SystemChat(self, SystemChat.SYSTEM, system, self.chatEntries, self.knownPlayerNames)
        sc.connect(self, Qt.SIGNAL("chat_message_added"), sc.addChatEntry)
        sc.connect(self, Qt.SIGNAL("avatar_loaded"), sc.newAvatarAvailable)
        sc.connect(sc, Qt.SIGNAL("location_set"), self.setLocation)
        sc.show()


    def markSystemOnMap(self, systemname):
        self.systems[six.text_type(systemname)].mark()
        self.updateMapView()


    def setLocation(self, char, newSystem):
        for system in self.systems.values():
            system.removeLocatedCharacter(char)
        if not newSystem == "?" and newSystem in self.systems:
            self.systems[newSystem].addLocatedCharacter(char)
            self.setMapContent(self.dotlan.svg)


    def setMapContent(self, content):
        if self.initialMapPosition is None:
            scrollPosition = self.mapView.page().mainFrame().scrollPosition()
        else:
            scrollPosition = self.initialMapPosition
        self.mapView.setContent(content)
        self.mapView.page().mainFrame().setScrollPosition(scrollPosition)
        self.mapView.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)

        # Make sure we have positioned the window before we nil the initial position;
        # even though we set it, it may not take effect until the map is fully loaded
        scrollPosition = self.mapView.page().mainFrame().scrollPosition()
        if scrollPosition.x() or scrollPosition.y():
            self.initialMapPosition = None


    def loadInitialMapPositions(self, newDictionary):
        self.mapPositionsDict = newDictionary


    def setInitialMapPositionForRegion(self, regionName):
        try:
            if not regionName:
                regionName = self.cache.getFromCache("region_name")
            if regionName:
                xy = self.mapPositionsDict[regionName]
                self.initialMapPosition = QPoint(xy[0], xy[1])
        except Exception:
            pass


    def mapPositionChanged(self, dx, dy, rectToScroll):
        regionName = self.cache.getFromCache("region_name")
        if regionName:
            scrollPosition = self.mapView.page().mainFrame().scrollPosition()
            self.mapPositionsDict[regionName] = (scrollPosition.x(), scrollPosition.y())


    def showChatroomChooser(self):
        chooser = ChatroomsChooser(self)
        chooser.connect(chooser, Qt.SIGNAL("rooms_changed"), self.changedRoomnames)
        chooser.show()


    def showJumbridgeChooser(self):
        url = self.cache.getFromCache("jumpbridge_url")
        chooser = JumpbridgeChooser(self, url)
        chooser.connect(chooser, Qt.SIGNAL("set_jumpbridge_url"), self.setJumpbridges)
        chooser.show()


    def setSoundVolume(self, value):
        SoundManager().setSoundVolume(value)


    def setJumpbridges(self, url):
        if url is None:
            url = ""
        try:
            data = []
            if url != "":
                resp = requests.get(url)
                for line in resp.iter_lines(decode_unicode=True):
                    parts = line.strip().split()
                    if len(parts) == 3:
                        data.append(parts)
            else:
                data = amazon_s3.getJumpbridgeData(self.dotlan.region.lower())
            self.dotlan.setJumpbridges(data)
            self.cache.putIntoCache("jumpbridge_url", url, 60 * 60 * 24 * 365 * 8)
        except Exception as e:
            QtGui.QMessageBox.warning(None, "Loading jumpbridges failed!", "Error: {0}".format(six.text_type(e)), "OK")


    def handleRegionMenuItemSelected(self, menuAction=None):
        self.catchRegionAction.setChecked(False)
        self.providenceRegionAction.setChecked(False)
        self.queriousRegionAction.setChecked(False)
        self.providenceCatchRegionAction.setChecked(False)
        self.providenceCatchCompactRegionAction.setChecked(False)
        self.chooseRegionAction.setChecked(False)
        if menuAction:
            menuAction.setChecked(True)
            regionName = six.text_type(menuAction.property("regionName").toString())
            regionName = dotlan.convertRegionName(regionName)
            Cache().putIntoCache("region_name", regionName, 60 * 60 * 24 * 365)
            self.setupMap()


    def showRegionChooser(self):
        def handleRegionChosen():
            self.handleRegionMenuItemSelected(None)
            self.chooseRegionAction.setChecked(True)
            self.setupMap()

        self.chooseRegionAction.setChecked(False)
        chooser = RegionChooser(self)
        self.connect(chooser, Qt.SIGNAL("new_region_chosen"), handleRegionChosen)
        chooser.show()


    def addMessageToIntelChat(self, message):
        scrollToBottom = False
        if (self.chatListWidget.verticalScrollBar().value() == self.chatListWidget.verticalScrollBar().maximum()):
            scrollToBottom = True
        chatEntryWidget = ChatEntryWidget(message)
        listWidgetItem = QtGui.QListWidgetItem(self.chatListWidget)
        listWidgetItem.setSizeHint(chatEntryWidget.sizeHint())
        self.chatListWidget.addItem(listWidgetItem)
        self.chatListWidget.setItemWidget(listWidgetItem, chatEntryWidget)
        self.avatarFindThread.addChatEntry(chatEntryWidget)
        self.chatEntries.append(chatEntryWidget)
        self.connect(chatEntryWidget, Qt.SIGNAL("mark_system"), self.markSystemOnMap)
        self.emit(Qt.SIGNAL("chat_message_added"), chatEntryWidget)
        self.pruneMessages()
        if scrollToBottom:
            self.chatListWidget.scrollToBottom()


    def pruneMessages(self):
        try:
            now = time.mktime(evegate.currentEveTime().timetuple())
            for row in range(self.chatListWidget.count()):
                chatListWidgetItem = self.chatListWidget.item(0)
                chatEntryWidget = self.chatListWidget.itemWidget(chatListWidgetItem)
                message = chatEntryWidget.message
                if now - time.mktime(message.timestamp.timetuple()) > MESSAGE_EXPIRY_SECS:
                    self.chatEntries.remove(chatEntryWidget)
                    self.chatListWidget.takeItem(0)

                    for widgetInMessage in message.widgets:
                        widgetInMessage.removeItemWidget(chatListWidgetItem)
                else:
                    break
        except Exception as e:
            logging.error(e)


    def showKosResult(self, state, text, requestType, hasKos):
        if not self.scanIntelForKosRequestsEnabled:
            return
        try:
            if hasKos:
                SoundManager().playSound("kos", text)
            if state == "ok":
                if requestType == "xxx":  # An xxx request out of the chat
                    self.trayIcon.showMessage("Player KOS-Check", text, 1)
                elif requestType == "clipboard":  # request from clipboard-change
                    if len(text) <= 0:
                        text = "None KOS"
                    self.trayIcon.showMessage("Your KOS-Check", text, 1)
                text = text.replace("\n\n", "<br>")
                message = chatparser.chatparser.Message("Vintel KOS-Check", text, evegate.currentEveTime(), "VINTEL",
                                                        [], states.NOT_CHANGE, text.upper(), text)
                self.addMessageToIntelChat(message)
            elif state == "error":
                self.trayIcon.showMessage("KOS Failure", text, 3)
        except Exception:
            pass
        self.trayIcon.setIcon(self.taskbarIconQuiescent)


    def changedRoomnames(self, newRoomnames):
        self.cache.putIntoCache("room_names", u",".join(newRoomnames), 60 * 60 * 24 * 365 * 5)
        self.chatparser.rooms = newRoomnames


    def showInfo(self):
        infoDialog = QtGui.QDialog(self)
        uic.loadUi(resourcePath("vi/ui/Info.ui"), infoDialog)
        infoDialog.versionLabel.setText(u"Version: {0}".format(vi.version.VERSION))
        infoDialog.logoLabel.setPixmap(QtGui.QPixmap(resourcePath("vi/ui/res/logo.png")))
        infoDialog.connect(infoDialog.closeButton, Qt.SIGNAL("clicked()"), infoDialog.accept)
        infoDialog.show()


    def showSoundSetup(self):
        dialog = QtGui.QDialog(self)
        uic.loadUi(resourcePath("vi/ui/SoundSetup.ui"), dialog)
        dialog.volumeSlider.setValue(SoundManager().soundVolume)
        dialog.connect(dialog.volumeSlider, Qt.SIGNAL("valueChanged(int)"), SoundManager().setSoundVolume)
        dialog.connect(dialog.testSoundButton, Qt.SIGNAL("clicked()"), SoundManager().playSound)
        dialog.connect(dialog.closeButton, Qt.SIGNAL("clicked()"), dialog.accept)
        dialog.show()


    def systemTrayActivated(self, reason):
        if reason == QtGui.QSystemTrayIcon.Trigger:
            if self.isMinimized():
                self.showNormal()
                self.activateWindow()
            elif not self.isActiveWindow():
                self.activateWindow()
            else:
                self.showMinimized()


    def updateAvatarOnChatEntry(self, chatEntry, avatarData):
        updated = chatEntry.updateAvatar(avatarData)
        if not updated:
            self.avatarFindThread.addChatEntry(chatEntry, clearCache=True)
        else:
            self.emit(Qt.SIGNAL("avatar_loaded"), chatEntry.message.user, avatarData)


    def updateStatisticsOnMap(self, data):
        if not self.statisticsButton.isChecked():
            return
        if data["result"] == "ok":
            self.dotlan.addSystemStatistics(data["statistics"])
        elif data["result"] == "error":
            text = data["text"]
            self.trayIcon.showMessage("Loading statstics failed", text, 3)
            logging.error("updateStatisticsOnMap, error: %s" % text)


    def updateMapView(self):
        logging.debug("Updating map start")
        self.setMapContent(self.dotlan.svg)
        logging.debug("Updating map complete")


    def zoomMapIn(self):
        self.mapView.setZoomFactor(self.mapView.zoomFactor() + 0.1)


    def zoomMapOut(self):
        self.mapView.setZoomFactor(self.mapView.zoomFactor() - 0.1)


    def logFileChanged(self, path):
        messages = self.chatparser.fileModified(path)
        for message in messages:
            # If players location has changed
            if message.status == states.LOCATION:
                self.knownPlayerNames.add(message.user)
                self.setLocation(message.user, message.systems[0])
            elif message.status == states.KOS_STATUS_REQUEST:
                # Do not accept KOS requests from monitored intel channels
                # as we don't want to encourage the use of xxx in those channels.
                if not message.room in self.roomnames:
                    text = message.message[4:]
                    text = text.replace("  ", ",")
                    parts = (name.strip() for name in text.split(","))
                    self.trayIcon.setIcon(self.taskbarIconWorking)
                    self.kosRequestThread.addRequest(parts, "xxx", False)
            # Otherwise consider it a 'normal' chat message
            elif message.user not in ("EVE-System", "EVE System") and message.status != states.IGNORE:
                self.addMessageToIntelChat(message)
                # For each system that was mentioned in the message, check for alarm distance to the current system
                # and alarm if within alarm distance.
                if message.systems:
                    for system in message.systems:
                        systemname = system.name
                        self.dotlan.systems[systemname].setStatus(message.status)
                        if message.status in (states.REQUEST, states.ALARM) and message.user not in self.knownPlayerNames:
                            alarmDistance = self.alarmDistance if message.status == states.ALARM else 0
                            for nSystem, data in system.getNeighbours(alarmDistance).items():
                                distance = data["distance"]
                                chars = nSystem.getLocatedCharacters()
                                if len(chars) > 0 and message.user not in chars:
                                    self.trayIcon.showNotification(message, system.name, ", ".join(chars), distance)
                self.setMapContent(self.dotlan.svg)
Example #47
0
    # Setting local directory for cache and logging
    vintelDirectory = os.path.join(os.path.dirname(os.path.dirname(chatLogDirectory)), "vintel")
    if not os.path.exists(vintelDirectory):
        os.mkdir(vintelDirectory)
    cache.Cache.PATH_TO_CACHE = os.path.join(vintelDirectory, "cache-2.sqlite3")

    vintelLogDirectory = os.path.join(vintelDirectory, "logs")
    if not os.path.exists(vintelLogDirectory):
        os.mkdir(vintelLogDirectory)

    # Setup the application object, display splash screen
    app = QtGui.QApplication(sys.argv)
    splash = QtGui.QSplashScreen(QtGui.QPixmap(resourcePath("vi/ui/res/logo.png")))

    vintelCache = Cache()
    logLevel = vintelCache.getFromCache("logging_level")
    if not logLevel:
        logLevel = logging.WARN
    backGroundColor = vintelCache.getFromCache("background_color")
    if backGroundColor:
        app.setStyleSheet("QWidget { background-color: %s; }" % backGroundColor)

    splash.show()
    app.processEvents()

    # Setup logging for console and rotated log files
    formatter = logging.Formatter('%(asctime)s| %(message)s', datefmt='%m/%d %I:%M:%S')
    rootLogger = logging.getLogger()
    rootLogger.setLevel(level=logLevel)
Example #48
0
class MainWindow(QtGui.QMainWindow):

	def __init__(self, pathToLogs, trayIcon):

		QtGui.QMainWindow.__init__(self)
		uic.loadUi(resourcePath('vi/ui/MainWindow.ui'), self)
		self.setWindowTitle("Vintel " + VERSION)
		self.taskbarIconQuiescent = QtGui.QIcon(resourcePath("vi/ui/res/logo_small.png"))
		self.taskbarIconWorking = QtGui.QIcon(resourcePath("vi/ui/res/logo_small_green.png"))
		self.setWindowIcon(self.taskbarIconQuiescent)

		self.pathToLogs = pathToLogs
		self.trayIcon = trayIcon
		self.cache = Cache()

		# Load my toon names
		self.knownPlayerNames = self.cache.getFromCache("known_player_names")
		if self.knownPlayerNames:
			self.knownPlayerNames = set(self.knownPlayerNames.split(","))
		else:
			self.knownPlayerNames = set()

		# Set up my intel rooms
		roomnames = self.cache.getFromCache("room_names")
		if roomnames:
			roomnames = roomnames.split(",")
		else:
			roomnames = (u"TheCitadel", u"North Provi Intel", u"North Catch Intel")
			self.cache.putIntoCache("room_names", u",".join(roomnames), 60 * 60 * 24 * 365 * 5)
		self.roomnames = roomnames

		# Disable the sound UI if sound is not available
		if not SoundManager().soundAvailable:
			self.changeSound(disable=True)
		else:
			self.changeSound()

		# Initialize state
		self.initMapPosition = None
		self.oldClipboardContent = ""
		self.alarmDistance = 0
		self.lastStatisticsUpdate = 0
		self.alreadyShowedSoundWarning = False
		self.chatEntries = []
		self.frameButton.setVisible(False)
		self.trayIcon.activated.connect(self.systemTrayActivated)
		self.clipboard = QtGui.QApplication.clipboard()
		self.clipboard.clear(mode=self.clipboard.Clipboard)

		# Fill in opacity values and connections
		self.opacityGroup = QtGui.QActionGroup(self.menu)
		for i in (100, 80, 60, 40, 20):
			action = QtGui.QAction("Opacity {0}%".format(i), None, checkable=True)
			if i == 100:
				action.setChecked(True)
			action.opacity = i / 100.0
			self.connect(action, QtCore.SIGNAL("triggered()"), self.changeOpacity)
			self.opacityGroup.addAction(action)
			self.menuTransparency.addAction(action)

		# Wire up UI connections
		self.connect(self.clipboard, Qt.SIGNAL("changed(QClipboard::Mode)"), self.clipboardChanged)
		self.connect(self.zoomInButton, Qt.SIGNAL("clicked()"), self.zoomMapIn)
		self.connect(self.zoomOutButton, Qt.SIGNAL("clicked()"), self.zoomMapOut)
		self.connect(self.statisticsButton, Qt.SIGNAL("clicked()"), self.changeStatisticsVisibility)
		self.connect(self.jumpbridgesButton, Qt.SIGNAL("clicked()"), self.changeJumpbridgesVisibility)
		self.connect(self.chatLargeButton, Qt.SIGNAL("clicked()"), self.chatLarger)
		self.connect(self.chatSmallButton, Qt.SIGNAL("clicked()"), self.chatSmaller)
		self.connect(self.infoAction, Qt.SIGNAL("triggered()"), self.showInfo)
		self.connect(self.showChatAvatarsAction, Qt.SIGNAL("triggered()"), self.changeShowAvatars)
		self.connect(self.alwaysOnTopAction, Qt.SIGNAL("triggered()"), self.changeAlwaysOnTop)
		self.connect(self.chooseChatRoomsAction, Qt.SIGNAL("triggered()"), self.showChatroomChooser)
		self.connect(self.catchRegionAction, Qt.SIGNAL("triggered()"), lambda item=self.catchRegionAction: self.handleRegionMenuItemSelected(item))
		self.connect(self.providenceRegionAction, Qt.SIGNAL("triggered()"), lambda item=self.providenceRegionAction: self.handleRegionMenuItemSelected(item))
		self.connect(self.providenceCatchRegionAction, Qt.SIGNAL("triggered()"), lambda item=self.providenceCatchRegionAction: self.handleRegionMenuItemSelected(item))
		self.connect(self.chooseRegionAction, Qt.SIGNAL("triggered()"), self.showRegionChooser)
		self.connect(self.showChatAction, Qt.SIGNAL("triggered()"), self.changeChatVisibility)
		self.connect(self.soundSetupAction, Qt.SIGNAL("triggered()"), self.showSoundSetup)
		self.connect(self.activateSoundAction, Qt.SIGNAL("triggered()"), self.changeSound)
		self.connect(self.useSpokenNotificationsAction, Qt.SIGNAL("triggered()"), self.changeUseSpokenNotifications)
		self.connect(self.floatingOverviewAction, Qt.SIGNAL("triggered()"), self.showFloatingOverview)
		self.connect(self.trayIcon, Qt.SIGNAL("alarm_distance"), self.changeAlarmDistance)
		self.connect(self.framelessWindowAction, Qt.SIGNAL("triggered()"), self.changeFrameless)
		self.connect(self.trayIcon, Qt.SIGNAL("change_frameless"), self.changeFrameless)
		self.connect(self.frameButton, Qt.SIGNAL("clicked()"), self.changeFrameless)
		self.connect(self.quitAction, Qt.SIGNAL("triggered()"), self.close)
		self.connect(self.trayIcon, Qt.SIGNAL("quit"), self.close)
		self.connect(self.jumpbridgeDataAction, Qt.SIGNAL("triggered()"), self.showJumbridgeChooser)

		# Create a timer to refresh the map, then load up the map, either from cache or dotlan
		self.mapTimer = QtCore.QTimer(self)
		self.connect(self.mapTimer, QtCore.SIGNAL("timeout()"), self.updateMapView)
		self.setupMap(True)

		# Recall cached user settings
		try:
			self.cache.recallAndApplySettings(self, "settings")
		except Exception as e:
			print str(e)
			self.trayIcon.showMessage("Settings error", "Something went wrong loading saved state:\n {0}".format(str(e)), 1)

		# Set up threads and their connections
		self.avatarFindThread = AvatarFindThread()
		self.connect(self.avatarFindThread, QtCore.SIGNAL("avatar_update"), self.updateAvatarOnChatEntry)
		self.avatarFindThread.start()

		self.kosRequestThread = KOSCheckerThread()
		self.connect(self.kosRequestThread, Qt.SIGNAL("kos_result"), self.showKosResult)
		self.kosRequestThread.start()

		self.filewatcherThread = filewatcher.FileWatcher(self.pathToLogs, 60 * 60 * 24)
		self.connect(self.filewatcherThread, QtCore.SIGNAL("file_change"), self.logFileChanged)
		self.filewatcherThread.start()

		self.versionCheckThread = amazon_s3.NotifyNewVersionThread()
		self.versionCheckThread.connect(self.versionCheckThread, Qt.SIGNAL("newer_version"), self.notifyNewerVersion)
		self.versionCheckThread.start()

		if sys.platform.startswith("win32") or sys.platform.startswith("cygwin"):
			font = self.statisticsButton.font()
			font.setPointSize(8)
			self.statisticsButton.setFont(font)
			self.jumpbridgesButton.setFont(font)


	def setupMap(self, initialize=False):
		self.mapTimer.stop()
		regionName = self.cache.getFromCache("region_name")
		if not regionName:
			regionName = "Providence"
		svg = None
		try:
			with open(resourcePath("vi/ui/res/mapdata/{0}.svg".format(regionName))) as svgFile:
				svg = svgFile.read()
		except Exception as e:
			pass

		try:
			self.dotlan = dotlan.Map(regionName, svg)
		except dotlan.DotlanException as e:
			QtGui.QMessageBox.critical(None, "Error getting map", unicode(e), "Quit")
			sys.exit(1)

		if self.dotlan.outdatedCacheError:
			e = self.dotlan.outdatedCacheError
			diagText = "Something went wrong getting map data. Proceeding with older cached data. " \
					   "Check for a newer version and inform the maintainer.\n\nError: {0} {1}".format(type(e), unicode(e))
			print str(e)
			QtGui.QMessageBox.warning(None, "Using map from cache", diagText, "Ok")

		# Load the jumpbridges
		self.setJumpbridges(self.cache.getFromCache("jumpbridge_url"))
		self.initMapPosition = None  # We read this after first rendering
		self.systems = self.dotlan.systems
		self.chatparser = chatparser.ChatParser(self.pathToLogs, self.roomnames, self.systems)

		# Menus - only once
		if initialize:
			# Add a contextual menu to the mapView
			def mapContextMenuEvent(event):
				self.mapView.contextMenu.exec_(self.mapToGlobal(QPoint(event.x(), event.y())))

			self.setMapContent(self.dotlan.svg)
			self.mapView.contextMenu = TrayContextMenu(self.trayIcon)
			self.mapView.contextMenuEvent = mapContextMenuEvent
			self.mapView.connect(self.mapView, Qt.SIGNAL("linkClicked(const QUrl&)"), self.mapLinkClicked)

			# Also set up our app menus
			regionName = self.cache.getFromCache("region_name")
			if not regionName:
				self.providenceRegionAction.setChecked(True)
			elif regionName.startswith("Providencecatch"):
				self.providenceCatchRegionAction.setChecked(True)
			elif regionName.startswith("Catch"):
				self.catchRegionAction.setChecked(True)
			elif regionName.startswith("Providence"):
				self.providenceRegionAction.setChecked(True)
			else:
				self.chooseRegionAction.setChecked(True)

		self.updateMapView(force=True)
		self.mapTimer.start(MAP_UPDATE_INTERVAL_IN_MSECS)
		self.jumpbridgesButton.setChecked(False)
		self.statisticsButton.setChecked(False)


	def closeEvent(self, event):
		""" Persisting things to the cache before closing the window
		"""
		# Known playernames
		if self.knownPlayerNames:
			value = ",".join(self.knownPlayerNames)
			self.cache.putIntoCache("known_player_names", value, 60 * 60 * 24 * 365)

		# Program state to cache (to read it on next startup)
		settings = ((None, "restoreGeometry", str(self.saveGeometry())),
					(None, "restoreState", str(self.saveState())),
					("splitter", "restoreGeometry", str(self.splitter.saveGeometry())),
					("splitter", "restoreState", str(self.splitter.saveState())),
					("mapView", "setZoomFactor", self.mapView.zoomFactor()),
					(None, "changeChatFontSize", ChatEntryWidget.TEXT_SIZE),
					(None, "changeOpacity", self.opacityGroup.checkedAction().opacity),
					(None, "changeAlwaysOnTop", self.alwaysOnTopAction.isChecked()),
					(None, "changeShowAvatars", self.showChatAvatarsAction.isChecked()),
					(None, "changeAlarmDistance", self.alarmDistance),
					(None, "changeSound", self.activateSoundAction.isChecked()),
					(None, "changeChatVisibility", self.showChatAction.isChecked()),
					(None, "setInitMapPosition", (self.mapView.page().mainFrame().scrollPosition().x(), self.mapView.page().mainFrame().scrollPosition().y())),
					(None, "setSoundVolume", SoundManager().soundVolume),
					(None, "changeFrameless", self.framelessWindowAction.isChecked()),
					(None, "changeUseSpokenNotifications", self.useSpokenNotificationsAction.isChecked()),
					(None, "changeClipboard", self.kosClipboardActiveAction.isChecked()),
					(None, "changeFloatingOverview", self.floatingOverviewAction.isChecked()),
					(None, "changeAlreadyShowedSoundWarning", self.alreadyShowedSoundWarning))
		self.cache.putIntoCache("settings", str(settings), 60 * 60 * 24 * 365)

		# Stop the threads
		try:
			self.filewatcherThread.quit()
			self.kosRequestThread.quit()
			SoundManager().quit()
			self.versionCheckThread.quit()
		except Exception:
			pass
		event.accept()


	def notifyNewerVersion(self, newestVersion):
		self.trayIcon.showMessage("Newer Version", ("An update is available for Vintel.\nhttps://github.com/Xanthos-Eve/vintel"), 1)


	def changeFloatingOverview(self, newValue=None):
		pass


	def changeAlreadyShowedSoundWarning(self, newValue):
		self.alreadyShowedSoundWarning = newValue


	def changeChatVisibility(self, newValue=None):
		if newValue is None:
			newValue = self.showChatAction.isChecked()
		self.showChatAction.setVisible(newValue)
		self.chatbox.setVisible(newValue)


	def changeClipboard(self, newValue=None):
		if newValue is None:
			newValue = self.kosClipboardActiveAction.isChecked()
		self.kosClipboardActiveAction.setChecked(newValue)


	def changeUseSpokenNotifications(self, newValue=None):
		if SoundManager().platformSupportsSpeech():
			if newValue is None:
				newValue = self.useSpokenNotificationsAction.isChecked()
			self.useSpokenNotificationsAction.setChecked(newValue)
			SoundManager().setUseSpokenNotifications(newValue)
		else:
			self.useSpokenNotificationsAction.setChecked(False)
			self.useSpokenNotificationsAction.setEnabled(False)


	def changeOpacity(self, newValue=None):
		if newValue is not None:
			for action in self.opacityGroup.actions():
				if action.opacity == newValue:
					action.setChecked(True)
		action = self.opacityGroup.checkedAction()
		self.setWindowOpacity(action.opacity)


	def changeSound(self, newValue=None, disable=False):
		if disable:
			self.activateSoundAction.setChecked(False)
			self.activateSoundAction.setEnabled(False)
			self.soundSetupAction.setEnabled(False)
			self.soundButton.setEnabled(False)
			if not self.alreadyShowedSoundWarning:
				self.alreadyShowedSoundWarning = True
				QtGui.QMessageBox.warning(None, "Sound disabled", "The lib 'pyglet' which is used to play sounds cannot be found, ""so the soundsystem is disabled.\nIf you want sound, please install the 'pyglet' library. This warning will not be shown again.", "OK")
		else:
			if newValue is None:
				newValue = self.activateSoundAction.isChecked()
			self.activateSoundAction.setChecked(newValue)
			SoundManager().soundActive = newValue


	def changeAlwaysOnTop(self, newValue=None):
		if newValue is None:
			newValue = self.alwaysOnTopAction.isChecked()
		self.hide()
		self.alwaysOnTopAction.setChecked(newValue)
		if newValue:
			self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
		else:
			self.setWindowFlags(self.windowFlags() & (~QtCore.Qt.WindowStaysOnTopHint))
		self.show()


	def changeFrameless(self, newValue=None):
		if newValue is None:
			newValue = not self.frameButton.isVisible()
		self.hide()
		if newValue:
			self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
			self.changeAlwaysOnTop(True)
		else:
			self.setWindowFlags(self.windowFlags() & (~QtCore.Qt.FramelessWindowHint))
		self.menubar.setVisible(not newValue)
		self.frameButton.setVisible(newValue)
		self.framelessWindowAction.setChecked(newValue)

		for cm in TrayContextMenu.instances:
			cm.framelessCheck.setChecked(newValue)
		self.show()


	def changeShowAvatars(self, newValue=None):
		if newValue is None:
			newValue = self.showChatAvatarsAction.isChecked()
		self.showChatAvatarsAction.setChecked(newValue)
		ChatEntryWidget.SHOW_AVATAR = newValue
		for entry in self.chatEntries:
			entry.avatarLabel.setVisible(newValue)


	def changeChatFontSize(self, newSize):
		if newSize:
			for entry in self.chatEntries:
				entry.changeFontSize(newSize)
			ChatEntryWidget.TEXT_SIZE = newSize

	def chatSmaller(self):
		newSize = ChatEntryWidget.TEXT_SIZE - 1
		self.changeChatFontSize(newSize)


	def chatLarger(self):
		newSize = ChatEntryWidget.TEXT_SIZE + 1
		self.changeChatFontSize(newSize)


	def changeAlarmDistance(self, distance):
		self.alarmDistance = distance
		for cm in TrayContextMenu.instances:
			for action in cm.distanceGroup.actions():
				if action.alarmDistance == distance:
					action.setChecked(True)
		self.trayIcon.alarmDistance = distance


	def changeJumpbridgesVisibility(self):
		newValue = self.dotlan.changeJumpbridgesVisibility()
		self.jumpbridgesButton.setChecked(newValue)
		self.updateMapView()

	def changeStatisticsVisibility(self):
		newValue = self.dotlan.changeStatisticsVisibility()
		self.statisticsButton.setChecked(newValue)
		self.updateMapView()

	def clipboardChanged(self, mode):
		if not (mode == 0 and self.kosClipboardActiveAction.isChecked() and self.clipboard.mimeData().hasText()):
			return
		content = unicode(self.clipboard.text())
		contentTuple = tuple(content)
		# Limit redundant kos checks
		if contentTuple != self.oldClipboardContent:
			parts = tuple(content.split("\n"))
			for part in parts:
				# Make sure user is in the content (this is a check of the local system in Eve)
				if part in self.knownPlayerNames:
					self.trayIcon.setIcon(self.taskbarIconWorking)
					self.kosRequestThread.addRequest(parts, "clipboard", True)
					break
			self.oldClipboardContent = contentTuple


	def mapLinkClicked(self, url):
		systemName = unicode(url.path().split("/")[-1]).upper()
		system = self.systems[str(systemName)]
		sc = SystemChat(self, SystemChat.SYSTEM, system, self.chatEntries, self.knownPlayerNames)
		sc.connect(self, Qt.SIGNAL("chat_message_added"), sc.addChatEntry)
		sc.connect(self, Qt.SIGNAL("avatar_loaded"), sc.newAvatarAvailable)
		sc.connect(sc, Qt.SIGNAL("location_set"), self.setLocation)
		sc.show()


	def markSystemOnMap(self, systemname):
		self.systems[unicode(systemname)].mark()
		self.updateMapView()


	def setLocation(self, char, newSystem):
		for system in self.systems.values():
			system.removeLocatedCharacter(char)
		if not newSystem == "?" and newSystem in self.systems:
			self.systems[newSystem].addLocatedCharacter(char)
			self.setMapContent(self.dotlan.svg)


	def setMapContent(self, content):
		if self.initMapPosition is None:
			scrollposition = self.mapView.page().mainFrame().scrollPosition()
		else:
			scrollposition = self.initMapPosition
			self.initMapPosition = None
		self.mapView.setContent(content)
		self.mapView.page().mainFrame().setScrollPosition(scrollposition)
		self.mapView.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)


	def setInitMapPosition(self, xy):
		self.initMapPosition = QPoint(xy[0], xy[1])


	def showChatroomChooser(self):
		chooser = ChatroomsChooser(self)
		chooser.connect(chooser, Qt.SIGNAL("rooms_changed"), self.changedRoomnames)
		chooser.show()


	def showJumbridgeChooser(self):
		url = self.cache.getFromCache("jumpbridge_url")
		chooser = JumpbridgeChooser(self, url)
		chooser.connect(chooser, Qt.SIGNAL("set_jumpbridge_url"), self.setJumpbridges)
		chooser.show()


	def setSoundVolume(self, value):
		SoundManager().setSoundVolume(value)


	def setJumpbridges(self, url):
		if url is None:
			url = ""
		try:
			data = []
			if url != "":
				content = urllib2.urlopen(url).read()
				for line in content.split("\n"):
					parts = line.strip().split()
					if len(parts) == 3:
						data.append(parts)
			else:
				data = amazon_s3.getJumpbridgeData(self.dotlan.region.lower())
			self.dotlan.setJumpbridges(data)
			self.cache.putIntoCache("jumpbridge_url", url, 60 * 60 * 24 * 365 * 8)
		except Exception as e:
			QtGui.QMessageBox.warning(None, "Loading jumpbridges failed!", "Error: {0}".format(unicode(e)), "OK")


	def handleRegionMenuItemSelected(self, menuAction=None):
		self.catchRegionAction.setChecked(False)
		self.providenceRegionAction.setChecked(False)
		self.providenceCatchRegionAction.setChecked(False)
		self.chooseRegionAction.setChecked(False)
		if menuAction:
			menuAction.setChecked(True)
			regionName = unicode(menuAction.property("regionName").toString())
			regionName = dotlan.convertRegionName(regionName)
			Cache().putIntoCache("region_name", regionName, 60 * 60 * 24 * 365)
			self.setupMap()


	def showRegionChooser(self):
		def handleRegionChosen():
			self.handleRegionMenuItemSelected(None)
			self.chooseRegionAction.setChecked(True)
			self.setupMap()

		self.chooseRegionAction.setChecked(False)
		chooser = RegionChooser(self)
		self.connect(chooser, Qt.SIGNAL("new_region_chosen"), handleRegionChosen)
		chooser.show()


	def addMessageToIntelChat(self, message):
		scrollToBottom = False
		if (self.chatListWidget.verticalScrollBar().value() == self.chatListWidget.verticalScrollBar().maximum()):
			scrollToBottom = True
		chatEntryWidget = ChatEntryWidget(message)
		listWidgetItem = QtGui.QListWidgetItem(self.chatListWidget)
		listWidgetItem.setSizeHint(chatEntryWidget.sizeHint())
		self.chatListWidget.addItem(listWidgetItem)
		self.chatListWidget.setItemWidget(listWidgetItem, chatEntryWidget)
		self.avatarFindThread.addChatEntry(chatEntryWidget)
		self.chatEntries.append(chatEntryWidget)
		self.connect(chatEntryWidget, Qt.SIGNAL("mark_system"), self.markSystemOnMap)
		self.emit(Qt.SIGNAL("chat_message_added"), chatEntryWidget)
		self.pruneMessages()
		if scrollToBottom:
			self.chatListWidget.scrollToBottom()


	def pruneMessages(self):
		try:
			now = time.mktime(evegate.currentEveTime().timetuple())
			for row in range(self.chatListWidget.count()):
				chatListWidgetItem = self.chatListWidget.item(0)
				chatEntryWidget = self.chatListWidget.itemWidget(chatListWidgetItem)
				message = chatEntryWidget.message
				if now - time.mktime(message.timestamp.timetuple()) > MESSAGE_EXPIRY_IN_SECONDS:
					self.chatEntries.remove(chatEntryWidget)
					self.chatListWidget.takeItem(0)

					for widgetInMessage in message.widgets:
						widgetInMessage.removeItemWidget(chatListWidgetItem)
				else:
					break
		except Exception as e:
			print e


	def showKosResult(self, state, text, requestType, hasKos):
		try:
			if hasKos:
				SoundManager().playSound("kos", text)
			if state == "ok":
				if requestType == "xxx":  # a xxx request out of the chat
					self.trayIcon.showMessage("Player KOS-Check", text, 1)
				elif requestType == "clipboard":  # request from clipboard-change
					if len(text) <= 0:
						text = "None KOS"
					self.trayIcon.showMessage("Your KOS-Check", text, 1)
				text = text.replace("\n\n", "<br>")
				message = chatparser.chatparser.Message("Vintel KOS-Check", text, evegate.currentEveTime(), "VINTEL", [],
														states.NOT_CHANGE, text.upper(), text)
				self.addMessageToIntelChat(message)
			elif state == "error":
				self.trayIcon.showMessage("KOS Failure", text, 3)
		except Exception:
			pass
		self.trayIcon.setIcon(self.taskbarIconQuiescent)


	def changedRoomnames(self, newRoomnames):
		self.cache.putIntoCache("room_names", u",".join(newRoomnames), 60 * 60 * 24 * 365 * 5)
		self.chatparser.rooms = newRoomnames


	def showInfo(self):
		infoDialog = QtGui.QDialog(self)
		uic.loadUi(resourcePath("vi/ui/Info.ui"), infoDialog)
		infoDialog.versionLabel.setText(u"Version: {0}".format(VERSION))
		infoDialog.logoLabel.setPixmap(QtGui.QPixmap(resourcePath("vi/ui/res/logo.png")))
		infoDialog.connect(infoDialog.closeButton, Qt.SIGNAL("clicked()"), infoDialog.accept)
		infoDialog.show()


	def showFloatingOverview(self):
		pass


	def showSoundSetup(self):
		dialog = QtGui.QDialog(self)
		uic.loadUi(resourcePath("vi/ui/SoundSetup.ui"), dialog)
		dialog.volumeSlider.setValue(SoundManager().soundVolume)
		dialog.connect(dialog.volumeSlider, Qt.SIGNAL("valueChanged(int)"), SoundManager().setSoundVolume)
		dialog.connect(dialog.testSoundButton, Qt.SIGNAL("clicked()"), SoundManager().playSound)
		dialog.connect(dialog.closeButton, Qt.SIGNAL("clicked()"), dialog.accept)
		dialog.show()


	def systemTrayActivated(self, reason):
		if reason == QtGui.QSystemTrayIcon.Trigger:
			if self.isMinimized():
				self.showNormal()
				self.activateWindow()
			elif not self.isActiveWindow():
				self.activateWindow()
			else:
				self.showMinimized()


	def updateAvatarOnChatEntry(self, chatEntry, avatarData):
		updated = chatEntry.updateAvatar(avatarData)
		if not updated:
			self.avatarFindThread.addChatEntry(chatEntry, clearCache=True)
		else:
			self.emit(Qt.SIGNAL("avatar_loaded"), chatEntry.message.user, avatarData)


	def updateMapView(self, force=False):
		def updateStatisticsOnMap(data):
			if data["result"] == "ok":
				self.dotlan.addSystemStatistics(data["statistics"])
			elif data["result"] == "error":
				text = data["text"]
				self.trayIcon.showMessage("Loading statstics failed", text, 3)

		if force or self.lastStatisticsUpdate < time.time() - STATISTICS_UPDATE_INTERVAL_IN_MSECS:
			self.lastStatisticsUpdate = time.time()
			statisticsThread = MapStatisticsThread()
			self.connect(statisticsThread, Qt.SIGNAL("statistic_data_update"), updateStatisticsOnMap)
			statisticsThread.start()
		self.setMapContent(self.dotlan.svg)


	def zoomMapIn(self):
		self.mapView.setZoomFactor(self.mapView.zoomFactor() + 0.1)


	def zoomMapOut(self):
		self.mapView.setZoomFactor(self.mapView.zoomFactor() - 0.1)


	def logFileChanged(self, path):
		messages = self.chatparser.fileModified(path)
		for message in messages:
			# If players location has changed
			if message.status == states.LOCATION:
				self.knownPlayerNames.add(message.user)
				self.setLocation(message.user, message.systems[0])
			# SOUND_TEST special
			elif message.status == states.SOUND_TEST and message.user in self.knownPlayerNames:
				words = message.message.split()
				if len(words) > 1:
					SoundManager().playSound(words[1])
			# KOS request
			elif message.status == states.KOS_STATUS_REQUEST:
				text = message.message[4:]
				text = text.replace("  ", ",")
				parts = (name.strip() for name in text.split(","))
				self.trayIcon.setIcon(self.taskbarIconWorking)
				self.kosRequestThread.addRequest(parts, "xxx", False)
			# Otherwise consider it a 'normal' chat message
			elif (message.user not in ("EVE-System", "EVE System") and message.status != states.IGNORE):
				self.addMessageToIntelChat(message)
				# For each system that was mentioned in the message, check for alarm distance to the current system
				# and alarm if within alarm distance.
				if message.systems:
					for system in message.systems:
						systemname = system.name
						self.dotlan.systems[systemname].setStatus(message.status)
						if message.status in (states.REQUEST, states.ALARM) and message.user not in self.knownPlayerNames:
							alarmDistance = self.alarmDistance if message.status == states.ALARM else 0
							for nSystem, data in system.getNeighbours(alarmDistance).items():
								distance = data["distance"]
								chars = nSystem.getLocatedCharacters()
								if len(chars) > 0 and message.user not in chars:
									self.trayIcon.showNotification(message, system.name, ", ".join(chars), distance)
				self.setMapContent(self.dotlan.svg)
Example #49
0
	def __init__(self, pathToLogs, trayIcon):

		QtGui.QMainWindow.__init__(self)
		uic.loadUi(resourcePath('vi/ui/MainWindow.ui'), self)
		self.setWindowTitle("Vintel " + VERSION)
		self.taskbarIconQuiescent = QtGui.QIcon(resourcePath("vi/ui/res/logo_small.png"))
		self.taskbarIconWorking = QtGui.QIcon(resourcePath("vi/ui/res/logo_small_green.png"))
		self.setWindowIcon(self.taskbarIconQuiescent)

		self.pathToLogs = pathToLogs
		self.trayIcon = trayIcon
		self.cache = Cache()

		# Load my toon names
		self.knownPlayerNames = self.cache.getFromCache("known_player_names")
		if self.knownPlayerNames:
			self.knownPlayerNames = set(self.knownPlayerNames.split(","))
		else:
			self.knownPlayerNames = set()

		# Set up my intel rooms
		roomnames = self.cache.getFromCache("room_names")
		if roomnames:
			roomnames = roomnames.split(",")
		else:
			roomnames = (u"TheCitadel", u"North Provi Intel", u"North Catch Intel")
			self.cache.putIntoCache("room_names", u",".join(roomnames), 60 * 60 * 24 * 365 * 5)
		self.roomnames = roomnames

		# Disable the sound UI if sound is not available
		if not SoundManager().soundAvailable:
			self.changeSound(disable=True)
		else:
			self.changeSound()

		# Initialize state
		self.initMapPosition = None
		self.oldClipboardContent = ""
		self.alarmDistance = 0
		self.lastStatisticsUpdate = 0
		self.alreadyShowedSoundWarning = False
		self.chatEntries = []
		self.frameButton.setVisible(False)
		self.trayIcon.activated.connect(self.systemTrayActivated)
		self.clipboard = QtGui.QApplication.clipboard()
		self.clipboard.clear(mode=self.clipboard.Clipboard)

		# Fill in opacity values and connections
		self.opacityGroup = QtGui.QActionGroup(self.menu)
		for i in (100, 80, 60, 40, 20):
			action = QtGui.QAction("Opacity {0}%".format(i), None, checkable=True)
			if i == 100:
				action.setChecked(True)
			action.opacity = i / 100.0
			self.connect(action, QtCore.SIGNAL("triggered()"), self.changeOpacity)
			self.opacityGroup.addAction(action)
			self.menuTransparency.addAction(action)

		# Wire up UI connections
		self.connect(self.clipboard, Qt.SIGNAL("changed(QClipboard::Mode)"), self.clipboardChanged)
		self.connect(self.zoomInButton, Qt.SIGNAL("clicked()"), self.zoomMapIn)
		self.connect(self.zoomOutButton, Qt.SIGNAL("clicked()"), self.zoomMapOut)
		self.connect(self.statisticsButton, Qt.SIGNAL("clicked()"), self.changeStatisticsVisibility)
		self.connect(self.jumpbridgesButton, Qt.SIGNAL("clicked()"), self.changeJumpbridgesVisibility)
		self.connect(self.chatLargeButton, Qt.SIGNAL("clicked()"), self.chatLarger)
		self.connect(self.chatSmallButton, Qt.SIGNAL("clicked()"), self.chatSmaller)
		self.connect(self.infoAction, Qt.SIGNAL("triggered()"), self.showInfo)
		self.connect(self.showChatAvatarsAction, Qt.SIGNAL("triggered()"), self.changeShowAvatars)
		self.connect(self.alwaysOnTopAction, Qt.SIGNAL("triggered()"), self.changeAlwaysOnTop)
		self.connect(self.chooseChatRoomsAction, Qt.SIGNAL("triggered()"), self.showChatroomChooser)
		self.connect(self.catchRegionAction, Qt.SIGNAL("triggered()"), lambda item=self.catchRegionAction: self.handleRegionMenuItemSelected(item))
		self.connect(self.providenceRegionAction, Qt.SIGNAL("triggered()"), lambda item=self.providenceRegionAction: self.handleRegionMenuItemSelected(item))
		self.connect(self.providenceCatchRegionAction, Qt.SIGNAL("triggered()"), lambda item=self.providenceCatchRegionAction: self.handleRegionMenuItemSelected(item))
		self.connect(self.chooseRegionAction, Qt.SIGNAL("triggered()"), self.showRegionChooser)
		self.connect(self.showChatAction, Qt.SIGNAL("triggered()"), self.changeChatVisibility)
		self.connect(self.soundSetupAction, Qt.SIGNAL("triggered()"), self.showSoundSetup)
		self.connect(self.activateSoundAction, Qt.SIGNAL("triggered()"), self.changeSound)
		self.connect(self.useSpokenNotificationsAction, Qt.SIGNAL("triggered()"), self.changeUseSpokenNotifications)
		self.connect(self.floatingOverviewAction, Qt.SIGNAL("triggered()"), self.showFloatingOverview)
		self.connect(self.trayIcon, Qt.SIGNAL("alarm_distance"), self.changeAlarmDistance)
		self.connect(self.framelessWindowAction, Qt.SIGNAL("triggered()"), self.changeFrameless)
		self.connect(self.trayIcon, Qt.SIGNAL("change_frameless"), self.changeFrameless)
		self.connect(self.frameButton, Qt.SIGNAL("clicked()"), self.changeFrameless)
		self.connect(self.quitAction, Qt.SIGNAL("triggered()"), self.close)
		self.connect(self.trayIcon, Qt.SIGNAL("quit"), self.close)
		self.connect(self.jumpbridgeDataAction, Qt.SIGNAL("triggered()"), self.showJumbridgeChooser)

		# Create a timer to refresh the map, then load up the map, either from cache or dotlan
		self.mapTimer = QtCore.QTimer(self)
		self.connect(self.mapTimer, QtCore.SIGNAL("timeout()"), self.updateMapView)
		self.setupMap(True)

		# Recall cached user settings
		try:
			self.cache.recallAndApplySettings(self, "settings")
		except Exception as e:
			print str(e)
			self.trayIcon.showMessage("Settings error", "Something went wrong loading saved state:\n {0}".format(str(e)), 1)

		# Set up threads and their connections
		self.avatarFindThread = AvatarFindThread()
		self.connect(self.avatarFindThread, QtCore.SIGNAL("avatar_update"), self.updateAvatarOnChatEntry)
		self.avatarFindThread.start()

		self.kosRequestThread = KOSCheckerThread()
		self.connect(self.kosRequestThread, Qt.SIGNAL("kos_result"), self.showKosResult)
		self.kosRequestThread.start()

		self.filewatcherThread = filewatcher.FileWatcher(self.pathToLogs, 60 * 60 * 24)
		self.connect(self.filewatcherThread, QtCore.SIGNAL("file_change"), self.logFileChanged)
		self.filewatcherThread.start()

		self.versionCheckThread = amazon_s3.NotifyNewVersionThread()
		self.versionCheckThread.connect(self.versionCheckThread, Qt.SIGNAL("newer_version"), self.notifyNewerVersion)
		self.versionCheckThread.start()

		if sys.platform.startswith("win32") or sys.platform.startswith("cygwin"):
			font = self.statisticsButton.font()
			font.setPointSize(8)
			self.statisticsButton.setFont(font)
			self.jumpbridgesButton.setFont(font)
Example #50
0
def getSystemStatistics():
    """ Reads the informations for all solarsystems from the EVE API
        Reads a dict like:
            systemid: "jumps", "shipkills", "factionkills", "podkills"
    """
    data = {}
    systemData = {}
    cache = Cache()
    # first the data for the jumps
    cacheKey = "jumpstatistic"
    jumpData = cache.getFromCache(cacheKey)

    try:
        if jumpData is None:
            jumpData = {}
            url = "https://api.eveonline.com/map/Jumps.xml.aspx"
            content = requests.get(url).text
            soup = BeautifulSoup(content, 'html.parser')

            for result in soup.select("result"):
                for row in result.select("row"):
                    jumpData[int(row["solarsystemid"])] = int(row["shipjumps"])

            cacheUntil = datetime.datetime.strptime(soup.select("cacheduntil")[0].text, "%Y-%m-%d %H:%M:%S")
            diff = cacheUntil - currentEveTime()
            cache.putIntoCache(cacheKey, json.dumps(jumpData), diff.seconds)
        else:
            jumpData = json.loads(jumpData)

        # now the further data
        cacheKey = "systemstatistic"
        systemData = cache.getFromCache(cacheKey)

        if systemData is None:
            systemData = {}
            url = "https://api.eveonline.com/map/Kills.xml.aspx"
            content = requests.get(url).text
            soup = BeautifulSoup(content, 'html.parser')

            for result in soup.select("result"):
                for row in result.select("row"):
                    systemData[int(row["solarsystemid"])] = {"ship": int(row["shipkills"]),
                                                             "faction": int(row["factionkills"]),
                                                             "pod": int(row["podkills"])}

            cacheUntil = datetime.datetime.strptime(soup.select("cacheduntil")[0].text, "%Y-%m-%d %H:%M:%S")
            diff = cacheUntil - currentEveTime()
            cache.putIntoCache(cacheKey, json.dumps(systemData), diff.seconds)
        else:
            systemData = json.loads(systemData)
    except Exception as e:
        logging.error("Exception during getSystemStatistics: : %s", e)

    # We collected all data (or loaded them from cache) - now zip it together
    for i, v in jumpData.items():
        i = int(i)
        if i not in data:
            data[i] = {"shipkills": 0, "factionkills": 0, "podkills": 0}
        data[i]["jumps"] = v
    for i, v in systemData.items():
        i = int(i)
        if i not in data:
            data[i] = {"jumps": 0}
        data[i]["shipkills"] = v["ship"] if "ship" in v else 0
        data[i]["factionkills"] = v["faction"] if "faction" in v else 0
        data[i]["podkills"] = v["pod"] if "pod" in v else 0
    return data
Example #51
0
File: viui.py Project: 3vi1/vintel
    def __init__(self, pathToLogs, trayIcon, backGroundColor):

        QtGui.QMainWindow.__init__(self)
        self.cache = Cache()

        if backGroundColor:
            self.setStyleSheet("QWidget { background-color: %s; }" % backGroundColor)
        uic.loadUi(resourcePath('vi/ui/MainWindow.ui'), self)
        self.setWindowTitle("Vintel " + vi.version.VERSION + "{dev}".format(dev="-SNAPSHOT" if vi.version.SNAPSHOT else ""))
        self.taskbarIconQuiescent = QtGui.QIcon(resourcePath("vi/ui/res/logo_small.png"))
        self.taskbarIconWorking = QtGui.QIcon(resourcePath("vi/ui/res/logo_small_green.png"))
        self.setWindowIcon(self.taskbarIconQuiescent)
        self.setFocusPolicy(QtCore.Qt.StrongFocus)

        self.pathToLogs = pathToLogs
        self.mapTimer = QtCore.QTimer(self)
        self.connect(self.mapTimer, QtCore.SIGNAL("timeout()"), self.updateMapView)
        self.clipboardTimer = QtCore.QTimer(self)
        self.oldClipboardContent = ""
        self.trayIcon = trayIcon
        self.trayIcon.activated.connect(self.systemTrayActivated)
        self.clipboard = QtGui.QApplication.clipboard()
        self.clipboard.clear(mode=self.clipboard.Clipboard)
        self.alarmDistance = 0
        self.lastStatisticsUpdate = 0
        self.chatEntries = []
        self.frameButton.setVisible(False)
        self.scanIntelForKosRequestsEnabled = True
        self.initialMapPosition = None
        self.mapPositionsDict = {}

        # Load user's toon names
        self.knownPlayerNames = self.cache.getFromCache("known_player_names")
        if self.knownPlayerNames:
            self.knownPlayerNames = set(self.knownPlayerNames.split(","))
        else:
            self.knownPlayerNames = set()
            diagText = "Vintel scans EVE system logs and remembers your characters as they change systems.\n\nSome features (clipboard KOS checking, alarms, etc.) may not work until your character(s) have been registered. Change systems, with each character you want to monitor, while Vintel is running to remedy this."
            QtGui.QMessageBox.warning(None, "Known Characters not Found", diagText, "Ok")

        # Set up user's intel rooms
        roomnames = self.cache.getFromCache("room_names")
        if roomnames:
            roomnames = roomnames.split(",")
        else:
            roomnames = (u"TheCitadel", u"North Provi Intel", u"North Catch Intel", "North Querious Intel")
            self.cache.putIntoCache("room_names", u",".join(roomnames), 60 * 60 * 24 * 365 * 5)
        self.roomnames = roomnames

        # Disable the sound UI if sound is not available
        if not SoundManager().soundAvailable:
            self.changeSound(disable=True)
        else:
            self.changeSound()

        # Set up Transparency menu - fill in opacity values and make connections
        self.opacityGroup = QtGui.QActionGroup(self.menu)
        for i in (100, 80, 60, 40, 20):
            action = QtGui.QAction("Opacity {0}%".format(i), None, checkable=True)
            if i == 100:
                action.setChecked(True)
            action.opacity = i / 100.0
            self.connect(action, QtCore.SIGNAL("triggered()"), self.changeOpacity)
            self.opacityGroup.addAction(action)
            self.menuTransparency.addAction(action)

        #
        # Platform specific UI resizing - we size items in the resource files to look correct on the mac,
        # then resize other platforms as needed
        #
        if sys.platform.startswith("win32") or sys.platform.startswith("cygwin"):
            font = self.statisticsButton.font()
            font.setPointSize(8)
            self.statisticsButton.setFont(font)
            self.jumpbridgesButton.setFont(font)
        elif sys.platform.startswith("linux"):
            pass

        self.wireUpUIConnections()
        self.recallCachedSettings()
        self.setupThreads()
        self.setupMap(True)