9
from translate import Translate
14
#When the class is loaded
15
def __init__(self, tour, directory):
18
self.folder = directory
23
#Some empty values to fill later
24
self.lang, self.info, self.parent, self.name, self.pos, self.default, self.id, self.t_pages = None, None, None, None, None, None, None, None
33
def detect_lang(self):
35
#Try using the language and country
36
if os.path.isdir(os.path.join(self.folder, self.tour.user_lang)):
37
self.lang = self.tour.user_lang
39
#Fallback on just the language
40
elif os.path.isdir(os.path.join(self.folder, self.tour.user_lang.split('_')[0])):
41
self.lang = self.tour.user_lang.split('_')[0]
43
#Fallback on default language
45
self.lang = self.tour.default_lang
52
def get_tour_info(self):
54
#Try and open the file
57
info = open(os.path.join(self.folder, self.lang, 'tour.info'),'r').read()
61
for line in info.split('\n'):
64
self.info[l[0]] = l[1]
66
#This is deliberately bad coding, so that if the tour is invalid, it will break the try and force the except to work.
67
self.parent = self.info['parent']
68
self.name = self.info['name']
70
self.pos = int(self.info['position'])
74
self.default = int(self.info['default'])#TODO: impliment features using this.
78
#If it survived that it's valid.
83
self.tour.p(self.folder + " does not have a tour.info, folder rejected.")
91
pages = glob.glob(os.path.join(self.folder, self.lang, "*"))
93
#Loop through the pages
96
if '_' in p.split('/')[-1]:
98
page = int(p.split('/')[-1].split('_')[0])
102
self.tour.p('Warning, ' + p.split('/')[-1] + ' contains an underscore, please rename.')
118
#Things to do when class is loaded
119
def __init__(self, debug, html, colours):
120
self.default_lang = 'en'
121
self.user_lang = self.detect_lang()
122
self.dialect = self.load_dialect()
126
self.colours = colours
133
self.progression_reqs = ''
134
self.fullscreen = False
138
self.catagories = ['Hidden', 'Getting Started', 'Internet', 'Office', 'Multimedia', 'Continue Playing']
140
#Debug print function
146
#Get a list of tutorials available
147
def get_sections(self):
149
if os.path.exists(os.path.join(os.getcwd(), "tours")):
150
dirs = glob.glob(os.path.join(os.getcwd(), "tours", "*"))
151
elif os.path.exists(os.path.join("/", "usr","share","ubuntu-tour","tours")):
152
dirs = glob.glob(os.path.join("/", "usr","share","ubuntu-tour","tours","*"))
153
elif os.path.exists(os.path.join(os.path.expanduser('~'), ".ubuntu-tour", "tours")):
154
dirs = glob.glob(os.path.join(os.path.expanduser('~'), ".ubuntu-tour", "tours", "*"))
156
#Go through the folders
160
tour = T(self, folder)
163
self.tours.append(tour)
170
def GetDefaultApp(Type):
171
if (Type.lower() == "browser"):
172
return os.popen("gconftool-2 -g /desktop/gnome/applications/browser/exec").read()[:-1]
173
elif (Type.lower() == "music" or Type.lower() == "media"):
174
return os.popen("gconftool-2 -g /desktop/gnome/applications/media/exec").read()[:-1]
176
print "There's no support for looking up the apps for \"" + Type + "\""
180
def load_page(self, tour_id, page=0, fullscreen=False, dark=False):
182
self.p("Loading page")
184
#Get the folder name and page number
185
self.page = int(page)
188
self.current_tour = self.tours[int(tour_id)]
189
tour = self.current_tour
191
#Try and read the page, if not, return a generic page
194
files = glob.glob(tour.folder + "/" + tour.lang + '/' + str(self.page) + "_*")
198
for n in range(0, len(files)):
199
if files[n].split('.')[-1] == 'html':
202
#Are we using the html
205
#Is there a html file?
208
msg = open(files[html],'r')
215
msg = open(files[html],'r')
221
text = self.raw_to_html(text)
223
#Otherwise we are using plain text
225
#Usually the file will be 0
229
#If however -1 is the html
231
#If there is another file
235
#Otherwise convert the html file to a text file
240
msg=open(files[f],'r')
245
#Should we try and convert
247
text = self.html_to_raw(text)
249
#Get the progression requirements
250
if '"Requirements" -->' in text:
251
reqs = text.split('"Requirements" -->', 2)[0]
252
if '<!-- "Requirements"' in reqs:
253
reqs = reqs.split('<!-- "Requirements"', 2)[1]
255
#Save these requirements
256
self.progression_reqs = reqs
259
self.progression_reqs = ''
262
self.progression_reqs = ''
264
#Convert text to the local dialect
265
if not '_' in tour.lang:
266
self.p('using dialect')
267
text = self.convert_to_dialect(text)
271
self.gui.html.load_html_string(self.parse_html(text, dark), 'file://' + tour.folder + "/" + tour.lang + "/")
273
self.gui.buffer.set_text(text)
276
if tour.name == "Home":
277
if tour.parent == "Hidden":
278
self.gui.addressbar.set_items(['Home'])
280
self.gui.addressbar.set_items(['Home', tour.parent])
283
elif tour.parent != "Hidden":
284
self.gui.addressbar.set_items(['Home', tour.parent, tour.name])
291
#If we can't load the file, we should give some generic text.
293
self.gui.html.load_html_string(self.parse_html("Nothing written yet.", dark), 'file://' + tour.folder + "/" + tour.lang + "/")
295
self.gui.buffer.set_text("Nothing written yet.")
301
if not self.fullscreen:
303
self.gui.progressbar.hide()
304
self.gui.buttonbox.hide()
305
self.gui.menuscroll.hide()
308
self.fullscreen = True
313
self.gui.progressbar.show()
314
self.gui.buttonbox.show()
315
self.gui.menuscroll.show()
317
#Now longer fullscreen
318
self.fullscreen = False
320
#Now we have loaded the page, lets see about the position.
321
if tour.t_pages == 0:
322
self.gui.next_button.set_sensitive(False)
323
self.gui.back_button.set_sensitive(False)
325
self.gui.next_button.set_sensitive(True)
326
self.gui.back_button.set_sensitive(False)
327
elif self.page == tour.t_pages:
328
self.gui.next_button.set_sensitive(False)
329
self.gui.back_button.set_sensitive(True)
331
self.gui.next_button.set_sensitive(True)
332
self.gui.back_button.set_sensitive(True)
334
if self.page==1 and self.current_tour.name=="Managing software":
335
self.gui.next_button.hide()
336
self.gui.check_button.show()
338
self.gui.next_button.show()
339
self.gui.check_button.hide()
343
progress = float(self.page) / float(tour.t_pages)
346
self.gui.progressbar.set_fraction(progress)
351
def num_pages(self, tutorial):
352
#Get the path to the tutorial
353
path = os.getcwd() + "/" + tutorial.replace(" ","-").lower() + "/"
356
pages = glob.glob(path + self.default_lang + "/*")
358
#Loop through the pages
362
page = int(p.split('/')[-1].split('_')[0])
370
#Detect the language that the user is using.
371
def detect_lang(self):
373
return locale.getdefaultlocale()[0]
376
#Detect the local dialect
377
def load_dialect(self):
379
#Dialects, start off empty
382
#For all the possible paths
383
for path in [os.path.join("/", "usr","share","ubuntu-tour","dialects", self.user_lang), os.path.join(os.getcwd(), "dialects", self.user_lang)]:
385
#See if the dialect exists here
386
if os.path.exists(path):
392
#Loop through replacements
393
for replace in repls.split('\n'):
396
#Get the find and replace part
397
r = replace.split('->', 1)
403
#And add to the dialect, provided there is something
405
dialects[r[0]] = r[1]
407
#All done, return the dialects
411
#Convert text into the dialect
412
def convert_to_dialect(self, text):
415
#Create a regex search for words which need changing
416
regex = '((.|\\r|\\n)(' + '|'.join(self.dialect.keys()) + ')(.|\\r|\\n))'
418
#Make a note of softkeys to remove
422
#Loop through all items of the original language
423
for i in re.findall(regex,text):
427
#If it is being used in the html, then we should not change it. (Protection against colo(u)r and cent[re/er])
428
if i[2] == 'color' and i[3] == '=':
430
if i[2] == 'center' and i[1] == '=':
433
#If prepended by an softkey symbol, then we don't convert
434
elif i[1] == softkey:
435
softkey_remove.append(i[2] + i[3])
438
#Otherwise, we convert
440
replace = i[1] + self.dialect[i[2]] + i[3]
442
#Go ahead and replace
444
self.p(i[0] + " to be replaced with " + replace)
445
text = text.replace(i[0], replace)
447
#If something goes wrong, complain quitly
451
#TODO: this spams '' errors. Why?
455
#Now remove the softkeys
456
for s in softkey_remove:
457
text = text.replace(softkey + s, s)
459
#And return the new text
462
#Convert a plain text file to html
463
def raw_to_html(self, text):
466
text = text.replace('\n', '<br />\n')
472
#Convert html to plain
473
def html_to_raw(self, text):
476
text = text.replace('\r', '')
477
text = text.replace('\r\n', '\n')
478
text = text.replace('<br />\n', '\n')
479
text = text.replace('<br />', '\n')
485
#Parse html, to get a whole page
486
def parse_html(self, html, dark=False):
488
#For Lightbox Effect: Search for screenshot tag and replace with img tag
489
pattern = r'''<screenshot([^"]+)src="([^"]+)"([^>]+)'''
490
pattern_string = re.compile(pattern)
491
replace_string = r'''<a id="lightbox" href="\2"><img src="\2" \1\3></a'''
492
if re.search(pattern_string,html):
493
html = re.sub(pattern_string,replace_string,html)
495
#Get the html opening
496
f = open(os.getcwd() + "/html/start.html",'r')
500
#Get the html closing
501
f = open(os.getcwd() + "/html/end.html",'r')
506
html = start + html + end
510
html = html.replace('{{BACK-COLOUR}}', self.colours['background_t'][0])
511
html = html.replace('{{TEXT-COLOUR}}', self.colours['foreground_t'][0])
513
html = html.replace('{{BACK-COLOUR}}', self.colours['background'][0])
514
html = html.replace('{{TEXT-COLOUR}}', self.colours['foreground'][0])
516
#Return the combined html
521
def parse_colours(self):
523
for k in self.colours.keys():
525
hex = self.colours[k].to_string()
527
#Convert to 256 colour hex
529
hex = hex[0:3] + hex[5:7] + hex[9:11]
532
self.colours[k] = (hex, self.colours[k])
536
def make_menu(self, gui):
542
self.tree_menu = gtk.TreeView()
545
self.tree_sections = gtk.TreeViewColumn("Chapters", gtk.CellRendererText(), text=0)
546
self.tree_menu.append_column(self.tree_sections)
548
self.tree_ids = gtk.TreeViewColumn("ID", gtk.CellRendererText(), text=1)
549
self.tree_ids.set_visible(False)
550
self.tree_menu.append_column(self.tree_ids)
556
self.tree_menu.get_selection().connect("changed", self.row_selected)
557
self.tree_menu.set_property("headers-visible", False)
559
self.tree_menu.modify_base(gtk.STATE_NORMAL, self.colours['background'][1])
560
self.tree_menu.modify_text(gtk.STATE_NORMAL, self.colours['foreground'][1])
561
self.tree_menu.expand_all()
563
#Append, if it's not already there
564
child = self.gui.menuscroll.get_child()
566
self.gui.menuscroll.add(self.tree_menu)
567
#self.gui.hbox.pack_start(self.tree_menu, False, True)
571
def update_menu(self, rescan=True):
578
self.tree_store = gtk.TreeStore(str, int)
580
#See how many times each catagory is used
582
for cat in self.catagories:
585
cat_count[t.parent] = 1
589
self.tree_catagories = []
591
for cat in self.catagories:
592
if cat_count[cat] > 0:
594
self.children[cat] = []
595
self.tree_catagories.append(cat)
597
#If it's not hidden, add it.
598
if cat.lower() != 'hidden':
599
self.parents[cat] = self.tree_store.append(None, [cat, -1])
602
self.sorted_tours = sorted(self.tours, cmp=lambda x,y: self.TourCmp(x, y))
604
#Loop through the tours
605
for t in self.sorted_tours:
610
#Add the parent if its not common
611
if not t.parent in self.children.keys():
612
if t.parent.lower() != 'hidden':
613
self.parents[t.parent] = self.tree_store.append(None, [t.parent, -1])
614
self.tree_catagories.append(t.parent)
615
self.children[t.parent] = []
617
#Add to tree store if its not a hidden tour
618
if t.parent.lower() != 'hidden':
619
self.tree_store.append(self.parents[t.parent], [t.name, t.id])
621
#Add to list of parents children
622
self.children[t.parent].append(t.id)
625
self.tree_menu.set_model(model=self.tree_store)
628
self.tree_menu.expand_all()
631
#A function to sort tours
632
def TourCmp(self, a, b):
642
#Row selected callback
643
def row_selected(self, selection, user_param=None):
644
if len(selection.get_selected_rows()[1]) > 0:
646
pos = selection.get_selected_rows()[1][0]
648
#Scroll to the selected value
649
self.tree_menu.scroll_to_cell(pos)
651
#What is the selected value
654
self.load_page(self.children[self.tree_catagories[pos[0]+1]][pos[1]],0)
656
self.p('Could not load ' + pos)