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