~benkai/unity/drawers

« back to all changes in this revision

Viewing changes to drawers/Drawer.py

  • Committer: Ian Berke
  • Date: 2012-08-18 02:49:28 UTC
  • Revision ID: ian.berke@gmail.com-20120818024928-frawwli8ip4u6xba
quickly saved

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
from drawers.PreferencesDrawersDialog import PreferencesDrawersDialog
43
43
 
44
44
(TARGET_ENTRY_TEXT, TARGET_ENTRY_PIXBUF) = range(2)
45
 
(COLUMN_TEXT, COLUMN_PIXBUF) = range(2)
 
45
(COLUMN_TEXT, COLUMN_PIXBUF, COLUMN_DISPNAME) = range(3)
46
46
iconpath="/opt/extras.ubuntu.com/drawers/share/drawers/media/"
47
47
settings = Gio.Settings("net.launchpad.drawers")
48
48
NUM_OPEN = settings.get_int("number-open") + 1
49
49
settings.set_int("number-open", NUM_OPEN)
50
50
REMINDER_NUM = settings.get_int("reminder-num")
 
51
 
 
52
BAD_CHARS=[';','[',']']
 
53
 
51
54
#REMINDER_NUM = 1
52
55
DONATE_URL = 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=GRXNFZQH5N7JS&lc=US&item_name=Drawers%20Development&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted'.replace('&','&')
53
56
def updateconfig(firstrun=None):
65
68
    global DEADREMOVE
66
69
    global DEADCONFIRM
67
70
    global NUM_OPEN
 
71
    global TEXT_ELLIPS
 
72
    global LIMIT_TEXT
68
73
    ICONSIZE=settings.get_int("iconsize")
69
74
    FONTSIZE=settings.get_int("fontsize")
70
75
    MAXICONS_ROW=settings.get_int("maxicons-row")
78
83
    QUICKLIST_MAX = settings.get_int("quicklist-max")
79
84
    DEADREMOVE=settings.get_boolean("dead-remove")
80
85
    DEADCONFIRM=settings.get_boolean("dead-confirm")
 
86
    TEXT_ELLIPS=settings.get_int("text-ellips")
 
87
    LIMIT_TEXT=settings.get_boolean("limit-text")
81
88
    if firstrun != None:
82
89
        settings.set_boolean("first-run", firstrun)
83
90
 
92
99
        dbg(debug, "Couldn't get icon_size from compizconfig")
93
100
        dbg(debug, repr(e))
94
101
        return None
95
 
    
96
 
    #import getpass,os
97
 
    #try:
98
 
        #conf='/home/'+getpass.getuser()+'/.gconf/apps/compiz-1/plugins/unityshell/screen0/options/%gconf.xml'
99
 
        #with open(conf,'r') as f:
100
 
            #for line in f.readlines():
101
 
                #if 'icon_size' in line:
102
 
                    #ind=line.find('value="')
103
 
                    #size=line[ind:].split('"')[1]
104
 
                    #dbg(debug, "gconf line: "+line)
105
 
                    #dbg(debug, "iconsize: "+size)
106
 
                    #return int(size)
107
 
    #except Exception as e:
108
 
        #dbg(debug,"Problem reading gconf file: ")
109
 
        #dbg(debug, repr(e))
110
 
        #return 32
111
 
    #dbg(debug,"Line not found")
112
 
#Using gconf caused conflict with gsettings/gio module therefore wrote 
113
 
#a function to parse the needed line in gconf xml file
114
102
 
115
103
updateconfig()
116
104
#Preferences for altering appearance - To be moved to config file
155
143
        Gtk.Window.__init__(self)
156
144
        self.debug=debug
157
145
        dbg(self.debug, "Debugging messages on")
 
146
        
 
147
        self.offset_x = 0
 
148
        self.offset_y = 0
 
149
        self.pin=False
 
150
        self.ordered=False
 
151
        self.dragging=False
 
152
        self.alpha=None
 
153
        
 
154
        #determine which monitor on multimonitor displays
158
155
        screen=self.get_screen()
159
 
        #determine which monitor on multimonitor displays
160
156
        num_mons = Gdk.Screen.get_n_monitors(screen)
161
 
        #print num_mons
162
 
        self.offset_x = 0
163
 
        self.offset_y = 0
 
157
        dbg(self.debug, "Detected %i monitors" %num_mons)
 
158
        
164
159
        if num_mons >1:
165
 
            #get screen geometry
166
 
            #(w,h)=(Gdk.Screen.get_width(screen),Gdk.Screen.get_height(screen))
167
 
            #print w,h
 
160
 
168
161
            #get position of mouse; assuming mouse doesn't move off monitor when launcher clicked
169
162
            display=Gdk.Display.get_default()
170
163
            (scr,x,y,modifier)=display.get_pointer()
171
164
            activemon=Gdk.Screen.get_monitor_at_point(screen,x,y)
172
 
            #rect=Gdk.Rectangle()
 
165
 
173
166
            rect=Gdk.Screen.get_monitor_geometry(screen,activemon)
174
167
            self.offset_x = rect.x
175
168
            self.offset_y = rect.y
176
 
            #print self.offset_x, self.offset_y
 
169
 
177
170
        self.set_visual(screen.get_rgba_visual())
178
 
        self.pin=False
179
 
        self.ordered=False
180
 
        self.dragging=False
181
 
        self.alpha=None
182
 
        #Determine position of launcher --> How will this work with non-Launcher Panel items!?
183
 
        #write functions to get these values from system!
 
171
        
 
172
        #Some settings for Unity Launcher and panel bar
184
173
        LF_ICONPADDING=10
185
174
        PANEL_HEIGHT=24
186
175
        
187
 
        #Get position (top to bottom) of the opened drawer
 
176
        #Get position (top to bottom) of the opened drawer in Launcher
188
177
        if UNITY:
189
178
            try:
190
179
                self.lf=Unity.LauncherFavorites.get_default().enumerate_ids()
191
180
                self.lfpos=self.lf.index(filename.split('/')[-1])+2
192
181
                LF_ICONSIZE=get_icon_size(self.debug)
193
182
            except Exception as inst:
194
 
                dbg(self.debug, type(inst), inst.args)
 
183
                dbg(self.debug, "%s\n%s"%(repr(inst), inst.args))
195
184
                self.lfpos=None
196
185
        else:
197
186
            self.lfpos=None
202
191
        else:
203
192
            self.anchorpos=(self.lfpos * (LF_ICONSIZE+LF_ICONPADDING))+PANEL_HEIGHT
204
193
        
 
194
        #Start setting up the drawer with the .desktop file
205
195
        if filename != None:  
206
196
            self.filename=filename
207
197
            try:
208
198
                self.df=DesktopEntry(filename) # will parse the .desktop file
209
199
                if self.df.hasKey('Actions'):
210
200
                    self.actions=self.df.get('Actions', 'Desktop Entry').split(';')
211
 
                    #function to remove duplicates
212
 
                    #self.actions=list(set(self.actions)) #screws up order
213
 
                    #self.actions=filter(lambda e: e not in self.actions, self.actions)
 
201
                    #function to remove duplicates just in case
214
202
                    for action in self.actions:
215
203
                        if self.actions.count(action)>1: self.actions.remove(action)
216
204
                    if DEADREMOVE: self.deadlinkcheck()
217
 
 
218
205
                else:
219
206
                    self.actions=[]
 
207
                    
220
208
            except Exception as e:
221
209
                dbg (self.debug,"Couldn't read desktop file")
222
210
                dbg (self.debug,repr(e))
223
211
                Gtk.main_quit()
224
 
 
 
212
            #Add any items passed to program if it's not in actions already
225
213
            for item in addfile:
226
214
                if item !=None and item.rstrip('/').split('/')[-1] not in self.actions:
227
215
                    self.add_file(item)
228
216
            self.builddrawer()
229
217
        
 
218
        #connect events
230
219
        
231
 
        self.set_decorated(False)
232
 
        self.set_app_paintable(True)
233
220
        self.connect("delete-event", Gtk.main_quit)
234
221
        self.connect("key-press-event", self.handle_keypresses)
235
222
        self.connect("key-release-event", self.handle_keyrelease)
236
223
        self.connect("enter-notify-event", self.on_mouse_enter)
 
224
        
237
225
        #Set up dragNdrop to add URIs to open draw
238
 
        #self.connect("drag-motion", self.motion_cb)
239
226
        self.connect("drag-drop", self.drop_cb)
240
227
        self.connect("drag-data-received", self.got_data_cb)
241
228
        self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
242
229
        self.drag_dest_set_target_list(None)
243
230
        self.drag_dest_add_uri_targets()
244
 
        #self.drag_dest_add_text_targets()
245
 
        #Format the drawer - not ideal would like to implement more unity 
246
 
        #like style that changes with theme
247
 
 
 
231
        
 
232
        
 
233
        #Format the drawer 
 
234
        self.set_decorated(False)
 
235
        self.set_app_paintable(True)
248
236
        css = Gtk.CssProvider()
 
237
        
249
238
        #Want the drawer background and font to change with average of desktop background
250
239
        self.BG_rgb= [int(i*COLOR_SCALING) for i in self.get_color() ]
251
240
        if sum(self.BG_rgb)/3 > 175:
265
254
        self.title.get_style_context().add_class('title')
266
255
        self.toolbarL.get_style_context().add_class('title')
267
256
        self.toolbarR.get_style_context().add_class('title')
268
 
#        self.get_style_context().add_class('background2')
 
257
        
 
258
        #Draw the window with cairo
269
259
        self.connect("draw", self.draw_window_cb)
 
260
        
 
261
        #Realize the window
270
262
        self.show_all()
 
263
        
 
264
        #Put the keyboard focus in the iconview
271
265
        self.iconview.grab_focus()
 
266
        
 
267
        #Don't draw anything until we've moved to the right spot
272
268
        gdkwindow=self.get_window()
273
 
        
274
269
        if gdkwindow: gdkwindow.freeze_updates()
 
270
        
275
271
        self.set_gravity(Gdk.Gravity.WEST)
276
 
        self.move(MARGIN+self.offset_x, self.anchorpos+self.offset_y)#Gdk.Screen.height()/2)
 
272
        self.x, self.y=(MARGIN+self.offset_x, self.anchorpos+self.offset_y)
 
273
        self.move(self.x,self.y)
277
274
        if gdkwindow: gdkwindow.thaw_updates()
278
275
        self.queue_draw()
 
276
        
279
277
        if FIRST_RUN:
280
278
            self.on_help_activate(None)
281
279
            updateconfig(False)
310
308
        self.headerbox=Gtk.Box()
311
309
        self.outerbox.pack_start(self.headerbox,False,True,1)
312
310
        
313
 
        
314
 
        
315
311
        #Setup a Toolbar using UI        
316
312
        #Create action group for UI
317
313
        action_group = Gtk.ActionGroup("my_actions")
357
353
        
358
354
        self.toolbarL = self.uimanager.get_widget("/ToolBarL")
359
355
        self.toolbarL.set_app_paintable(True)
360
 
 
361
356
        
362
357
        #Setup a TitleBar
363
358
        self.title=Gtk.Label(self.df.get('Name', 'Desktop Entry'))
414
409
 
415
410
    def place_items(self):
416
411
        """Clears the iconview model and iterates through a DesktopEntry to repopulate"""
417
 
        self.model = Gtk.ListStore(str, GdkPixbuf.Pixbuf)
 
412
        self.model = Gtk.ListStore(str, GdkPixbuf.Pixbuf, str)
418
413
        
419
414
        if self.df.hasKey('Actions'):
420
415
            for action in self.actions:
436
431
                    self.actions.remove(action)
437
432
                    pass
438
433
        #iconview must be reformatted to get correct size_request()
439
 
        self.iconview.set_text_column(COLUMN_TEXT)
 
434
        self.iconview.set_text_column(COLUMN_DISPNAME)
440
435
        self.iconview.set_pixbuf_column(COLUMN_PIXBUF)
441
436
        self.iconview.set_columns(MAXICONS_ROW)
442
437
        self.iconview.set_column_spacing(COLUMN_SPACING)
492
487
                
493
488
            if pixbuf==None:
494
489
                pixbuf = Gtk.IconTheme.get_default().load_icon(icon_name, ICONSIZE, 0)
495
 
 
496
 
            self.model.append([text, pixbuf])
 
490
            
 
491
            if LIMIT_TEXT and len(text)>TEXT_ELLIPS:
 
492
                if TEXT_ELLIPS==0:
 
493
                    ellips=''
 
494
                else:
 
495
                    ellips='...'
 
496
                dispname=(text[:TEXT_ELLIPS]+ellips)
 
497
            else:
 
498
                dispname=text
 
499
            self.model.append([text, pixbuf, dispname])
497
500
            succeed=True
498
501
        except:
499
502
            succeed=False
508
511
        
509
512
    def execute(self, value):            
510
513
        """Executes the Exec line of a Desktop Action group"""
511
 
        group='Desktop Action '+value
 
514
        group='Desktop Action '+self.cleanname(value)
512
515
        execline=self.df.get("Exec",group)
513
516
        args=shlex.split(execline)
514
517
        subprocess.Popen(args)
552
555
                    'Type':filetype,
553
556
                    'Icon':icon,
554
557
                    'OnlyShowIn':'Unity;'}
555
 
        group='Desktop Action ' + name
 
558
        group='Desktop Action ' + name.replace(';','').replace('[','').replace(']','')
556
559
        dbg(self.debug, " Name: %s \n Exec: %s \n Type: %s \n Icon: %s"%(groupentry['Name'],
557
560
                                                                         groupentry['Exec'],
558
561
                                                                         groupentry['Type'],
561
564
        self.df.addGroup(group)
562
565
        for key in groupentry:
563
566
            self.df.set(key,groupentry[key],group)
564
 
        self.actions.append(name)
 
567
        self.actions.append(name.replace(';','').replace('[','').replace(']',''))
565
568
        self.df.set('Actions', ';'.join(self.actions),'Desktop Entry')
566
569
        dbg(self.debug, " Actions: %s"%';'.join(self.actions))
567
570
        self.savedf()
569
572
    def delete_selected(self,selection):
570
573
        """Takes an action name and removes it from the .desktop file
571
574
        and redraws the iconview"""
572
 
        self.df.removeGroup('Desktop Action ' + selection)
573
 
        self.actions.remove(selection)
 
575
        self.df.removeGroup('Desktop Action ' + self.cleanname(selection))
 
576
        self.actions.remove(self.cleanname(selection))
574
577
        if self.actions !=[]:
575
578
            self.df.set('Actions', ';'.join(self.actions),'Desktop Entry')
576
579
        else:
708
711
            dbg(self.debug, "problem reordering")
709
712
            dbg(self.debug, repr(e))
710
713
            pass
711
 
        
 
714
    def cleanname(self,name):
 
715
        for character in BAD_CHARS:
 
716
            name=name.replace(character,'')
 
717
        return name
712
718
        
713
719
 
714
720
        
774
780
        
775
781
        
776
782
    def on_editname_activate(self, widget, data=None):
777
 
        newname=self.getText(_('Please enter a new name'))
 
783
        selected_name=self.model[self.iconview.get_selected_items()[0]][0]
 
784
        newname=self.getText(_('Please enter a new name'), Entry=selected_name)
778
785
        if newname != None:
779
 
            selected_name=self.model[self.iconview.get_selected_items()[0]][0]
780
786
            # need to copy keys and create new group with new action link
 
787
            selected_name=self.cleanname(selected_name)
781
788
            groupcopy={}
782
789
            for key in ['Type','Icon','Exec','OnlyShowIn']:
783
 
                
784
790
                groupcopy[key]=self.df.get(key,'Desktop Action '+selected_name)
785
791
            groupcopy['Name']=newname
786
 
            self.df.addGroup('Desktop Action '+newname)
 
792
            newname=self.cleanname(newname)
 
793
            #only copy to new group if cleaned up name changes
 
794
            if selected_name != newname:
 
795
                self.df.addGroup('Desktop Action '+newname)
 
796
                dbg(self.debug, "copying group %s to %s"%(selected_name, newname))
 
797
                self.df.removeGroup('Desktop Action '+selected_name)
 
798
                #replace action in list without changing order
 
799
                index=self.actions.index(selected_name)
 
800
                self.actions[index]=newname
 
801
                self.df.set('Actions',';'.join(self.actions),'Desktop Entry')
 
802
            #copy keys even if some are the same because name has changed
787
803
            for key in groupcopy:
788
804
                self.df.set(key, groupcopy[key], 'Desktop Action '+newname)
789
 
            self.df.removeGroup('Desktop Action '+selected_name)
790
 
            self.actions.remove(selected_name)
791
 
            self.actions.append(newname)
792
 
            self.df.set('Actions',';'.join(self.actions),'Desktop Entry')
793
805
            self.savedf()
794
806
            self.place_items()
795
807
    
796
808
    def on_editexec_activate(self,widget,data=None):
797
 
        selected_name=self.model[self.iconview.get_selected_items()[0]][0]
 
809
        selected_name=self.cleanname(self.model[self.iconview.get_selected_items()[0]][0])
798
810
        selected_exec=self.df.get('Exec','Desktop Action ' + selected_name)
 
811
        dbg(self.debug, "changing exec line from %s"%(selected_exec))
799
812
        newexec=self.getText('Please edit execution line',label='Exec',Entry=selected_exec)
800
813
        if (newexec != selected_exec) and (newexec != None):
 
814
            dbg(self.debug, "    to %s"%(new_exec))
801
815
            self.df.set('Exec',newexec,'Desktop Action ' + selected_name)
802
816
            self.savedf()
803
817
            self.place_items()
833
847
        self.place_items()
834
848
        context.finish(True, False, time)
835
849
    def window_drag(self, widget, data):
836
 
        self.pos_x, self.pos_y = self.get_position()
837
 
        
838
 
        #print "dragging from: "+str(self.pos_x) +' '+str(self.pos_y)
839
 
        #print data.x, data.y
840
 
        self.move(self.pos_x+int(data.x)-MARGIN,self.pos_y+int(data.y)+self.anchorpos/2)
 
850
        dbg(self.debug, "Starting at: %i, %i"%(self.x,self.y))
 
851
        self.begin_move_drag(1, data.x_root, data.y_root, data.time)
 
852
        self.x, self.y=self.get_position()
841
853
        pass
842
854
 
843
855
    def on_button_clicked(self,widget, data=None):
972
984
        elif event.type == Gdk.EventType.BUTTON_RELEASE and self.dragging==True:
973
985
            self.dragging=False
974
986
 
 
987
 
975
988
    def on_drag_begin(self,widget, data):
976
989
        self.dragging=True
977
990
    
1030
1043
        if self.ordered:
1031
1044
            newactions=[]
1032
1045
            for row in range(0,len(self.model)):
1033
 
                newactions.append(self.model[row][0])
 
1046
                newactions.append(self.cleanname(self.model[row][0]))
1034
1047
            self.df.set('Actions', ';'.join(newactions),'Desktop Entry')
1035
1048
            self.actions=newactions
1036
1049
            self.savedf()