#!/usr/bin/env python2.5
# -*- coding: utf-8 -*-
#
#       shoplist.py
#
#       Copyright 2010 César Themudo <cthemudo@yahoo.es>
#
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import sqlite3
import uuid
import gtk
import hildon
import sys
import shutil
import os
import gobject

class AppProp():
	APP_NAME    = 'Shop List'
	APP_VERSION = '0.4'
	APP_AUTHORS = ['César Themudo <cthemudo@yahoo.es>']
	APP_COMMENT = 'Shoplist is a tool that helps you remember things to buy.\n'\
		'Also will help you remember other details such as how many units you have to buy, the price and where.\n'\
		'All in an easy and intuitive.'
	APP_COPYRIGHT = 'Copyright © 2010 César Themudo'
	APP_LICENSE   = 'GNU Public License\n'\
		'http://www.gnu.org/licenses/gpl.html'

	ICON_FOLDER = 'share/icons/hicolor/scalable/hildon'
	ICON_APP = os.path.join(sys.prefix, ICON_FOLDER, 'shoplist.png')

	DB_NAME = '.shoplist.db'

	MONEY = '€'

#PROPERTIES OF APP
PROPS_APP = None
#PROPERTIES OF ITEMS
PROPS_ITEMS = None
#PROPERTIES OF SHOPS
PROPS_SHOPS = None

def main():
	gtk.set_application_name(AppProp.APP_NAME)

	win = ShoplistAppWindow()
	#Arranque acelerado
	win.show_all()
	while gtk.events_pending():
		gtk.main_iteration()

	#Base de datos
	db = ShoplistDatabase()
	win.database = db
	load_properties(db)
	#db.fill_example()

	rotation_object = FremantleRotation(AppProp.APP_NAME, win,
		AppProp.APP_VERSION, FremantleRotation.AUTOMATIC)
	gtk.main()
	return 0

def load_properties(database):
	global PROPS_APP
	global PROPS_ITEMS
	global PROPS_SHOPS

	AppProp.MONEY = database.get_config('currency', '€')
	
	#PROPERTIES OF APP
	PROPS_APP = [
		Property("Currency", "config", "value", ['€','$','¥','£','¤','¢','f','₣','Fr''₧'], '', 'currency'),
		]
	#PROPERTIES OF ITEMS
	PROPS_ITEMS = [
		Property("Name",    "elements", "name", None),
		Property("Quantity","elements", "quantity", ['',1,2,3,4,5,6,7,8,9,10,12,15,20,15,30,40,50,60,70,80,90,100]),
		Property("Unit",    "elements", "unit", ['','ud','litres','kg','carton','can','dozen','package','bag','box','tin','gr']),
		Property("Price",   "elements", "price", ['',1.00,2.00,3.00,4.00,5.00,6.00,7.00,8.00,9.00,10.00,12.00,15.00,20.00,15.00,30.00,40.00,50.00,60.00,70.00,80.00,90.00,100.00], AppProp.MONEY),
		]
	#PROPERTIES OF SHOPS
	PROPS_SHOPS = [
		Property("Name", "shops", "name", None),
		]

def about_dialog(parent):
	about_dialog = AboutDialog(parent)
	about_dialog.set_logo(AppProp.ICON_APP)
	about_dialog.set_name(AppProp.APP_NAME)
	about_dialog.set_version(AppProp.APP_VERSION)
	about_dialog.set_comments(AppProp.APP_COMMENT)
	about_dialog.set_authors(AppProp.APP_AUTHORS)
	about_dialog.set_copyright(AppProp.APP_COPYRIGHT)
	about_dialog.set_license(AppProp.APP_LICENSE)
	about_dialog.run()
	about_dialog.destroy()

########################################################################
#######################################################   VENTANAS   ###
########################################################################
####   ShoplistAppWindow
class ShoplistAppWindow(hildon.StackableWindow):
	database = None
	__main_menu = []
	__vbox = None
	__hbox = None

	def __init__(self):
		super(ShoplistAppWindow, self).__init__()
		self.set_border_width(30)
		self.connect("destroy", gtk.main_quit)
		self.connect("expose-event", self.__on_expose_event, None)
		self.set_title(AppProp.APP_NAME)
		self.__add_main()
		self.__add_menu()

	def __add_menu(self):
		#Menu
		menu = hildon.AppMenu()
		# Create a button and add it to the menu
		button = gtk.Button("Edit item...")
		button.connect("clicked", self.__edit_item_clicked, self)
		menu.append(button)
		# Create a button and add it to the menu
		button = gtk.Button("Edit shop...")
		button.connect("clicked", self.__edit_shop_clicked, self)
		menu.append(button)
		# Create a button and add it to the menu
		button = gtk.Button("Config...")
		button.connect("clicked", self.__config_clicked, self)
		menu.append(button)
		# Create a button and add it to the menu
		button = gtk.Button("About...")
		button.connect("clicked", self.__about_clicked, self)
		menu.append(button)
		# Show all menu items
		menu.show_all()
		# Add the menu to the window
		self.set_app_menu(menu)

	def __add_main(self):
		self.add(self.__create_main_menu())
		self.__create_main_menu_button("Shop List","Items to buy", MainMenuOptions.SHOPLIST)
		self.__create_main_menu_button("Go shopping","Select shop where to buy", MainMenuOptions.GOSHOPPING)

	def __create_main_menu(self):
		vbox = gtk.VBox(False, 10)

		self.__hbox = gtk.HBox(False, 0)
		self.__hbox.set_border_width(60)
		self.__hbox.set_homogeneous(True)
		vbox.pack_start(self.__hbox, False, False, 0)

		self.__vbox = gtk.VBox(False, 0)
		self.__vbox.set_border_width(60)
		self.__vbox.set_homogeneous(True)
		vbox.pack_start(self.__vbox, False, False, 0)

		return vbox

	def __edit_item_clicked(self, widget, userdata):
		ei =EditItem(self, self.database, ItemType.ITEM)
		ei.run()

	def __edit_shop_clicked(self, widget, userdata):
		ei =EditItem(self, self.database, ItemType.SHOP)
		ei.run()

	def __config_clicked(self, widget, userdata):
		edit_props = EditProperties(
			self,
			self.database,
			PROPS_APP,
			None)
		edit_props.run()
		load_properties(self.database)
		

	def __about_clicked(self, widget, userdata):
		about_dialog(userdata)

	def __create_main_menu_button(self, title, subtitle, action):
		self.__hbox.pack_start(self.__create_button(title, subtitle, action),expand=True, fill=True)
		self.__vbox.pack_start(self.__create_button(title, subtitle, action),expand=True, fill=True)

	def __create_button(self, title, subtitle, action):
		box = gtk.VBox()
		box.set_border_width(20)

		button = hildon.Button(gtk.HILDON_SIZE_THUMB_HEIGHT,
							   hildon.BUTTON_ARRANGEMENT_VERTICAL,
							   title, subtitle)
		button.connect('clicked', self.__button_clicked, action)

		box.pack_start(button, expand=True, fill=False)

		self.__main_menu.append(box)
		return box

	def __on_expose_event(self, widget, event, userdata):
		(width, height) = event.window.get_size()
		if width > height:
			#Horizontal
			self.__hbox.show()
			self.__vbox.hide()
		else:
			#Vertica
			self.__vbox.show()
			self.__hbox.hide()

	def __button_clicked(self, widget, userdata):
		if userdata == MainMenuOptions.SHOPLIST:
			shoplist = ShoplistWindow(
							self.database,
							'SELECT "id", "buy", "name", "quantity", "price", "unit" '
							'FROM "elements" '
							'ORDER BY "buy" DESC, "name" ASC;')
			shoplist.show_all();
		elif userdata == MainMenuOptions.GOSHOPPING:
			go_to_shop = GoShoppingWindow(self.database)
			go_to_shop.show_all()

###   ShoplistWindow
class ShoplistWindow(hildon.StackableWindow):
	__database = None
	__SQLcmd = None
	__list = None

	def __init__(self, database, SQLcmd):
		super(ShoplistWindow, self).__init__()
		self.__database = database
		self.__SQLcmd = SQLcmd
		self.set_title("Shop list")
		self.set_border_width(6)
		self.__add_menu()
		self.__add_main()

	def __add_menu(self):
		#Menu
		menu = hildon.AppMenu()
		# Create a button and add it to the menu
		button = gtk.Button("Edit item...")
		button.connect("clicked", self.__edit_item_clicked, self)
		menu.append(button)
		# Create a button and add it to the menu
		button = gtk.Button("Revert")
		button.connect("clicked", self.__update_clicked, self)
		menu.append(button)
		# Create a button and add it to the menu
		button = gtk.Button("About...")
		button.connect("clicked", self.__about_clicked, self)
		menu.append(button)
		# Show all menu items
		menu.show_all()
		# Add the menu to the window
		self.set_app_menu(menu)

	def __add_main(self):
		vbox = gtk.VBox(False, 10)
		self.add(vbox)
		self.__list = TreeItems(self.__database,self.__SQLcmd)
		self.connect("destroy", self.__list.save_changes, None)
		vbox.add(self.__list)

	def __edit_item_clicked(self, widget, userdata):
		ei =EditItem(self, self.__database, ItemType.ITEM)
		ei.run()
		self.__list.save_changes(self.__list, None)
		self.__list.update()

	def __update_clicked(self, widget, userdata):
		self.__list.update()

	def __about_clicked(self, widget, userdata):
		about_dialog(userdata)

###   GoShoppingWindow
class GoShoppingWindow(hildon.StackableWindow):
	__database = None
	__list = None

	def __init__(self, database):
		super(GoShoppingWindow, self).__init__()
		self.__database = database
		self.set_title("Shops")
		self.set_border_width(6)
		self.__add_menu()
		self.__add_main()

	def __add_menu(self):
		#Menu
		menu = hildon.AppMenu()
		# Create a button and add it to the menu
		button = gtk.Button("Edit shop...")
		button.connect("clicked", self.__edit_shop_clicked, self)
		menu.append(button)
		# Create a button and add it to the menu
		button = gtk.Button("About...")
		button.connect("clicked", self.__about_clicked, self)
		menu.append(button)
		# Show all menu items
		menu.show_all()
		# Add the menu to the window
		self.set_app_menu(menu)

	def __add_main(self):
		vbox = gtk.VBox(False, 10)
		self.add(vbox)
		ls = ListShops(self.__database,
			'SELECT DISTINCT '
			'	"shops"."id"   AS "id", '
			'	"shops"."name" AS "shop", '
			'	COUNT( "elements"."name" ) AS "quantity", '
			'	SUM(   "elements"."price"*"elements"."quantity") AS "total", '
			'   SUM(   "elements"."price"/"elements"."price") AS "no_null"'
			'FROM "elements_in_shops", "elements", "shops" '
			'WHERE "elements_in_shops"."id_element" = "elements"."id" '
			'	AND "shops"."id" = "elements_in_shops"."id_shop" '
			'	AND "elements"."buy" > 0 '
			'GROUP BY "shops"."name"',
			'SELECT '
			'	Null as id, '
			'	Null as shop, '
			'	Count (elements.id) AS "quantity", '
			'	SUM(elements.price*elements.quantity) AS "total", '
			'   SUM(elements.price/elements.price) AS "no_null" '
			'FROM elements LEFT JOIN elements_in_shops ON elements.id = elements_in_shops.id_element '
			'WHERE (elements.buy > 0 '
			'		AND ((elements_in_shops.id_shop) Is Null))'
		)
		vbox.add(ls)
		self.__list = ls

	def __edit_shop_clicked(self, widget, userdata):
		self.__list.freeze()
		ei =EditItem(self, self.__database, ItemType.SHOP)
		ei.run()
		self.__list.update()
		self.__list.unfreeze()

	def __about_clicked(self, widget, userdata):
		about_dialog(userdata)

########################################################################
#########################################################   CLASES   ###
########################################################################
####   ShoplistDatabase
class ShoplistDatabase:
	con = None

	def __init__(self):
		self.__get_database()

	def __get_database(self):
		os.chdir(os.path.expanduser('~'))
		new_db = False
		if not os.path.isfile(AppProp.DB_NAME): new_db = True
		self.con = sqlite3.connect(AppProp.DB_NAME)
		self.__check_tables()
		if new_db: self.fill_example()

	def __check_tables(self):
		self.table_create_if_no_exists("elements",
			( "'id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL",
			  "'name' TEXT NOT NULL DEFAULT ('Elemento x')",
			  "'buy' INTEGER NOT NULL DEFAULT (0)",
			  "'quantity' REAL",
			  "'unit' TEXT",
			  "'price' REAL",
			))
		self.table_create_if_no_exists("shops",
			( "'id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL",
			  "'name' TEXT NOT NULL DEFAULT ('Tienda x')",
			))
		self.table_create_if_no_exists("elements_in_shops",
			( "'id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL",
			  "'id_shop'    INTEGER NOT NULL",
			  "'id_element' INTEGER NOT NULL",
			))
		self.table_create_if_no_exists("config",
			( "'id' TEXT PRIMARY KEY NOT NULL",
			  "'value' TEXT"
			))

	def table_new(self, tablename, fields):
		sFields = fields[0]
		for f in fields[1::]:
			sFields += ", " + f
		self.con.execute("CREATE TABLE %s (%s)" % (tablename, sFields))

	def table_exists(self, tablename):
		c = self.con.cursor()
		tbls = c.execute("SELECT name FROM sqlite_master")
		for row in tbls:
			if row[0] == tablename: return True
		return False

	def table_create_if_no_exists(self, tablename, fields):
		if not self.table_exists(tablename):
			self.table_new( tablename, fields)

	def SQLexec(self, cmdSQL, args = None, commit = None):
		c = self.con.cursor()
		if args == None: ret = c.execute(cmdSQL)
		else: ret = c.execute(cmdSQL, args)
		if commit or (commit == None and not args == None):
			self.con.commit()
			c.close()
		return ret

	def commit(self):
		self.con.commit()

	def fill_example(self):
		#Shops
		for shop in [('Supermarket',), ('Butcher shop',), ('Bakery',), ('Fruit shop',)]:
			self.SQLexec('INSERT INTO shops(name) VALUES (?)', shop, False)
		#Elements
		elems = [
			('Sugar', 1, 1.0,  'kg',      1.0),
			('Coffe', 1, 1.0,  'package', None),
			('Apples',0, 1.0,  'kg',      None),
			('Bread', 1, None, None,      0.8),
			('Meat',  0, None, 'kg',      6.0)]
		for elem in elems:
			self.SQLexec('INSERT INTO elements(name, buy, quantity, unit, price) VALUES (?, ?, ?, ?, ?)', elem, False)
		#Elements
		for rel in [(1,1), (1,2), (1,3), (1,4), (1,5), (2,5), (3,4), (4,3)]:
			self.SQLexec('INSERT INTO elements_in_shops(id_shop, id_element) VALUES (?, ?)', rel, False)
		self.commit()

	def str(self, text):
		if text == None or text == '': return None
		else: return str(text)

	def get_config(self, key, default=None):
		elems = self.SQLexec('SELECT value FROM config WHERE id == ?', (key,))
		res = elems.fetchone()
		if res == None:
			#print "No se encuentra %s" % key
			return default
		else: return self._convert(res[0],type(default))

	def set_config(self, key, value):
		tmp = self.get_config(key)
		if tmp == None:
			#print "Insertando %s, %s" % (key, str(value))
			self.SQLexec('INSERT INTO config(id, value) VALUES (?, ?)', (key, value,))
		else:
			#print "Actualizando %s, %s" % (key, str(value))
			self.SQLexec('UPDATE config SET value = ? WHERE id = ?;', (value, key,))
		self.commit()

	def _convert(self, value, _type):
		if value == None:    return None
		elif _type == None:  return value
		elif _type is int:   return int(value)
		elif _type is float: return float(value)
		elif _type is str:   return str(value)
		else: return value

####   TreeItems
class TreeItems(hildon.TouchSelector):
	__database = None
	__SQL_cmd = None
	__store = None

	def __init__(self, database, SQL_cmd):
		self.__database = database
		self.__SQL_cmd = SQL_cmd
		super(TreeItems, self).__init__()
		self.__store = self.__create_model()
		self.__create_treeview(self.__store)
		self.load_values()

	def __create_model(self):
		#                    ID,               Buy,              Nombre a mostrar
		return gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_INT, gobject.TYPE_STRING)

	def __create_treeview(self, store):
		# Create and set up a pixbuf renderer to use in the selector
		renderer = gtk.CellRendererText()
		# Add the column to the selector
		column = self.append_column(store, renderer)
		column.add_attribute(renderer, "markup", 2)
		column.set_property("text-column", 2)
		# Set the selection mode
		self.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE)

	def add_item(self, data):
		new_iter = self.__store.append();
		name = data[2] #'<b>'+data[2]+'</b>'
		info = self.__info_extra(data)
		if not info == '':
			name = name + '\n<span foreground=\"#babababababa\" size=\"small\">' + info + '</span>'
		#                            id          buy         Nombre
		self.__store.set(new_iter, 0, data[0], 1, data[1], 2, name)
		if data[1] > 0: self.select_iter(0,new_iter,False)

	def __info_extra(self, data):
		text = ''
		quantity = data[3]
		price = data[4]
		unit = data[5]
		if unit == None: unit = 'ud'
		if not quantity == None:
			text = text + str(quantity) + ' ' + unit
			if not price == None:
				total = quantity*price
				text = text + ' = ' + str(total) + ' ' + AppProp.MONEY
 		else:
			if not price == None:
				text = text + str(price) + ' ' + AppProp.MONEY + '/' + unit
		return text

	def load_values(self):
		elems = self.__database.SQLexec(self.__SQL_cmd)
		for row in elems:
			self.add_item(row)
		elems.close()
		if self.__store.iter_n_children(None) == 0:
			hildon.hildon_banner_show_information(self, 'kk', "Empty list!")

	def update(self):
		self.__store.clear()
		self.load_values()

	def save_changes(self, widget, userdata):
		model = self.get_model(0)
		path_list = self.get_selected_rows(0)
		iter = model.get_iter_first()
		while iter is not None:
			self.__update_iter(iter,path_list)
			iter = self.__store.iter_next(iter)
                self.__database.commit()

	def __update_iter(self, iter, path_list):
		path_iter= self.__store.get_path(iter)
		id       = self.__store.get_value(iter, 0)
		try:
			if path_list.index(path_iter) >= 0: selected = True
			else: selected = False
		except ValueError:
			selected = False
		if selected: buy = 1
		else: buy = 0
		self.__database.SQLexec('UPDATE elements SET buy = ? WHERE id = ?;', (buy, id,), False)

####   ListShops
class ListShops(hildon.TouchSelector):
#class ListShops(gtk.TreeView):
	__database = None
	__SQL_cmd = None
	__SQL_cmd_empty = None
	__block_select = False

	def __init__(self, database, SQL_cmd, SQL_cmd_empty):
		self.__database = database
		self.__SQL_cmd = SQL_cmd
		self.__SQL_cmd_empty = SQL_cmd_empty
		super(ListShops, self).__init__()
		self.__store = self.__create_model()
		self.__create_treeview(self.__store)
		self.__handler_signal = self.connect("changed", self.__selection_changed)
		#self.__handler_signal = self.connect("row-activated", self.__row_activated)
		self.load_values()

	def __create_model(self):
		#                    ID,               Name                 Nombre a mostrar
		return gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING)

	def __create_treeview(self, store):
		# Create and set up a pixbuf renderer to use in the selector
		renderer = gtk.CellRendererText()
		#column = gtk.TreeViewColumn('Name', renderer)
		column = self.append_column(store, renderer)
		column.add_attribute(renderer, "markup", 2)
		column.set_property("text-column", 1)

	def __selection_changed(self, selector, user_data):
		if self.__block_select == True: return
		if self.get_model(0).iter_n_children(None) == 0: return
		(model, iter) = self.get_selected(0)
		shop_id   = model.get_value(iter, 0)
		shop_name = model.get_value(iter, 1)
		if shop_name == None: return
		if shop_id >= 0:
			sl = ShoplistWindow(
				self.__database,
				'SELECT "elements"."id", '
				'	"elements"."buy", '
				'	"elements"."name", '
				'	"elements"."quantity", '
				'	"elements"."price", '
				'	"elements"."unit", '
				'	"shops"."name" AS "shop"'
				'FROM "elements_in_shops", "elements", "shops" '
				'WHERE 		"elements_in_shops"."id_element" = "elements"."id" '
				'		AND "shops"."id" = "elements_in_shops"."id_shop" '
				'		AND "elements"."buy" > 0 '
				'		AND "shops"."id" = ' + str(shop_id) + ' '
				'ORDER BY "elements"."buy" DESC, "elements"."name" ASC'
				)
		else:
			sl = ShoplistWindow(
				self.__database,
				'SELECT '
				'	elements.id, '
				'	elements.buy, '
				'	elements.name, '
				'	elements.quantity, '
				'	elements.price, '
				'	elements.unit, '
				'	Null as shop '
				'FROM elements LEFT JOIN elements_in_shops ON elements.id = elements_in_shops.id_element '
				'WHERE (elements.buy > 0 '
				'		AND ((elements_in_shops.id_shop) Is Null))'
				)
		sl.connect("destroy", self.__update_event, None)
		sl.set_title(shop_name)
		sl.show_all()
		#win_shop_list_in_marquet(current_selection)

	def __update_event(self, sender, userdata):
		self.freeze()
		self.update()
		self.unfreeze()

	def update(self):
		model = self.get_model(0)
		model.clear()
		self.load_values()

	def load_values(self):
		c = self.__database.con.cursor()
		elems = self.__database.SQLexec(self.__SQL_cmd)
		for row in elems:
			self.add_item(row)
		elems.close()
		elems = self.__database.SQLexec(self.__SQL_cmd_empty)
		for row in elems:
			if row[2] == 0: continue
			self.add_item(row)
		elems.close()
		if self.get_model(0).iter_n_children(None) == 0:
			hildon.hildon_banner_show_information(self, 'kk', "Empty shopping list!")

	def add_item(self, data):
		new_iter = self.__store.append();
		if data[0] == None: id = -1
		else:               id = data[0]
		if data[1] == None: text = 'Other'
		else:               text = data[1]
		name = text #'<b>'+text+'</b>'
		info = self.__info_extra(data)
		if not info == '':
			name = name + '\n<span foreground=\"#babababababa\" size=\"small\">' + info + '</span>'
		#                             id     Name	  Nombre+info
		self.__store.set(new_iter, 0, id, 1, text, 2, name)

	def __info_extra(self, data):
		text = ''
		quantity = data[2]
		money    = data[3]
		no_null  = data[4]
		price = data[3]
		if not quantity == None: text = text + ' ' + str(quantity) + ' items'
		if quantity == no_null and money !=None :  text = text + ' ' + str(money) + ' ' + AppProp.MONEY
		return text
	def freeze(self):
		self.handler_block
		self.__block_select = True
		
	def unfreeze(self):
		self.__block_select = False
		self.handler_unblock
		
####   EditItem
class EditItem(gtk.Dialog):
	__parent = None
	__database = None
	__element_table = None
	__element_field = None
	__relation_table = None
	__relation_field = None

	__store = None
	__tree_view = None
	__item_type = None

	__props = None

	def __init__(self, parent, database, item_type):
		self.__parent = parent
		self.__database = database
		super(EditItem, self).__init__(parent=parent, flags=gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL)
		self.__set_item_type(item_type)
		self.__create_dialog()
		self.connect("expose-event", self.__on_expose_event, None)
		self.show_all()
		#self.run()

	def __set_item_type(self, item_type):
		global PROPS_ITEMS
		global PROPS_SHOPS

		self.__item_type = item_type
		if item_type == ItemType.ITEM:
			self.__element_table = 'elements'
			self.__element_field = 'id_element'
			self.__relation_table = 'shops'
			self.__relation_field = 'id_shop'
			self.__props = PROPS_ITEMS
		else:
			self.__element_table = 'shops'
			self.__element_field = 'id_shop'
			self.__relation_table = 'elements'
			self.__relation_field = 'id_element'
			self.__props =  PROPS_SHOPS

	def __on_expose_event(self, widget, event, userdata):
		self.set_geometry_hints(self, 700,700)

	def __create_model(self):
		#                    ID,               Name                 Nombre a mostrar
		self.__store = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING)

	def __create_treeview(self):
		self.__tree_view = hildon.TouchSelectorEntry()
		# Create and set up a pixbuf renderer to use in the selector
		renderer = gtk.CellRendererText()
		#column = gtk.TreeViewColumn('Name', renderer)
		column = self.__tree_view.append_column(self.__store, renderer)
		column.add_attribute(renderer, "markup", 2)
		column.set_property("text-column", 1)

	def __create_dialog(self):
		self.set_title("Select one")
		self.set_default_response(EditFunctions.CANCEL)
		#self.add_button(gtk.STOCK_CANCEL, EditFunctions.CANCEL)
		self.add_button("gtk-add", EditFunctions.CREATE)
		self.add_button("gtk-delete", EditFunctions.DELETE)
		self.add_button("Properties", EditFunctions.PROPERTIES)
		self.add_button("Relations", EditFunctions.RELATIONS)
		self.set_default_size(-1,2000)

		# Create a touch selector entry
		self.__create_model()
		self.__create_treeview()
		self.vbox.pack_start(self.__tree_view, expand=True, fill=True)

	def update(self):
		self.__store.clear()
		self.__fill_selector()

	def __fill_selector(self):
		elems = self.__database.SQLexec('SELECT id, name FROM ' + self.__element_table + ' ORDER BY "name" ASC;')
		for row in elems:
			id = row[0]
			name = row[1]
			self.__add_element(id, name)
		elems.close()

	def __add_element(self, id, name):
		props = self.__get_properties_text(id)
		rels  = self.__get_relations_text(id)
		text = props + rels
		new_iter = self.__store.append();
		self.__store.set(new_iter, 0, id, 1, name, 2, text)


	def __get_properties_text(self, id):
		elems = self.__database.SQLexec(
			'SELECT ' + self.__join_props_fields() + ' '
			'FROM ' + self.__element_table + ' '
			'WHERE id == ?;', (id,))
		for i in elems:
			return i[0] + ': <span foreground=\"#babababababa\" size=\"small\">' + self.__join_props_sufix(i) + '</span>'


	def __get_relations_text(self, id):
		SQLcmd = ('SELECT ' + self.__relation_table + '.name '
			'FROM ' + self.__relation_table + ' INNER JOIN elements_in_shops '
			'	ON '+ self.__relation_table +'.id = elements_in_shops.' + self.__relation_field + ' '
			'WHERE (((elements_in_shops.' + self.__element_field + ')=' + str(id) + '));')
		elems = self.__database.SQLexec(SQLcmd)
		rels = []
		for i in elems:
			rels.append(i[0])
		return '\n<span foreground=\"#babababababa\" size=\"small\">' + self.__join(rels) + '</span>'

	def __join(self, list, separator = ', '):
		text = ''
		if len(list) > 0: text = str(list[0])
		for i in list[1:]:
			text += separator + str(i)
		return text

	def __join_props_sufix(self, list, separator1 = ' ', separator2 = ', '):
		text = ''
		if len(list) > 1:
			text = str(list[1])+separator1+self.__props[1].sufix
		for i in range(2,len(list)):
			text += separator2+str(list[i])+separator1+self.__props[i].sufix
		return text

	def __join_props_fields(self, separator = ', '):
		text = ''
		if len(self.__props) > 0:
			text = self.__props[0].field_name
		for i in self.__props[1:]:
			text += separator + i.field_name
		return text

	def run(self):
		while True:
			text = self.__tree_view.get_current_text()
			self.update()
			if not text == None:
				self.__tree_view.get_entry().set_text(text)
				self.__tree_view.center_on_selected()
			function = gtk.Dialog.run(self)
			text = self.__tree_view.get_current_text()
			if EditFunctions.CREATE == function:
				id = self.__create_element(text)
				if not id == None: self.__add_element(id, text)

			elif EditFunctions.DELETE == function:
				(model, iter) = self.__tree_view.get_selected(0)
				elem_id   = model.get_value(iter, 0)
				elem_name = model.get_value(iter, 1)
				self.__delete_element(elem_id, elem_name)

			elif EditFunctions.PROPERTIES == function:
				id = self.__get_id(text)
				if id == None:
					id = self.__create_element(text)
					if not id == None: self.__add_element(id, text)
				edit_props = EditProperties(
					self.__parent,
					self.__database,
					self.__props,
					self.__get_id(text))
				edit_props.run()

			elif EditFunctions.RELATIONS == function:
				id = self.__get_id(text)
				if id == None:
					id = self.__create_element(text)
					if not id == None:
						self.__fill_element(id, text)
				#EditRelations
				edit_rels = EditRelations(
					self.__parent,
					self.__database,
					id, text,
					not self.__item_type)
				edit_rels.run()
			else:
				break
		self.destroy()

	def __create_element(self, element):
		if element == '':
			hildon.hildon_banner_show_information_with_markup(self.__parent, 'kk', "I can't create empty element!")
			return None
		id = self.__get_id(element)
		if not id == None:
			hildon.hildon_banner_show_information_with_markup(self.__parent, 'kk', "<b><i>"+element+"</i></b> element exists!")
			return None
		note = hildon.Note(hildon.NOTE_TYPE_CONFIRMATION, self.__parent, "Create "+element+"?")
		retcode = gtk.Dialog.run(note)
		note.destroy()
		if retcode == gtk.RESPONSE_OK:
			self.__database.SQLexec('INSERT INTO '+self.__element_table+'(name) VALUES(?);', (element,))
			id = self.__get_id(element)
		return id

	def __delete_element(self, id, element):
		if id == None: return
		note = hildon.Note(hildon.NOTE_TYPE_CONFIRMATION, self.__parent, "Delete "+element+"?")
		retcode = gtk.Dialog.run(note)
		note.destroy()
		if retcode == gtk.RESPONSE_OK:
			self.__reset_relations(self.__element_field, id)
			self.__database.SQLexec('DELETE FROM '+self.__element_table+' WHERE id = ?;', (id,))

	def __reset_relations(self, field, element_id):
		self.__database.SQLexec('DELETE FROM elements_in_shops WHERE ? = ?;', (field, element_id,))

	def __get_id(self, element):
		elems = self.__database.SQLexec('SELECT id FROM ' + self.__element_table + ' WHERE name = ? ;', (element,))
		for row in elems:
			elems.close()
			return row[0]
		return None

####   EditProperties
class Property():
	name = None
	table_name = None
	field_name = None
	values = None
	sufix = ''
	id = None

	def __init__(self, name, table_name, field_name, values=None, sufix='', id=None):
		self.name = name
		self.table_name = table_name
		self.field_name = field_name
		self.values = values
		self.sufix = sufix
		self.id = id

####   EditProperties
class PropertyEntry(hildon.Entry):
	__database = None
	__property = None
	__id = None

	def __init__(self, parent, database, property,  id):
		self.__database = database
		self.__property = property
		self.__id = id

		super(PropertyEntry, self).__init__(gtk.HILDON_SIZE_AUTO)
		self.set_placeholder(self.__property.name)
		self.load_item()

	def load_item(self):
		if self.__id != None: id = self.__id
		else: id = self.property.id
		elems = self.__database.SQLexec('SELECT ' + self.__property.field_name + ' FROM ' + self.__property.table_name + ' WHERE id == ?;', (id,))
		for row in elems:
			self.set_text(str(row[0]))

	def save_item(self):
		value = self.__database.str(self.get_text())
		if value == None or value == '':
			hildon.hildon_banner_show_information_with_markup(self, 'kk', "I can't create empty element!")
			return
		if self.__id != None: id = self.__id
		else: id = self.property.id
		SQLcmd ='UPDATE ' + self.__property.table_name + ' SET ' + self.__property.field_name + ' = ? WHERE id == ?;'
		args = (value, id,)
		self.__database.SQLexec(SQLcmd, args)

####   EditProperties
class PropertyButton(hildon.PickerButton):
	__database = None
	__property = None
	__id = None

	def __init__(self, parent, database, property,  id):
		self.__database = database
		self.__property = property
		self.__id = id

		super(PropertyButton, self).__init__(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
		self.set_title(self.__property.name)
		self.set_alignment(0.1,0.5,1.0,1.0)
		selector = hildon.TouchSelectorEntry(text=True)
		for i in self.__property.values:
			selector.append_text(str(i))
		self.set_selector(selector)
		self.load_item()

	def load_item(self):
		if self.__id != None: id = self.__id
		else: id = self.__property.id
		elems = self.__database.SQLexec('SELECT ' + self.__property.field_name + ' FROM ' + self.__property.table_name + ' WHERE id == ?;', (id,))
		for row in elems:
			val = row[0]
			if val == None: self.set_value('')
			else: self.set_value(str(val))

	def save_item(self):
		value = self.__database.str(self.get_value())
		SQLcmd ='UPDATE ' + self.__property.table_name + ' SET ' + self.__property.field_name + ' = ? WHERE id == ?;'
		if self.__id != None:
			id = self.__id
		else:
			id = self.__property.id
			if not self.__id_exist(id):
				SQLcmd ='INSERT INTO ' + self.__property.table_name + '(' + self.__property.field_name + ', id) VALUES (?, ?);'
		args = (value, id,)
		self.__database.SQLexec(SQLcmd, args)

	def __id_exist(self, id):
		elems = self.__database.SQLexec('SELECT id FROM '+self.__property.table_name+' WHERE id == ?;', (id,))
		elem = elems.fetchone()
		if elem == None: return False
		else: return True

####   EditProperties
class EditProperties(gtk.Dialog):
	__database = None
	__props = None
	__id = None
	__wProps = []

	def __init__(self, parent, database, props,  id):
		self.__database = database
		self.__props = props
		self.__id = id

		if len(props) == 0: return
		super(EditProperties, self).__init__(parent=parent, flags=gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL)
		if not self.__id_exist():
			hildon.hildon_banner_show_information_with_markup(self, 'kk', "ID <b><i>"+str(id)+"</i></b> don't found!")
			self.destroy()
			return
		self.set_default_response(gtk.RESPONSE_CANCEL)
		self.add_button("gtk-ok", gtk.RESPONSE_OK)
		self.add_button("gtk-cancel", gtk.RESPONSE_CANCEL)

		for prop in props:
			if prop.values == None:
				wProp = PropertyEntry(parent, self.__database, prop, self.__id)
			else:
				wProp = PropertyButton(parent, self.__database, prop, self.__id)
			self.vbox.pack_start(wProp, expand=False, fill=True)
		self.connect("expose-event", self.__on_expose_event, None)

	def __on_expose_event(self, widget, event, userdata):
		self.set_geometry_hints(self, 700,700)

	def run(self):
		self.show_all()
		function = gtk.Dialog.run(self)
		if function == gtk.RESPONSE_OK: self.__save_props()
		self.destroy()

	def __save_props(self):
		for w in self.vbox.get_children():
			w.save_item()

	def __id_exist(self):
		if self.__id == None: return True
		elems = self.__database.SQLexec('SELECT id FROM '+self.__props[0].table_name+' WHERE id == ?;', (self.__id,))
		for row in elems:
			return True
		return None

####   EditRelations
class EditRelations(gtk.Dialog):
	__parent = None
	__database = None
	__item_type = None
	__element_id = None
	__element_name = None
	__element_table = None
	__element_field = None
	__relation_table = None
	__relation_field = None
	__selector = None

	def __init__(self, parent, database, elem_id, elem_name, item_type):
		self.__parent = parent
		self.__database = database
		self.__element_id = elem_id
		self.__element_name = elem_name
		self.__set_item_type(item_type)

		super(EditRelations, self).__init__(parent=parent, flags=gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL)
		self.__create_dialog()
		self.connect("expose-event", self.__on_expose_event, None)
		self.show_all()

	def __on_expose_event(self, widget, event, userdata):
		self.set_geometry_hints(self, 700,700)

	def __set_item_type(self, item_type):
		self.__item_type = item_type
		if item_type == ItemType.SHOP:
			self.__element_table = 'elements'
			self.__element_field = 'id_element'
			self.__relation_table = 'shops'
			self.__relation_field = 'id_shop'
		else:
			self.__element_table = 'shops'
			self.__element_field = 'id_shop'
			self.__relation_table = 'elements'
			self.__relation_field = 'id_element'

	def __create_dialog(self):
		self.set_title("Select one or more relations for "+self.__element_name)
		self.set_default_response(EditFunctions.CANCEL)
		self.add_button(gtk.STOCK_ADD, EditFunctions.CREATE)
		self.add_button(gtk.STOCK_DELETE, EditFunctions.DELETE)
		#self.add_button(gtk.STOCK_CANCEL, EditFunctions.CANCEL)
		self.add_button(gtk.STOCK_OK, EditFunctions.OK)
		self.set_default_size(-1,2000)
		#self.maximize()

		# Create a touch selector entry
		self.__selector = hildon.TouchSelectorEntry(text=True)
		self.__selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE)

		#self.__fill_selector(self.__relation_table, selector_elem)
		self.vbox.pack_start(self.__selector, expand=True, fill=True)

	def run(self):
		while True:
			self.update()
			function = gtk.Dialog.run(self)
			text = self.__selector.get_current_text()
			if EditFunctions.CREATE == function:
				id = self.__create_element(text)
				if not id == None:
					model = self.__selector.get_model(0)
					new_iter = model.append();
					model.set(new_iter, 0, text)
			elif EditFunctions.DELETE == function:
				self.__delete_element(self.__relation_table, self.__relation_field, text)
			elif EditFunctions.OK == function:
				self.__save_relations()
				break
			else:
				break
		self.destroy()

	def update(self):
		self.__selector.get_model(0).clear()
		self.__fill_selector()

	def __fill_selector(self):
		elems = self.__database.SQLexec('SELECT id, name FROM ' + self.__relation_table + ' ORDER BY "name" ASC;')
		model = self.__selector.get_model(0)
		for row in elems:
			new_iter = model.append();
			model.set(new_iter, 0, row[1])
			if self.__relation_exist(row[0]):
				self.__selector.select_iter(0,new_iter,True)
		elems.close()

	def __create_element(self, element):
		if element == '':
			hildon.hildon_banner_show_information_with_markup(self.__parent, 'kk', "I can't create empty element!")
			return None
		id = self.__get_id(element)
		if not id == None:
			hildon.hildon_banner_show_information_with_markup(self.__parent, 'kk', "<b><i>"+element+"</i></b> element exists!")
			return None
		note = hildon.Note(hildon.NOTE_TYPE_CONFIRMATION, self.__parent, "Create "+element+"?")
		retcode = gtk.Dialog.run(note)
		note.destroy()
		if retcode == gtk.RESPONSE_OK:
			self.__database.SQLexec('INSERT INTO '+self.__relation_table+'(name) VALUES(?);', (element,))
			id = self.__get_id(element)
		return id

	def __delete_element(self, tablename, field, element):
		note = hildon.Note(hildon.NOTE_TYPE_CONFIRMATION, self.__parent, "Delete "+element+"?")
		retcode = gtk.Dialog.run(note)
		note.destroy()
		if retcode == gtk.RESPONSE_OK:
			id = self.__get_id(element)
			if id == None: return
			self.__reset_relations(self.__relation_field, id)
			self.__database.SQLexec('DELETE FROM '+self.__relation_table+' WHERE id = ?;', (id,))

	def __create_relation(self, relation_name):
		relation_id = self.__get_id(relation_name)
		if relation_id == None:
			relation_id = self.__create_element(relation_name)
			if relation_id == None: return
		cmdSQL = 'INSERT INTO elements_in_shops( '+self.__element_field+', '+self.__relation_field+' ) VALUES( ?, ? );'
		self.__database.SQLexec(cmdSQL, (self.__element_id, relation_id,))

	def __relation_exist(self, id):
		SQLcmd = 'SELECT id FROM elements_in_shops WHERE '+self.__element_field+' = ? AND '+self.__relation_field+' = ? ;'
		elems = self.__database.SQLexec(SQLcmd,(self.__element_id, id,))
		for i in elems:
			return True
		return False

	def __save_relations(self):
		self.__reset_relations(self.__element_field, self.__element_id)
		pathlist = self.__selector.get_selected_rows(0)
		model = self.__selector.get_model(0)
		for path in pathlist:
			iter = model.get_iter(path)
			text = model.get_value(iter, 0)
			self.__create_relation(text)

	def __reset_relations(self, field_name, id):
		self.__database.SQLexec('DELETE FROM elements_in_shops WHERE '+field_name+' = ?;', (id,))

	def __get_id(self, element):
		elems = self.__database.SQLexec('SELECT id FROM ' + self.__relation_table + ' WHERE name = ?;', (element,))
		for row in elems:
			elems.close()
			return row[0]
		return None

########################################################################
################################################   CLASES EXTERNAS   ###
########################################################################

####   AboutDialog
class AboutDialog(gtk.Dialog):
    PADDING = 5

    def __init__(self, parent):
        super(AboutDialog, self).__init__(parent=parent,
                                          flags=gtk.DIALOG_DESTROY_WITH_PARENT)
        self._logo = gtk.Image()
        self._name = ''
        self._name_label = gtk.Label()
        self._version = ''
        self._comments_label = gtk.Label()
        self._copyright_label = gtk.Label()
        self._license_label = gtk.Label()
        _license_alignment = gtk.Alignment(0, 0, 0, 1)
        _license_alignment.add(self._license_label)
        self._license_label.set_line_wrap(True)

        self._writers_caption = gtk.Label()
        self._writers_caption.set_markup('<b>%s</b>' % 'Authors:')
        _writers_caption = gtk.Alignment()
        _writers_caption.add(self._writers_caption)
        self._writers_label = gtk.Label()
        self._writers_contents = gtk.VBox(False, 0)
        self._writers_contents.pack_start(_writers_caption)
        _writers_alignment = gtk.Alignment(0.2, 0, 0, 1)
        _writers_alignment.add(self._writers_label)
        self._writers_contents.pack_start(_writers_alignment)

        _contents = gtk.VBox(False, 0)
        _contents.pack_start(self._logo, False, False, self.PADDING)
        _contents.pack_start(self._name_label, False, False, self.PADDING)
        _contents.pack_start(self._comments_label, False, False, self.PADDING)
        _contents.pack_start(self._copyright_label, False, False, self.PADDING)
        _contents.pack_start(self._writers_contents, False, False, self.PADDING)
        _contents.pack_start(_license_alignment, False, False, self.PADDING)

        _contents_area = hildon.PannableArea()
        _contents_area.add_with_viewport(_contents)
        _contents_area.set_size_request_policy(hildon.SIZE_REQUEST_CHILDREN)
        self.vbox.add(_contents_area)
        self.vbox.show_all()
        self._writers_contents.hide()

    def set_logo(self, logo_path):
        self._logo.set_from_file(logo_path)

    def set_name(self, name):
        self._name = name
        self.set_version(self._version)
        self.set_title('About %s' % self._name)

    def _set_name_label(self, name):
        self._name_label.set_markup('<big>%s</big>' % name)

    def set_version(self, version):
        self._version = version
        self._set_name_label('%s %s' % (self._name, self._version))

    def set_comments(self, comments):
        self._comments_label.set_text(comments)

    def set_copyright(self, copyright):
        self._copyright_label.set_markup('<small>%s</small>' % copyright)

    def set_license(self, license):
        self._license_label.set_markup('<b>%s</b>\n<small>%s</small>' % \
                                       ('License:', license))

    def set_authors(self, authors_list):
        authors = '\n'.join(authors_list)
        self._writers_label.set_text(authors)
        self._writers_contents.show_all()

# Thanks to
# gPodder - A media aggregator and podcast client
# Copyright (c) 2005-2010 Thomas Perl and the gPodder Team
#
# source = http://wiki.maemo.org/PyMaemo/Portrait_mode
#
import dbus
import dbus.glib

import hildon
import osso

def _(text):
	return text

class FremantleRotation(object):
    """thp's screen rotation for Maemo 5

    Simply instantiate an object of this class and let it auto-rotate
    your StackableWindows depending on the device orientation.

    If you need to relayout a window, connect to its "configure-event"
    signal and measure the ratio of width/height and relayout for that.

    You can set the mode for rotation to AUTOMATIC (default), NEVER or
    ALWAYS with the set_mode() method.
    """
    AUTOMATIC, NEVER, ALWAYS = range(3)

    # Human-readable captions for the above constants
    MODE_CAPTIONS = (_('Automatic'), _('Landscape'), _('Portrait'))

    # Privately-used constants
    _PORTRAIT, _LANDSCAPE = ('portrait', 'landscape')
    _ENABLE_ACCEL = 'req_accelerometer_enable'
    _DISABLE_ACCEL = 'req_accelerometer_disable'

    # Defined in mce/dbus-names.h
    _MCE_SERVICE = 'com.nokia.mce'
    _MCE_REQUEST_PATH = '/com/nokia/mce/request'
    _MCE_REQUEST_IF = 'com.nokia.mce.request'

    # sysfs device name for the keyboard slider switch
    KBD_SLIDER = '/sys/devices/platform/gpio-switch/slide/state'
    _KBD_OPEN = 'open'
    _KBD_CLOSED = 'closed'

    def __init__(self, app_name, main_window=None, version='1.0', mode=0):
        """Create a new rotation manager

        app_name    ... The name of your application (for osso.Context)
        main_window ... The root window (optional, hildon.StackableWindow)
        version     ... The version of your application (optional, string)
        mode        ... Initial mode for this manager (default: AUTOMATIC)
        """
        self._orientation = None
        self._main_window = main_window
        self._stack = hildon.WindowStack.get_default()
        self._mode = -1
        self._last_dbus_orientation = None
        self._keyboard_state = self._get_keyboard_state()
        app_id = '-'.join((app_name, self.__class__.__name__))
        self._osso_context = osso.Context(app_id, version, False)
        program = hildon.Program.get_instance()
        program.connect('notify::is-topmost', self._on_topmost_changed)
        system_bus = dbus.Bus.get_system()
        system_bus.add_signal_receiver(self._on_orientation_signal, \
                signal_name='sig_device_orientation_ind', \
                dbus_interface='com.nokia.mce.signal', \
                path='/com/nokia/mce/signal')
        system_bus.add_signal_receiver(self._on_keyboard_signal, \
                signal_name='Condition', \
                dbus_interface='org.freedesktop.Hal.Device', \
                path='/org/freedesktop/Hal/devices/platform_slide')
        self.set_mode(mode)

    def get_mode(self):
        """Get the currently-set rotation mode

        This will return one of three values: AUTOMATIC, ALWAYS or NEVER.
        """
        return self._mode

    def set_mode(self, new_mode):
        """Set the rotation mode

        You can set the rotation mode to AUTOMATIC (use hardware rotation
        info), ALWAYS (force portrait) and NEVER (force landscape).
        """
        if new_mode not in (self.AUTOMATIC, self.ALWAYS, self.NEVER):
            raise ValueError('Unknown rotation mode')

        if self._mode != new_mode:
            if self._mode == self.AUTOMATIC:
                # Remember the current "automatic" orientation for later
                self._last_dbus_orientation = self._orientation
                # Tell MCE that we don't need the accelerometer anymore
                self._send_mce_request(self._DISABLE_ACCEL)

            if new_mode == self.NEVER:
                self._orientation_changed(self._LANDSCAPE)
            elif new_mode == self.ALWAYS and \
                    self._keyboard_state != self._KBD_OPEN:
                self._orientation_changed(self._PORTRAIT)
            elif new_mode == self.AUTOMATIC:
                # Restore the last-known "automatic" orientation
                self._orientation_changed(self._last_dbus_orientation)
                # Tell MCE that we need the accelerometer again
                self._send_mce_request(self._ENABLE_ACCEL)

            self._mode = new_mode

    def _send_mce_request(self, request):
        rpc = osso.Rpc(self._osso_context)
        rpc.rpc_run(self._MCE_SERVICE, \
                    self._MCE_REQUEST_PATH, \
                    self._MCE_REQUEST_IF, \
                    request, \
                    use_system_bus=True)

    def _on_topmost_changed(self, program, property_spec):
        # XXX: This seems to never get called on Fremantle(?)
        if self._mode == self.AUTOMATIC:
            if program.get_is_topmost():
                self._send_mce_request(self._ENABLE_ACCEL)
            else:
                self._send_mce_request(self._DISABLE_ACCEL)

    def _get_main_window(self):
        if self._main_window:
            # If we have gotten the main window as parameter, return it and
            # don't try "harder" to find another window using the stack
            return self._main_window
        else:
            # The main window is at the "bottom" of the window stack, and as
            # the list we get with get_windows() is sorted "topmost first", we
            # simply take the last item of the list to get our main window
            windows = self._stack.get_windows()
            if windows:
                return windows[-1]
            else:
                return None

    def _orientation_changed(self, orientation):
        if self._orientation == orientation:
            # Ignore repeated requests
            return

        flags = 0

        if orientation != self._LANDSCAPE:
            flags |= hildon.PORTRAIT_MODE_SUPPORT

        if orientation == self._PORTRAIT:
            flags |= hildon.PORTRAIT_MODE_REQUEST

        window = self._get_main_window()
        if window is not None:
            hildon.hildon_gtk_window_set_portrait_flags(window, flags)

        self._orientation = orientation

    def _get_keyboard_state(self):
        # For sbox, if the device does not exist assume that it's closed
        try:
            return open(self.KBD_SLIDER).read().strip()
        except IOError:
            return self._KBD_CLOSED

    def _keyboard_state_changed(self):
        state = self._get_keyboard_state()

        if state == self._KBD_OPEN:
            self._orientation_changed(self._LANDSCAPE)
        elif state == self._KBD_CLOSED:
            if self._mode == self.AUTOMATIC:
                self._orientation_changed(self._last_dbus_orientation)
            elif self._mode == self.ALWAYS:
                self._orientation_changed(self._PORTRAIT)

        self._keyboard_state = state

    def _on_keyboard_signal(self, condition, button_name):
        if condition == 'ButtonPressed' and button_name == 'cover':
            self._keyboard_state_changed()

    def _on_orientation_signal(self, orientation, stand, face, x, y, z):
        if orientation in (self._PORTRAIT, self._LANDSCAPE):
            if self._mode == self.AUTOMATIC and \
                    self._keyboard_state != self._KBD_OPEN:
                # Automatically set the rotation based on hardware orientation
                self._orientation_changed(orientation)

            # Save the current orientation for "automatic" mode later on
            self._last_dbus_orientation = orientation


########################################################################
##################################################   ENUMERACIONES   ###
########################################################################
####   MainMenuOptions
class MainMenuOptions:
    NONE, SHOPLIST, GOSHOPPING = range(3)

####   EditFunctions
class EditFunctions:
    NONE, CANCEL, OK, CREATE, DELETE, PROPERTIES, RELATIONS = range(7)

####   EditFunctions
class ItemType:
    ITEM, SHOP = range(2)

########################################################################
###########################################################   MAIN   ###
########################################################################
if __name__ == '__main__':
	main()
