Skeleton of an application
[watersofshiloah] / src / mormonchannel_gtk.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 from __future__ import with_statement
5
6 import gc
7 import logging
8 import ConfigParser
9
10 import gtk
11
12 try:
13         import hildon
14 except ImportError:
15         hildon = None
16
17 try:
18         import osso
19 except ImportError:
20         osso = None
21
22 import constants
23 import hildonize
24 import gtk_toolbox
25
26
27 _moduleLogger = logging.getLogger(__name__)
28 PROFILE_STARTUP = False
29
30
31 class MormonChannelProgram(hildonize.get_app_class()):
32
33         def __init__(self):
34                 super(MormonChannelProgram, self).__init__()
35                 self._clipboard = gtk.clipboard_get()
36
37                 self._window_in_fullscreen = False #The window isn't in full screen mode initially.
38
39                 #Create GUI main vbox
40                 vbox = gtk.VBox(homogeneous = False, spacing = 0)
41
42                 if hildonize.GTK_MENU_USED:
43                         #Create Menu and apply it for hildon
44                         filemenu = gtk.Menu()
45
46                         menu_items = gtk.MenuItem("Quit")
47                         filemenu.append(menu_items)
48                         menu_items.connect("activate", self._on_destroy, None)
49
50                         file_menu = gtk.MenuItem("File")
51                         file_menu.show()
52                         file_menu.set_submenu(filemenu)
53
54                         categorymenu = gtk.Menu()
55
56                         menu_items = gtk.MenuItem("Search")
57                         categorymenu.append(menu_items)
58                         menu_items.connect("activate", self._on_toggle_search)
59
60                         helpmenu = gtk.Menu()
61
62                         menu_items = gtk.MenuItem("About")
63                         helpmenu.append(menu_items)
64                         menu_items.connect("activate", self._on_show_about, None)
65
66                         help_menu = gtk.MenuItem("Help")
67                         help_menu.show()
68                         help_menu.set_submenu(helpmenu)
69
70                         menuBar = gtk.MenuBar()
71                         menuBar.show()
72                         menuBar.append (file_menu)
73                         menuBar.append (help_menu)
74
75                         vbox.pack_start(menuBar, False, False, 0)
76                 else:
77                         menuBar = gtk.MenuBar()
78                         menuBar.show()
79                         vbox.pack_start(menuBar, False, False, 0)
80
81                 #Get the Main Window, and connect the "destroy" event
82                 self._window = gtk.Window()
83                 self._window.add(vbox)
84
85                 self._window = hildonize.hildonize_window(self, self._window)
86                 hildonize.set_application_title(self._window, "%s" % constants.__pretty_app_name__)
87                 menuBar = hildonize.hildonize_menu(
88                         self._window,
89                         menuBar,
90                 )
91                 if hildonize.IS_FREMANTLE_SUPPORTED:
92                         searchButton= gtk.Button("Search")
93                         searchButton.connect("clicked", self._on_toggle_search)
94                         menuBar.append(searchButton)
95
96                         menuBar.show_all()
97
98                 if not hildonize.IS_HILDON_SUPPORTED:
99                         _moduleLogger.info("No hildonization support")
100
101                 if osso is not None:
102                         self._osso_c = osso.Context(constants.__app_name__, constants.__version__, False)
103                         self._deviceState = osso.DeviceState(self._osso_c)
104                         self._deviceState.set_device_state_callback(self._on_device_state_change, 0)
105                 else:
106                         _moduleLogger.info("No osso support")
107                         self._osso_c = None
108                         self._deviceState = None
109
110                 self._window.connect("delete-event", self._on_delete_event)
111                 self._window.connect("destroy", self._on_destroy)
112                 self._window.connect("key-press-event", self._on_key_press)
113                 self._window.connect("window-state-event", self._on_window_state_change)
114
115                 self._window.show_all()
116                 self._load_settings()
117
118         def _save_settings(self):
119                 config = ConfigParser.SafeConfigParser()
120                 self.save_settings(config)
121                 with open(constants._user_settings_, "wb") as configFile:
122                         config.write(configFile)
123
124         def save_settings(self, config):
125                 config.add_section(constants.__pretty_app_name__)
126                 config.set(constants.__pretty_app_name__, "fullscreen", str(self._window_in_fullscreen))
127
128         def _load_settings(self):
129                 config = ConfigParser.SafeConfigParser()
130                 config.read(constants._user_settings_)
131                 self.load_settings(config)
132
133         def load_settings(self, config):
134                 try:
135                         self._window_in_fullscreen = config.getboolean(constants.__pretty_app_name__, "fullscreen")
136                 except ConfigParser.NoSectionError, e:
137                         _moduleLogger.info(
138                                 "Settings file %s is missing section %s" % (
139                                         constants._user_settings_,
140                                         e.section,
141                                 )
142                         )
143
144                 if self._window_in_fullscreen:
145                         self._window.fullscreen()
146                 else:
147                         self._window.unfullscreen()
148
149         def _toggle_search(self):
150                 if self._search.get_property("visible"):
151                         self._search.hide()
152                 else:
153                         self._search.show()
154
155         @gtk_toolbox.log_exception(_moduleLogger)
156         def _on_device_state_change(self, shutdown, save_unsaved_data, memory_low, system_inactivity, message, userData):
157                 """
158                 For system_inactivity, we have no background tasks to pause
159
160                 @note Hildon specific
161                 """
162                 if memory_low:
163                         gc.collect()
164
165                 if save_unsaved_data or shutdown:
166                         self._save_settings()
167
168         @gtk_toolbox.log_exception(_moduleLogger)
169         def _on_window_state_change(self, widget, event, *args):
170                 if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
171                         self._window_in_fullscreen = True
172                 else:
173                         self._window_in_fullscreen = False
174
175         @gtk_toolbox.log_exception(_moduleLogger)
176         def _on_key_press(self, widget, event, *args):
177                 RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
178                 isCtrl = bool(event.get_state() & gtk.gdk.CONTROL_MASK)
179                 if (
180                         event.keyval == gtk.keysyms.F6 or
181                         event.keyval in RETURN_TYPES and isCtrl
182                 ):
183                         # The "Full screen" hardware key has been pressed 
184                         if self._window_in_fullscreen:
185                                 self._window.unfullscreen ()
186                         else:
187                                 self._window.fullscreen ()
188                         return True
189                 elif event.keyval == gtk.keysyms.f and isCtrl:
190                         self._toggle_search()
191                         return True
192                 elif (
193                         event.keyval in (gtk.keysyms.w, gtk.keysyms.q) and
194                         event.get_state() & gtk.gdk.CONTROL_MASK
195                 ):
196                         self._window.destroy()
197                 elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK:
198                         with open(constants._user_logpath_, "r") as f:
199                                 logLines = f.xreadlines()
200                                 log = "".join(logLines)
201                                 self._clipboard.set_text(str(log))
202                         return True
203
204         @gtk_toolbox.log_exception(_moduleLogger)
205         def _on_toggle_search(self, *args):
206                 self._toggle_search()
207
208         @gtk_toolbox.log_exception(_moduleLogger)
209         def _on_delete_event(self, widget, event, data = None):
210                 return False
211
212         @gtk_toolbox.log_exception(_moduleLogger)
213         def _on_destroy(self, widget = None, data = None):
214                 try:
215                         self._save_settings()
216
217                         try:
218                                 self._deviceState.close()
219                         except AttributeError:
220                                 pass # Either None or close was removed (in Fremantle)
221                         try:
222                                 self._osso_c.close()
223                         except AttributeError:
224                                 pass # Either None or close was removed (in Fremantle)
225                 finally:
226                         gtk.main_quit()
227
228         @gtk_toolbox.log_exception(_moduleLogger)
229         def _on_show_about(self, widget = None, data = None):
230                 dialog = gtk.AboutDialog()
231                 dialog.set_position(gtk.WIN_POS_CENTER)
232                 dialog.set_name(constants.__pretty_app_name__)
233                 dialog.set_version(constants.__version__)
234                 dialog.set_copyright("")
235                 dialog.set_website("")
236                 comments = "Mormon Radio and Audiobook Player"
237                 dialog.set_comments(comments)
238                 dialog.set_authors(["Ed Page <eopage@byu.net>"])
239                 dialog.run()
240                 dialog.destroy()
241
242
243 def run():
244         if hildonize.IS_HILDON_SUPPORTED:
245                 gtk.set_application_name(constants.__pretty_app_name__)
246         app = MormonChannelProgram()
247         if not PROFILE_STARTUP:
248                 gtk.main()
249
250
251 if __name__ == "__main__":
252         logging.basicConfig(level=logging.DEBUG)
253         run()