#! /usr/bin/python

#===================================
#		   stackapplet
#  Copyright 2011 - Nathan Osman
#
#	 Contains the main class
#	  used by StackApplet
#
#   StackApplet is released under
#		the MIT license
#===================================

# Standard modules
import os
import platform
import signal
import sys
import time
import urllib2
import webbrowser

# The following modules are required
# for supporting translations
import locale
import gettext

# We create a shortcut for the gettext function
# which will later point to the function that can
# be used to retrieve text in the appropriate language.
_ = None

# Global definitions
__application__ = "StackApplet"
__authors__	    = ["Nathan Osman", "Isaiah Heyer"]
__artists__	    = ["Marco Ceppi"]
__translators__ = "translator-credits"
__copyright__   = "Copyright (c) 2011, Nathan Osman"
__license__	    = '''Copyright (c) 2011 Nathan Osman

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.'''
__version__	 = "1.5.1"

# Before we do much else, we are going to
# suppress any warnings - these wreak havok
# on Windows.

if platform.system() == 'Windows':
	import warnings
	warnings.simplefilter('ignore')

# modules required for using GTK
import pygtk
pygtk.require('2.0')
import gtk
import gobject

# Now for our own modules
# =======================

# First try to import the native app
# indicator module. Failing that, use our
# fallback module instead.
try:
	import appindicator
except ImportError:
	import appindicator_replacement as appindicator

# Do the exact same thing with pynotify.
# Use our fallback module if it's not available
try:
	import pynotify
except ImportError:
	import pynotify_replacement as pynotify

# Initialize PyNotify
pynotify.init('StackApplet')

# ... the rest of them.
import config_store    # stores configuration settings / data
import defaults        # list of default settings
import network_thread  # for making anychronous network requests to the API
import preferences     # a web server that allows preferences to be changed

# Messaging menu support requires
try:
	import pymm
	CAN_USE_MM = 1
	
except ImportError:
	CAN_USE_MM = 0

#=======================================
# This is the root class that contains
# all of the core logic for StackApplet
#=======================================
class stackapplet:
	
	# Our constructor
	def __init__ (self):
		
		# Before doing anything, we set the current language
		self.set_language()
		
		# Begin by creating the application indicator which we
		# use for displaying the icon.
		self.indicator = appindicator.Indicator ("stackapplet-desktop-client",
		                                         "stackapplet_grey",
		                                         appindicator.CATEGORY_APPLICATION_STATUS)
		
		self.indicator.set_status(appindicator.STATUS_ACTIVE)
		self.indicator.set_attention_icon("stackapplet")
		
		# Create the settings object so that we
		# can retrieve the list of accounts, preferences,
		# and so on.
		self.prefs = config_store.config_store()
		self.prefs.load_settings()
		
		self.refresh_rate = self.prefs.get_val("refresh_rate", defaults.__default_refresh_rate__)
		language          = self.prefs.get_val("language",     defaults.__default_language__)
		
		if not language == "":
			self.set_language(language)
		
		# Determine which icon set to use.
		if self.prefs.get_val("theme", defaults.__default_theme__) == 'dark':
			icon_to_use = 'stackapplet_grey'
		else:
			icon_to_use = 'stackapplet_light'
		
		self.indicator.set_icon(icon_to_use)
		
		# Create the menus for the accounts
		self.initialize_menu()
		
		# Create the messaging menu entry as well.
		if CAN_USE_MM:
			self.mm = pymm.pymm("/usr/share/applications/stackapplet.desktop")
		
		# Create the threaded network manager
		self.network = network_thread.network_thread(self.process_error)
		
		# Immediately get it fetching the list of sites.
		self.stackauth = None
		self.network.issue_request("http://stackauth.com/1.0/sites?key=" + network_thread.API_KEY,
		                           self.process_stackauth,
		                           None,
		                           True,
		                           1)
		
		# Register one of our member functions with
		# the preference server so that we can supply
		# the requested details as necessary.
		preferences.register_callback(self.preference_callback)
		
		# Finally, begin updating the accounts.
		self.timer = None
		self.update()
	
	# If language == "", then the system default is used
	def set_language(self, language=""):
		
		# Bind the domain
		if not platform.system() == 'Windows':
			gettext.bindtextdomain("stackapplet", "/usr/share/locale")
		
		gettext.textdomain("stackapplet")
		
		if language == None:
			
			# Figure out the system locale
			(lang, enc) = locale.getdefaultlocale()
			
			# Set it to a sensible default if we couldn't
			# figure it out otherwise
			if lang == "":
				lang = "en_US"
		
		else:
			lang = language
		
		# Now create the translation object and
		# register the translation function
		if platform.system() == 'Windows':
			tr = gettext.translation("stackapplet",
									 "po",
									 [lang],
									 fallback=True)
		else:
			tr = gettext.translation("stackapplet",
									 "/usr/share/locale",
									 [lang],
									 fallback=True)
		
		# Now apply tr to our _ shortcut
		global _
		_ = tr.gettext
	
	def initialize_menu(self):
		
		# Create the root GTK menu
		self.root_menu = gtk.Menu()
		
		# Create the Accounts and Tools
		# menu headers
		menu_item_accounts_header = gtk.MenuItem(_("Accounts"))
		menu_item_accounts_header.set_sensitive(False)
		menu_item_accounts_header.show()
		self.root_menu.append(menu_item_accounts_header)
		
		# Now add the accounts to the list.
		# The return value tells us if any accounts
		# were added, and if so, we add a separator
		if self.populate_menu():
			separator = gtk.SeparatorMenuItem()
			separator.show()
			self.root_menu.append(separator)
			
		else:
			menu_item_accounts_header.set_label(_("No Accounts"))
		
		# Now we add the remaining menu items
		menu_item_tools_header = gtk.MenuItem(_("Tools"))
		menu_item_tools_header.set_sensitive(False)
		menu_item_tools_header.show()
		self.root_menu.append(menu_item_tools_header)
		
		# For these items, we can use the stock
		# GTK menuitems
		menu_item_refresh = gtk.ImageMenuItem(stock_id=gtk.STOCK_REFRESH)
		menu_item_prefs   = gtk.ImageMenuItem(stock_id=gtk.STOCK_PREFERENCES)
		menu_item_about   = gtk.ImageMenuItem(stock_id=gtk.STOCK_ABOUT)
		menu_item_quit    = gtk.ImageMenuItem(stock_id=gtk.STOCK_QUIT)
		
		menu_item_refresh.connect("activate", self.menu_refresh_activate)
		menu_item_prefs  .connect("activate", self.menu_prefs_activate)
		menu_item_about  .connect("activate", self.menu_about_activate)
		menu_item_quit   .connect("activate", self.menu_quit_activate)
		
		menu_item_refresh.show()
		menu_item_prefs  .show()
		menu_item_about  .show()
		menu_item_quit   .show()
		
		# Add them all to the menu
		self.root_menu.append(menu_item_refresh)
		self.root_menu.append(menu_item_prefs)
		self.root_menu.append(menu_item_about)
		self.root_menu.append(menu_item_quit)
		
		self.indicator.set_menu(self.root_menu)
	
	def populate_menu(self):
		
		# Reset our accounts container
		self.accounts = []
		
		# Loop through each of the accounts in the list
		entries = self.prefs.get_val("accounts", defaults.__default_accounts__)
		accounts_processed = 0
		
		for entry in entries:
			
			self.create_menu_item(entry)
			accounts_processed += 1
		
		return accounts_processed
	
	def create_menu_item(self, entry):
		
		# Create the menu item
		menu_entry = gtk.MenuItem()
		menu_entry.set_label(_("Loading..."))
		
		# Add it to the menu
		menu_entry.show()
		self.root_menu.insert(menu_entry, 1 + len(self.accounts))
		
		# Create the messaging menu entry
		if CAN_USE_MM:
			mm_source = pymm.pymm_source(entry["site_name"])
			mm_source.set_count(0)
		else:
			mm_source = None
		
		# Now we need to check and see what values
		# are present in the configuration file.
		reputation_on_last_poll = entry['reputation_on_last_poll'] if 'reputation_on_last_poll' in entry else 0
		last_comment_ts         = entry['last_comment_ts']         if 'last_comment_ts'         in entry else 0
		last_answer_ts          = entry['last_answer_ts']          if 'last_answer_ts'          in entry else 0
		unread_reputation       = entry['unread_reputation']       if 'unread_reputation'       in entry else 0
		unread_comments         = entry['unread_comments']         if 'unread_comments'         in entry else 0
		unread_answers          = entry['unread_answers']          if 'unread_answers'          in entry else 0
		notifications           = entry['notifications']           if 'notifications'           in entry else 0
		
		account = { "menu"      : menu_entry,           # the Gtk menu
		            "mm_source" : mm_source,            # the Messaging menu source
		            "site"      : entry['site'],        # the URL of the SE site with this account
		            "site_name" : entry['site_name'],   # the name of the SE site
		            "user_id"   : entry['user_id'],     # the user ID for the site
		            
		            "reputation_on_last_poll"   : reputation_on_last_poll, # the API will never return 0, so this is safe
		            "last_comment_ts"           : last_comment_ts,         # the last timestamp for comments to user
		            "last_answer_ts"	        : last_answer_ts,          # the last timestamp for answers to questions
		            "unread_reputation"         : unread_reputation,       # the amount of rep. earned that hasn't been seen
		            "unread_comments"           : unread_comments,         # the num. of comments that haven't been seen
		            "unread_answers"	        : unread_answers,          # the num. of answers that haven't been seen
		            "notifications"             : notifications }          # whether this item has notifications or not
		
		# If there are any notifications, display
		# the indicator.
		if notifications:
			self.activate_notification(account)
		
		# Set the handlers
		menu_entry.connect("activate", self.menu_item_activate, account)
		
		if CAN_USE_MM:
			mm_source.source.connect("user-display", self.messaging_item_activate, account)
		
		# Add this item to our account list
		self.accounts.append(account)
	
	def process_stackauth(self, data, ignored):
		
		self.stackauth = data
	
	def display_notification(self, title, message, image):
		
		# The image in this case is expected to either
		# be an icon name (in which case we display it)
		# or a complete URL (in which case we fetch it)
		if image.startswith("/"):
			
			# Local path, so display it.
			n = pynotify.Notification(title, message, image)
			n.show()
				
		else:
		
			# Check to see if this image is in the cache
			img_path = os.path.join(os.path.expanduser("~"),".stackapplet")
			img_path = os.path.join(img_path, 'logos')
			img_fn = os.path.join(img_path, image + ".png")
			
			if os.path.isfile(img_fn):
			
				# It's in the cache, so simply display
				# the image.
				n = pynotify.Notification(title, message, img_fn)
				n.show()
			
			else:
			
				# Make sure that the dir exists
				if not os.path.isdir(img_path):
					os.makedirs(img_path)
				
				# We need to determine which site is equivalent to this image.
				for site in self.stackauth['api_sites']:
					
					if site['site_url'] == 'http://' + image + '.com':
						
						self.network.issue_request(site['icon_url'],
						                           self.save_and_display_notification,
						                           { 'title': title,
						                             'message': message,
						                             'image_location': img_fn},
						                           False)
					
	def save_and_display_notification(self, data, info):
	
		# Dump data to the file.
		f = open(info['image_location'], "wb")
		f.write(data)
		f.close()
		
		self.display_notification(info['title'],
		                          info['message'],
		                          info['image_location'])
	
	def activate_notification(self, account):
		
		# Set the color of our indicator
		self.indicator.set_status(appindicator.STATUS_ATTENTION)
		
		# Also set the active state of the messaging menu
		if CAN_USE_MM:
			account['mm_source'].set_notify(True)
	
	# Check to see if there are any pending notifications
	# for any of the accounts.
	def test_notifications(self):
		
		any_notifications = 0
		
		for account in self.accounts:
			
			if account['notifications']:
			
				if CAN_USE_MM:
					account['mm_source'].set_notify(True)
				
				any_notifications = 1
			
			else:
				
				if CAN_USE_MM:
					account['mm_source'].set_notify(False)
		
		if any_notifications:
			self.indicator.set_status(appindicator.STATUS_ATTENTION)
		else:
			self.indicator.set_status(appindicator.STATUS_ACTIVE)
	
	# Process an error that we receive from the
	# network thread
	def process_error(self, data, error_str):
	
		# If it's an account, then at least
		# display a notification in that account
		# that there was an error retrieving the data.
		if data in self.accounts:
			
			data['menu'].set_label(error_str)
	
	# This function is responsible for dispatching
	# the API requests and making sure that when the
	# requests are completed that they are processed
	# by the right functions.
	def update(self):
		
		# Remove the current timer
		if(not self.timer == None):
			gobject.source_remove(self.timer)
		
		for account in self.accounts:
			
			self.update_account(account)
		
		# Now run the update again after the specified
		# timeout has been reached
		self.timer = gobject.timeout_add(self.refresh_rate, self.update)
	
	def update_account(self, account):
		
		# Start by dispatching a request to get the
		# current reputation for this account.
		self.network.issue_api_request(account['site'],
		                               '/users/' + account['user_id'],
		                               self.update_reputation,
		                               account)
		
		self.network.issue_api_request(account['site'],
		                               '/users/' + account['user_id'] + '/mentioned',
		                               self.update_comments,
		                               account,
		                               'fromdate=' + str(account["last_comment_ts"]))
		
		self.network.issue_api_request(account['site'],
		                               '/users/' + account['user_id'] + '/questions',
		                               self.update_answers_1,
		                               account)
	
	def update_reputation(self, data, account):
		
		# First make sure that the account still exists
		if not account in self.accounts:
			return
		
		# First check to see if there is any new reputation
		current_rep = data['users'][0]['reputation']
		
		# Check to see if there has been a change
		if not current_rep == account['reputation_on_last_poll'] and not account['reputation_on_last_poll'] == 0:
			
			# Calculate the change
			change = current_rep - account['reputation_on_last_poll']
			
			# Add this new reputation to the amount of reputation
			# that the user has not seen yet.
			account['unread_reputation'] += change
			
			# Display a notification
			if change > 0:
				message = _("You have gained %s reputation.") % (change)
			else:
				message = _("You have lost %s reputation.") % (abs(change))
			
			self.display_notification(account["site_name"] + ":", message, account['site'])
			
			# Last but not least, we need to set that this item
			# has a pending unread notification
			account['notifications'] = 1
			
			self.activate_notification(account)
			
		# Update the menu captions
		self.set_menu_label(account, current_rep)
			
		# Set this as the new reputation.
		account['reputation_on_last_poll'] = current_rep
	
	def update_comments(self, data, account):
		
		# First make sure that the account still exists
		if not account in self.accounts:
			return
		
		if len(data['comments']) and account["last_comment_ts"]:
			
			# We know there is one or more comments
			
			if len(data['comments']) == 1:
				message = _("%s has posted a comment to you.") % (data['comments'][0]["owner"]["display_name"])
			else:
				message = _("You have received %s new comments.") % (len(data['comments']))
			
			self.display_notification(account["site_name"] + ":", message, account['site'])
			
			account['unread_comments'] += len(data['comments'])
			account['notifications'] = 1
			
			self.set_menu_label(account, account['reputation_on_last_poll'])
			
			self.activate_notification(account)
		
		# Set the timestamp
		account["last_comment_ts"] = int(time.time())
	
	def update_answers_1(self, data, account):
		
		# First make sure that the account still exists
		if not account in self.accounts:
			return
		
		# We are only half of the way there. We have the users'
		# questions... now get the answers to those questions.
		
		# Create a vectorized list of question ids
		id_array = []
		
		for question in data['questions']:
			id_array.append(str(question["question_id"]))
		
		if len(id_array) and account["last_answer_ts"]:
			
			# Join the IDs
			id_str = ";".join(id_array)
			
			# Issue the second part of the request
			self.network.issue_api_request(account['site'],
				                           '/questions/' + id_str + '/answers',
				                           self.update_answers_2,
				                           account,
				                           'fromdate=' + str(account["last_answer_ts"]))
				                           
			# ...and the third part - which will get us a list
			# of comments to the question list we have
			self.network.issue_api_request(account['site'],
				                           '/posts/' + id_str + '/comments',
				                           self.update_post_comments,
				                           account,
				                           'fromdate=' + str(account["last_answer_ts"]))
		
		# Set the timestamp
		account["last_answer_ts"] = int(time.time())
	
	def update_answers_2(self, data, account):
		
		# First make sure that the account still exists
		if not account in self.accounts:
			return
		
		# See if there are any new answers
		if len(data['answers']):
			
			# Display a notification
			message = _("Your have received %s new answer(s) to your questions.") % (len(data['answers']))
			self.display_notification(account["site_name"] + ":", message, account['site'])
			
			account['unread_answers'] += len(data['answers'])
			account['notifications'] = 1
			
			self.set_menu_label(account, account['reputation_on_last_poll'])
			
			self.activate_notification(account)
	
	def update_post_comments(self, data, account):
		
		# See if there are any comments that matched the criterion
		
		# First make sure that the account still exists
		if not account in self.accounts:
			return
		
		# We know there is one or more comments but are they
		# comments that were made by that user?
		for comment in data['comments']:
			if int(account['user_id']) == comment["owner"]["user_id"]:
				data['comments'].remove(comment)
		
		if len(data['comments']):
			
			if len(data['comments']) == 1:
				message = _("%s has posted a comment on your question.") % (data['comments'][0]["owner"]["display_name"])
			else:
				message = _("You have received %s new comments to your question.") % (len(data['comments']))
			
			self.display_notification(account["site_name"] + ":", message, account['site'])
			
			account['unread_comments'] += len(data['comments'])
			account['notifications'] = 1
			
			self.set_menu_label(account, account['reputation_on_last_poll'])
			
			self.activate_notification(account)
		
		# Either way, save the account information
		self.save_account_info()
	
	def set_menu_label(self, account, reputation):
		
		# Construct the label we will be using for the account in the menu
		label = account['site_name'] + ' / ' + str(reputation)
		
		# Check for unread reputation
		if account['unread_reputation']:
			label += _(' [%s reputation]') % (account['unread_reputation'])
		
		# Check for comments
		if account['unread_comments']:
			label += _(' [%s comments]') % (account['unread_comments'])
		
		# Check for new answers
		if account['unread_answers']:
			label += _(' [%s answers]') % (account['unread_answers'])
		
		if account['notifications']:
			label = "* " + label
		
		account['menu'].set_label(label)
		
		# Don't forget about the MM
		if CAN_USE_MM:
			account['mm_source'].set_count(account['unread_comments'] + account['unread_answers'])
	
	def preference_callback(self, command, event, data):
		
		# Process the request that was made
		if command == 'get_settings':
		
			data['accounts']     = self.accounts[:]
			data['theme']        = str(self.prefs.get_val('theme', defaults.__default_theme__))
			data['refresh_rate'] = int(self.refresh_rate)
			data['language']     = str(self.prefs.get_val('language', defaults.__default_language__))
		
		elif command == 'get_translation':
			
			global _
			data['translation'] = _
			
		elif command == 'add_account':
			
			# Add the account
			self.create_menu_item(data)
			
			self.update_account(self.accounts[len(self.accounts) - 1])
			
		elif command == 'remove_account':
			
			index = int(data)
			
			# Remove the menu item and MM entry
			self.root_menu.remove(self.accounts[index]['menu'])
			
			if CAN_USE_MM:
				del self.accounts[index]['mm_source']
			
			# Delete the account
			del self.accounts[index]
			
			self.test_notifications()
		
		elif command == 'reorder':
			
			# We need to grab a copy of the item
			account = self.accounts[int(data['old_index'])]
			
			# Now remove it from the list
			self.accounts.remove(account)
			
			# Insert it into its new location
			self.accounts.insert(int(data['new_index']), account)
			
			# We also need to switch the menu items around too.
			self.root_menu.remove(account['menu'])
			self.root_menu.insert(account['menu'], 1 + int(data['new_index']))
		
		elif command == 'set_rate':
			
			self.refresh_rate = int(data)
			
			self.prefs.set_val('refresh_rate', int(data))
		
		elif command == 'set_theme':
			
			if data == 'dark':
				icon_to_use = 'stackapplet_grey'
			else:
				icon_to_use = 'stackapplet_light'
			
			self.indicator.set_icon(icon_to_use)
			self.prefs.set_val('theme', str(data))
		
		elif command == 'set_language':
			
			self.set_language(str(data))
			self.prefs.set_val('language', str(data))
		
		# Set the event to allow the other thread
		# to continue along.
		event.set()
	
	def menu_item_activate(self, widget, account):
		
		# We need to either reset any unread stuff
		# or if there isn't any, then launch the user's
		# profile page.
		if account['notifications']:
			
			# Reset everything.
			account['notifications']     = 0
			account['unread_reputation'] = 0
			account['unread_comments']   = 0
			account['unread_answers']    = 0
			
			# Reset the menu caption
			self.set_menu_label(account, account['reputation_on_last_poll'])
			
			# Recheck for global notifications
			self.test_notifications()
		
		# Otherwise, display their profile page
		else:
			
			webbrowser.open("http://" + account["site"] + ".com/users/" + str(account["user_id"]))
	
	# Note that I have no clue what the third parameter is since
	# it is not documented ANYWHERE.
	def messaging_item_activate(self, indicator, unknown_data, account):
		
		# Just turn around and call menu_item_activate
		self.menu_item_activate(None, account)
	
	def menu_refresh_activate(self, widget):
		
		self.update()
	
	def menu_prefs_activate(self, widget):
		
		preferences.trigger()
	
	def menu_about_activate(self, widget):
		
		global _,__application__,__author__,__copyright__,__license__,__version__
		
		# Display the about dialog box
		dialog = gtk.AboutDialog()
		
		dialog.set_name(_(__application__))
		dialog.set_authors(__authors__)
		dialog.set_artists(__artists__)
		dialog.set_translator_credits(_(__translators__))
		dialog.set_copyright(_(__copyright__))
		dialog.set_license(_(__license__))
		dialog.set_version(__version__)
		
		if platform.system() == 'Windows':
			dialog.set_logo(gtk.gdk.pixbuf_new_from_file(os.path.join(os.path.dirname(sys.executable), "images/stackapplet.png")))
		else:
			dialog.set_logo_icon_name("stackapplet")
		
		dialog.connect("response",lambda x,y: dialog.destroy())
		
		dialog.run()
	
	def menu_quit_activate(self, widget):
		
		self.shutdown()
		
	# Saves all account information
	def save_account_info(self):
		
		# Save the accounts
		accounts_data = []
		
		for account in self.accounts:
			
			# Take a copy
			copy_of_account = dict(account)
			
			# Remove two items
			del copy_of_account['menu']
			del copy_of_account['mm_source']
			
			accounts_data.append(copy_of_account)
		
		self.prefs.set_val('accounts', accounts_data)
		self.prefs.save_settings()
	
	# This is the safe shutdown function that
	# ensures all accounts' notification data
	# are saved with the accounts' information.
	def shutdown(self):
		
		# We need the network thread to shutdown.
		self.network.request_queue.put([0, None])
		self.network.join()
		
		# ...and we need the preferences thread to
		# shutdown.
		preferences.httpd.shutdown()
		preferences.thread.join()
		
		self.save_account_info();
		
		gtk.main_quit()

stackapplet_instance = None

# Do a quick check for old config files
if os.path.isfile(config_store.CONFIG_FILE_PATH):
	
	dialog = gtk.MessageDialog(None,
		                       gtk.DIALOG_MODAL,
		                       gtk.MESSAGE_INFO,gtk.BUTTONS_OK,
		                       _("StackApplet 1.5.1 has found some old configuration files from a previous version of StackApplet.\n\nThese files will be removed so that StackApplet can continue loading. If you had any accounts registered with StackApplet, you will need to add them again.\n\nNote: StackApplet is no longer a Gnome panel applet. It is an indicator and can be located in your system's notification or tray area."))
	dialog.set_title(_("StackApplet has been upgraded:"))
	dialog.connect("response", lambda x,y: dialog.destroy())
	dialog.run()

	# Delete the old files
	os.remove(config_store.CONFIG_FILE_PATH)

# SIGTERM handler
def signal_handler(a, b):
	
	global stackapplet_instance
	stackapplet_instance.shutdown()

# Create the instance of stackapplet and
# run the main GTK thread
if __name__ == "__main__":

	stackapplet_instance = stackapplet()

	# For Windows, we need our helper module
	if platform.system() == 'Windows':
		import w32_notifications
		w32_notifications.register_main_instance(stackapplet_instance)
	
	signal.signal(signal.SIGTERM, signal_handler)
		
	gtk.main()
