source: lliurex-moving-editor/trunk/fuentes/src/lliurex-moving-editor @ 618

Last change on this file since 618 was 618, checked in by jrpelegrina, 4 years ago

First release to xenial

  • Property svn:executable set to *
File size: 14.7 KB
Line 
1#!/usr/bin/python
2
3from gi.repository import Gtk,GObject
4import os
5import sys
6import signal
7import hashlib
8import copy
9import time
10import xmlrpclib
11
12
13signal.signal(signal.SIGINT, signal.SIG_DFL)
14
15import gettext
16gettext.textdomain('lliurex-moving-editor')
17_ = gettext.gettext
18
19
20
21class Editor:
22
23        def __init__(self):
24       
25                glade_file="../rsrc/ui.glade"
26               
27                if not os.path.exists(glade_file):
28                        glade_file="/usr/share/lliurex-moving-editor/ui.glade"
29                       
30                        if not os.path.exists(glade_file):
31                                raise("Resource file not found: "+glade_file)
32               
33                h=hashlib.md5()
34                h.update("default profile")
35                self.default_id=h.hexdigest()
36               
37                #print "default id:",self.default_id
38               
39                self.first=True
40                self.count=0
41                self.LoadSetup()
42       
43                uitree = Gtk.Builder()
44                uitree.set_translation_domain("lliurex-moving-editor")
45                uitree.add_from_file(glade_file)
46               
47               
48                self.winProfiles=uitree.get_object("winProfiles")
49                self.winRules=uitree.get_object("winRules")
50                self.winEditor=uitree.get_object("winEditor")
51                self.winIconSelector=uitree.get_object("winIconSelector")
52               
53                self.winProfiles.connect("destroy",self.OnDestroy)
54               
55                self.treeProfiles=uitree.get_object("treeProfiles")
56                self.treeRules=uitree.get_object("treeRules")
57                self.treeRegex=uitree.get_object("treeRegex")
58               
59                btnEditProfile=uitree.get_object("btnEditProfile")
60                btnEditProfile.connect("clicked",self.OnBtnEditProfileClicked)
61               
62                btnAddProfile=uitree.get_object("btnAddProfile")
63                btnAddProfile.connect("clicked",self.OnBtnAddProfileClicked)
64               
65                btnRemoveProfile=uitree.get_object("btnRemoveProfile")
66                btnRemoveProfile.connect("clicked",self.OnBtnRemoveProfileClicked)
67               
68                btnDuplicateProfile=uitree.get_object("btnDuplicateProfile")
69                btnDuplicateProfile.connect("clicked",self.OnBtnDuplicateProfileClicked)
70               
71                btnEditRule=uitree.get_object("btnEditRule")
72                btnEditRule.connect("clicked",self.OnBtnEditRuleClicked)
73               
74                btnOkRule=uitree.get_object("btnOkRule")
75                btnOkRule.connect("clicked",self.OnBtnOkRuleClicked)
76               
77                btnCancelRule=uitree.get_object("btnCancelRule")
78                btnCancelRule.connect("clicked",self.OnBtnCancelRuleClicked)
79               
80                btnIconEditor=uitree.get_object("btnIconEditor")
81                btnIconEditor.connect("clicked",self.OnBtnIconEditorClicked)
82               
83                self.imgIconEditor=uitree.get_object("imgIconEditor")
84
85                btnOkEdit=uitree.get_object("btnOkEdit")
86                btnOkEdit.connect("clicked",self.OnBtnOkEditClicked)
87               
88                btnCancelEdit=uitree.get_object("btnCancelEdit")
89                btnCancelEdit.connect("clicked",self.OnBtnCancelEditClicked)
90               
91                btnAddRegex=uitree.get_object("btnAddRegex")
92                btnAddRegex.connect("clicked",self.OnBtnAddRegexClicked)
93               
94                btnRemoveRegex=uitree.get_object("btnRemoveRegex")
95                btnRemoveRegex.connect("clicked",self.OnBtnRemoveRegexClicked)
96
97                btnAddRule=uitree.get_object("btnAddRule")
98                btnAddRule.connect("clicked",self.OnBtnAddRuleClicked)
99               
100                btnRemoveRule=uitree.get_object("btnRemoveRule")
101                btnRemoveRule.connect("clicked",self.OnBtnRemoveRuleClicked)
102               
103               
104                self.txtRuleName=uitree.get_object("txtRuleName")
105                self.txtProfileName=uitree.get_object("txtProfileName")
106               
107                #icon selector
108                self.treeIconContexts=uitree.get_object("treeIconContexts")
109                self.treeIconContexts.connect("cursor-changed",self.OnTreeIconContextsChanged)
110               
111                self.treeIcons=uitree.get_object("treeIcons")
112                self.treeIcons.connect("cursor-changed",self.OnTreeIconsChanged)
113               
114                self.txtIconName=uitree.get_object("txtIconName")
115                self.txtIconName.connect("changed",self.OnTxtIconNameChanged)
116                self.imgIconPreview=uitree.get_object("imgIconPreview")
117               
118                btnIconOk=uitree.get_object("btnIconOk")
119                btnIconOk.connect("clicked",self.OnBtnIconOkClicked)
120               
121                btnIconCancel=uitree.get_object("btnIconCancel")
122                btnIconCancel.connect("clicked",self.OnBtnIconCancelClicked)
123               
124               
125                #str unique id
126                #bool active
127                #str name
128                self.modelProfiles=Gtk.ListStore(str,bool,str)
129                self.treeProfiles.set_model(self.modelProfiles)
130               
131                col=Gtk.TreeViewColumn(_("Use"))
132                col.set_resizable(True)
133                cell = Gtk.CellRendererToggle()
134                col.pack_start(cell, True)
135                cell.set_property("activatable",True)
136                cell.set_property("radio",True)
137                cell.connect("toggled",self.OnCellRadioToggled,self.modelProfiles,1)
138                col.add_attribute(cell, 'active', 1)
139                self.treeProfiles.append_column(col)
140
141
142                col=Gtk.TreeViewColumn(_("Profile"))
143                col.set_resizable(True)
144                cell = Gtk.CellRendererText()
145                col.pack_start(cell, True)
146                col.add_attribute(cell, 'text', 2)
147                self.treeProfiles.append_column(col)
148               
149               
150                self.LoadProfiles()
151               
152               
153                #str unique id
154                #bool Used
155                # str name
156                # str icon-name
157                self.modelRules=Gtk.ListStore(str,bool,str,str)
158                self.treeRules.set_model(self.modelRules)
159               
160               
161                               
162               
163                col=Gtk.TreeViewColumn(_("Use"))
164                col.set_resizable(True)
165                cell = Gtk.CellRendererToggle()
166                col.pack_start(cell, True)
167                cell.set_property("activatable",True)
168                cell.connect("toggled",self.OnCellToggled,self.modelRules,1)
169                col.add_attribute(cell, 'active', 1)
170                self.treeRules.append_column(col)
171               
172                col=Gtk.TreeViewColumn(_("Rule"))
173                col.set_resizable(True)
174                cell = Gtk.CellRendererText()
175                col.pack_start(cell, True)
176                col.add_attribute(cell, 'text', 2)
177                self.treeRules.append_column(col)
178               
179                col=Gtk.TreeViewColumn()
180                col.set_resizable(True)
181                cell=Gtk.CellRendererPixbuf()
182                col.pack_start(cell, True)
183                col.add_attribute(cell, 'icon-name', 3)
184                cell.set_property("stock-size",Gtk.IconSize.DND)
185                self.treeRules.append_column(col)
186               
187               
188               
189                #str regex
190                #str type
191                self.modelRegex=Gtk.ListStore(str,str)
192                self.treeRegex.set_model(self.modelRegex)
193               
194                col=Gtk.TreeViewColumn(_("Regex"))
195                col.set_resizable(True)
196                cell = Gtk.CellRendererText()
197                cell.set_property("editable",True)
198                cell.connect("edited",self.OnCellEdited,self.modelRegex,0)
199                col.pack_start(cell, True)
200                col.add_attribute(cell, 'text', 0)
201                self.treeRegex.append_column(col)
202               
203                type_model=Gtk.ListStore(str)
204                type_model.append(["include"])
205                type_model.append(["exclude"])
206               
207                col=Gtk.TreeViewColumn(_("Type"))
208                col.set_resizable(True)
209                cell = Gtk.CellRendererCombo()
210                cell.set_property("model",type_model)
211                cell.set_property("editable",True)
212                cell.set_property("text-column",0)
213                cell.connect("edited",self.OnCellEdited,self.modelRegex,1)
214               
215                col.pack_start(cell, True)
216                col.add_attribute(cell, 'text', 1)
217                self.treeRegex.append_column(col)
218               
219               
220                # icon selector
221               
222                #str context name
223                self.modelContexts=Gtk.ListStore(str)
224                self.treeIconContexts.set_model(self.modelContexts)
225               
226                col=Gtk.TreeViewColumn(_("Context"))
227                col.set_resizable(True)
228                cell = Gtk.CellRendererText()
229                col.pack_start(cell, True)
230                col.add_attribute(cell, 'text', 0)
231
232                self.treeIconContexts.append_column(col)
233               
234                self.theme = Gtk.IconTheme.get_default()
235               
236               
237               
238                       
239                       
240                #str icon name
241                self.modelIcons=Gtk.ListStore(str)
242                self.treeIcons.set_model(self.modelIcons)
243               
244                col=Gtk.TreeViewColumn()
245                col.set_resizable(False)
246                cell=Gtk.CellRendererPixbuf()
247                col.pack_start(cell, False)
248                col.add_attribute(cell, 'icon-name', 0)
249                cell.set_property("stock-size",Gtk.IconSize.DND)
250                self.treeIcons.append_column(col)
251               
252                col=Gtk.TreeViewColumn(_("Icon name"))
253                col.set_resizable(False)
254                cell = Gtk.CellRendererText()
255                col.pack_start(cell, False)
256                col.add_attribute(cell, 'text', 0)
257                col.set_sort_order(Gtk.SortType.ASCENDING)
258                self.treeIcons.append_column(col)
259               
260               
261               
262               
263               
264                for c in self.theme.list_contexts():
265                        self.modelContexts.append([c])
266               
267                self.winProfiles.show_all()
268               
269
270        def OnDestroy(self,data):
271       
272                proxy=xmlrpclib.ServerProxy("https://server:9779")
273                proxy.set_conf("","MovingProfiles",self.db)
274       
275                Gtk.main_quit()
276
277        def OnCellRadioToggled(self,cell,path,model,col):
278
279                sel_iter=model.get_iter(path)
280                value=model.get_value(sel_iter,col)
281               
282                if not value:
283                        sel_id=model.get_value(sel_iter,0)
284                        self.db["setup"]["selected"]=sel_id
285                       
286                        self.LoadProfiles()
287               
288               
289               
290
291        def OnCellToggled(self,cell,path,model,col):
292                #print "Toggled: ",path
293                iter=model.get_iter(path)
294                value=model.get_value(iter,col)
295                model.set_value(iter,col,not value)
296       
297
298        def OnCellEdited(self,cell,path,text,model,col):
299                #print "Edited: ",path," with data ",text
300               
301                iter=model.get_iter(path)
302                model.set_value(iter,col,text)
303               
304               
305       
306        def OnBtnEditProfileClicked(self,data):
307       
308                #I do not know why in the name of god, treemodel
309                # messes it up all when operating it hidden
310                self.winRules.show_all()
311       
312                self.backup=copy.deepcopy(self.db)
313               
314                self.LoadProfile()
315               
316
317        def OnBtnAddProfileClicked(self,data):
318                h=hashlib.md5()
319                h.update(str(time.time()))
320                id=h.hexdigest()
321               
322                #print "New Profile ",id
323               
324                profile={}
325                profile["id"]=id
326                profile["name"]=_("New profile")
327                profile["rules"]=[]
328               
329                self.db["setup"]["profiles"].append(profile)
330               
331                self.LoadProfiles()
332               
333        def OnBtnRemoveProfileClicked(self,data):
334                model,iter=self.treeProfiles.get_selection().get_selected()
335               
336                src_id=model.get_value(iter,0)
337               
338                #default profile cannot be removed
339                if src_id==self.default_id:
340                        return
341               
342                if src_id==self.db["setup"]["selected"]:
343                        self.db["setup"]["selected"]=self.default_id
344                       
345               
346               
347                n=0
348               
349                for p in self.db["setup"]["profiles"]:
350                       
351                        if p["id"]==src_id:
352                                break
353                               
354                        n=n+1
355                       
356                self.db["setup"]["profiles"].pop(n)
357                       
358                self.LoadProfiles()
359       
360        def OnBtnDuplicateProfileClicked(self,data):
361                model,iter=self.treeProfiles.get_selection().get_selected()
362               
363                src_id=model.get_value(iter,0)
364               
365                print "Duplicating id ",src_id
366               
367                for p in self.db["setup"]["profiles"]:
368                        if p["id"]==src_id:
369                                src_profile=p
370                                break
371                               
372               
373                h=hashlib.md5()
374                h.update(str(time.time()))
375                id=h.hexdigest()
376               
377                profile={}
378                profile["id"]=id
379                profile["name"]=_("Copy of ")+src_profile["name"]
380                profile["rules"]=src_profile["rules"]
381               
382                self.db["setup"]["profiles"].append(profile)
383               
384                self.LoadProfiles()
385       
386               
387        def OnBtnEditRuleClicked(self,data):
388                self.winEditor.show_all()
389               
390                model,iter=self.treeRules.get_selection().get_selected()
391
392                if not iter==None:
393                        self.current_rule_id=model.get_value(iter,0)
394                       
395                        self.LoadRule()
396       
397        def LoadRule(self):
398
399                self.modelRegex.clear()
400               
401                for rule in self.db["setup"]["rules"]:
402               
403                        if rule["id"]==self.current_rule_id:
404                                self.txtRuleName.set_text(rule["name"])
405                                self.imgIconEditor.set_from_icon_name(rule["icon"],Gtk.IconSize.DND)
406                               
407                                for rg in rule["regex"]:
408                                        self.modelRegex.append([rg["pattern"],rg["type"]])
409               
410       
411        def OnBtnOkRuleClicked(self,data):
412       
413                if self.current_profile_id==self.default_id:
414                        #print "Ignoring changes"
415                        self.winRules.hide()
416                        self.LoadProfiles()
417                        return
418               
419                print ("Saving profile to {0}".format(self.current_profile_id))
420               
421               
422       
423                iter=self.modelRules.get_iter_first()
424                ids=[]
425                while iter!=None:
426                        id=self.modelRules.get_value(iter,0)
427                        active=self.modelRules.get_value(iter,1)
428                        name=self.modelRules.get_value(iter,2)
429                        icon=self.modelRules.get_value(iter,3)
430                       
431                        if active:
432                                ids.append(id)
433                       
434                        iter=self.modelRules.iter_next(iter)
435               
436               
437                for p in self.db["setup"]["profiles"]:
438                        if p["id"]==self.current_profile_id:
439                                p["name"]=self.txtProfileName.get_text()
440                                #print "Selected ids:"
441                                #print ids
442                                p["rules"]=ids
443                               
444                self.winRules.hide()
445                self.LoadProfiles()
446
447       
448        def OnBtnCancelRuleClicked(self,data):
449                self.db=self.backup
450                self.winRules.hide()
451       
452        def OnBtnOkEditClicked(self,data):
453                print ("Saving rule to {0}".format(self.current_rule_id))
454                for rule in self.db["setup"]["rules"]:
455                        if(rule["id"]==self.current_rule_id):
456                                rule["name"]=self.txtRuleName.get_text()
457                               
458                                icon_name,icon_size=self.imgIconEditor.get_icon_name()
459                                rule["icon"]=icon_name
460                                iter=self.modelRegex.get_iter_first()
461                                regex=[]
462                                while iter!=None:
463                                        p={}
464                                        p["pattern"]=self.modelRegex.get_value(iter,0)
465                                        p["type"]=self.modelRegex.get_value(iter,1)
466                                        regex.append(p)
467                                       
468                                        iter=self.modelRegex.iter_next(iter)
469
470                                rule["regex"]=regex
471                       
472                self.winEditor.hide()
473                self.LoadProfile()
474               
475               
476       
477       
478        def OnBtnCancelEditClicked(self,data):
479                self.winEditor.hide()
480               
481       
482       
483       
484        def OnBtnIconEditorClicked(self,data):
485                self.winIconSelector.show_all()
486               
487                for rule in self.db["setup"]["rules"]:
488                        if(rule["id"]==self.current_rule_id):
489                                self.txtIconName.set_text(rule["icon"])
490       
491        def LoadProfiles(self):
492       
493                self.modelProfiles.clear()
494                sel_id=self.db["setup"]["selected"]
495               
496                for p in self.db["setup"]["profiles"]:
497                        use=p["id"]==sel_id
498                       
499                        if (p["id"]==self.default_id):
500                                name=p["name"]+" "+_("(read only)")
501                        else:
502                                name=p["name"]
503                       
504                        self.modelProfiles.append([p["id"],use,name])
505       
506        def LoadProfile(self):
507                model,iter=self.treeProfiles.get_selection().get_selected()
508
509                if not iter==None:
510                        id=model.get_value(iter,0)
511                       
512                        print "Selected: ",id
513                       
514                        self.current_profile_id=id
515                       
516                        rmodel=self.treeRules.get_model()
517                        rmodel.clear()
518                       
519                       
520                        selected=[]
521                        for p in self.db["setup"]["profiles"]:
522                                if p["id"]==id:
523                                        self.txtProfileName.set_text(p["name"])
524
525                               
526                                        for r in p["rules"]:
527                                                selected.append(r)
528                                       
529                        for rule in self.db["setup"]["rules"]:
530                                rmodel.append([rule["id"],rule["id"] in selected,rule["name"],rule["icon"]])
531                               
532                               
533
534        def OnBtnAddRuleClicked(self,data):
535                h=hashlib.md5()
536                h.update(str(time.time()))
537                id=h.hexdigest()
538               
539                print ("New rule {0}".format(id))
540               
541                rule={}
542                rule["id"]=id
543                rule["name"]="New Rule"
544                rule["icon"]="user-info"
545                rule["regex"]=[{"pattern":"*.*","type":"include"}]
546                self.db["setup"]["rules"].append(rule)
547               
548                self.LoadProfile()
549               
550               
551        def OnBtnRemoveRuleClicked(self,data):
552                model,iter=self.treeRules.get_selection().get_selected()
553               
554                id=model.get_value(iter,0)
555               
556               
557                n=0
558                for rule in self.db["setup"]["rules"]:
559                        if rule["id"]==id:
560                                break
561                               
562                        n=n+1
563               
564                #print "Removing ",id, " at ",n
565                self.db["setup"]["rules"].pop(n)
566               
567                self.LoadProfile()
568
569       
570        def OnBtnAddRegexClicked(self,data):
571                self.modelRegex.append(["*","include"])
572                       
573        def OnBtnRemoveRegexClicked(self,data):
574                model,iter=self.treeRegex.get_selection().get_selected()
575               
576                model.remove(iter)
577               
578               
579        # *********** Icon selector **************
580       
581        def OnBtnIconOkClicked(self,data):
582       
583                self.imgIconEditor.set_from_icon_name(self.txtIconName.get_text(),Gtk.IconSize.DND)
584       
585                self.winIconSelector.hide()
586               
587       
588       
589        def OnBtnIconCancelClicked(self,data):
590       
591                self.winIconSelector.hide()
592       
593        def OnTreeIconContextsChanged(self,data):
594               
595                model,iter=self.treeIconContexts.get_selection().get_selected()
596               
597                if iter!=None:
598               
599                        context=model.get_value(iter,0)
600               
601                        self.modelIcons.clear()
602               
603                        for ic in self.theme.list_icons(context):
604                                self.modelIcons.append([ic])
605               
606       
607        def OnTreeIconsChanged(self,data):
608                model,iter=self.treeIcons.get_selection().get_selected()
609               
610                if iter!=None:
611                        name=self.modelIcons.get_value(iter,0)
612                        self.txtIconName.set_text(name)
613               
614       
615       
616       
617       
618        def OnTxtIconNameChanged(self,data):
619                name=self.txtIconName.get_text()
620               
621                self.imgIconPreview.set_from_icon_name(name,Gtk.IconSize.DND)
622       
623       
624        def LoadSetup(self):
625       
626                proxy=xmlrpclib.ServerProxy("https://server:9779")
627                self.db=proxy.get_conf("","MovingProfiles")
628               
629               
630if __name__=="__main__":
631
632        p=Editor()
633        Gtk.main()
Note: See TracBrowser for help on using the repository browser.