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

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

Update changelog

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