~muelnet/heybuddy/pulltimes

91 by jezra
copyright notices
1
'''
2
this is a part of the heybuddy project
3
copyright 2010 jezra lickter http://www.jezra.net
4
'''
1 by jezra
init
5
import gtk
6
import gobject
152 by jezra
n900 scrolling of the settings and filters(I hope)
7
from DentScroller import DentScroller
1 by jezra
init
8
from Dent import Dent
53 by jezra
spell check
9
try:
133 by jezra
better quitter crap
10
	import gtkspell
11
	has_gtkspell=True
53 by jezra
spell check
12
except:
133 by jezra
better quitter crap
13
	has_gtkspell=False
152 by jezra
n900 scrolling of the settings and filters(I hope)
14
15
from PlatformSpecific import has_hildon
1 by jezra
init
16
#make a fake enumeration
226 by jezra
get text of urllib2 errors
17
DENT,MENTION,DIRECT,CONVERSATION,USER,GROUP,ACCOUNT,ABOUT = range(8)
7 by jezra
communication error message
18
STATUS_MESSAGE,ERROR_MESSAGE = range(2)
1 by jezra
init
19
class MainWindow(gtk.Window,gobject.GObject):
133 by jezra
better quitter crap
20
	__gsignals__ = {
21
		'update-status': (
22
			gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
23
							 (gobject.TYPE_STRING,)
24
			),
25
		'get-conversation': (
26
			gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
27
							 (gobject.TYPE_INT,)
28
			),
29
		'show-user': (
30
			gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
31
							 (gobject.TYPE_STRING,)
32
			),
33
		'show-group': (
34
			gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
35
							 (gobject.TYPE_STRING,)
36
			),
37
		'notebook-page-change': (
38
			gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
39
							 (gobject.TYPE_INT,gobject.TYPE_INT)
40
			),
41
		'follow-user' : (
42
			gobject.SIGNAL_RUN_FIRST,gobject.TYPE_NONE,
43
				(gobject.TYPE_STRING,gobject.TYPE_BOOLEAN)
44
			),
45
		'join-group' : (
46
			gobject.SIGNAL_RUN_FIRST,gobject.TYPE_NONE,
47
				(gobject.TYPE_STRING,gobject.TYPE_BOOLEAN)
48
			),
49
		'add-tag-filter': (
50
			gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
51
						 (gobject.TYPE_STRING,)
52
			),
53
		'remove-tag-filter' : (
54
			gobject.SIGNAL_RUN_FIRST,gobject.TYPE_NONE,
55
				(gobject.TYPE_STRING,)
56
			),
57
		'add-user-filter': (
58
			gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
59
						 (gobject.TYPE_STRING,)
60
			),
61
		'remove-user-filter' : (
62
			gobject.SIGNAL_RUN_FIRST,gobject.TYPE_NONE,
63
				(gobject.TYPE_STRING,)
64
			),
65
		'add-group-filter': (
66
			gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
67
						 (gobject.TYPE_STRING,)
68
			),
69
		'remove-group-filter' : (
70
			gobject.SIGNAL_RUN_FIRST,gobject.TYPE_NONE,
71
				(gobject.TYPE_STRING,)
72
			),
73
		'clear-respond-to-id' : (
74
			gobject.SIGNAL_RUN_FIRST,gobject.TYPE_NONE,
75
				()
76
			),
77
		'quit' : (
78
			gobject.SIGNAL_RUN_FIRST,gobject.TYPE_NONE,
79
				()
167 by jezra
ctrl+w start
80
			),
81
		'window-to-tray' : (
82
			gobject.SIGNAL_RUN_FIRST,gobject.TYPE_NONE,
83
				()
133 by jezra
better quitter crap
84
			)		 
85
	}
86
	def __init__(self,app_name,version,branch):
87
		gtk.Window.__init__(self,gtk.WINDOW_TOPLEVEL)	
88
		gobject.GObject.__init__(self)
229 by jezra
I bet the horseshit time fucking shit will make lots of shit break
89
		self.textlimit = 140 #this is default
133 by jezra
better quitter crap
90
		self.last_clicked_label=None
91
		self.do_submit=False
92
		self.is_fullscreen=False
93
		self.set_title(app_name)
94
		self.set_default_size(500,500)
95
		self.notebook_current_page=DENT
184 by jezra
start of int
96
		self.string_update_textview=_("Update Status")
97
		self.string_direct_message=_("Direct Message to")
170 by jezra
ctrl+things do stuff
98
		self.string_status_frame=self.string_update_textview
133 by jezra
better quitter crap
99
		self.conversation_page=None
100
		self.pre_conversation_page=None
101
		self.user_page=None
102
		self.pre_user_page=None
103
		self.pre_group_page=None
145 by jezra
start of direct messages
104
		self.is_direct_message_mode=False
133 by jezra
better quitter crap
105
		#create an accellerator group for this window
106
		accel = gtk.AccelGroup()
107
		#add the ctrl+q to quit
108
		accel.connect_group(gtk.keysyms.q, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE, self.quit )
167 by jezra
ctrl+w start
109
		#add ctrl+w to set tray app and close to tray
110
		accel.connect_group(gtk.keysyms.w, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE, self.window_to_tray )
170 by jezra
ctrl+things do stuff
111
		#add the ctrl+c to copy
133 by jezra
better quitter crap
112
		accel.connect_group(gtk.keysyms.c, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE, self.copy )
170 by jezra
ctrl+things do stuff
113
		#add the ctrl+Page_Up and ctrl Page_Down to notebook focus
114
		accel.connect_group(gtk.keysyms.Page_Up, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE, self.focus_notebook )
115
		accel.connect_group(gtk.keysyms.Page_Down, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE, self.focus_notebook )
116
		#set focus for ctrl+u		
117
		accel.connect_group(gtk.keysyms.u, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE, self.focus_update_textview )
118
		#set focus for ctrl+l		
119
		accel.connect_group(gtk.keysyms.l, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE, self.focus_update_textview)
133 by jezra
better quitter crap
120
		#lock the group
121
		accel.lock()
122
		#add the group to the window
123
		self.add_accel_group(accel)
124
		
125
		''' make the GUI stuff '''
126
		#start with vbox
127
		self.main_vbox = gtk.VBox()
128
		#add the vbox to the self
129
		self.add(self.main_vbox)
130
		#make a notebook
131
		self.notebook = gtk.Notebook()
132
		#pack the note book in the vbox
133
		self.main_vbox.pack_start(self.notebook)
134
		#make the update status area
135
		self.update_textbuffer = gtk.TextBuffer()
136
		self.update_textview = gtk.TextView(self.update_textbuffer)
137
		#the text view needs to be multiline
138
		self.update_textview.set_wrap_mode(gtk.WRAP_WORD_CHAR)
139
		#try and add spell checking to the textview
140
		if has_gtkspell:
141
			#what if there is no aspell library?
142
			try:
143
				self.spell = gtkspell.Spell(self.update_textview)
144
				self.has_spell_library=True
145
			except Exception:
146
				#bummer
147
				self.has_spell_library=False
148
				print Exception.message
149
				
150
		#add a shadowed frame around the textview
151
		tvframe = gtk.Frame();
152
		tvframe.set_shadow_type(gtk.SHADOW_IN)
153
		tvframe.add(self.update_textview)
154
		#what happens when text is inserted in the buffer?
184 by jezra
start of int
155
		self.update_textbuffer.connect('insert-text', self.update_textbuffer_insert)
133 by jezra
better quitter crap
156
		#what happens when the buffer is changed?
184 by jezra
start of int
157
		self.update_textbuffer.connect('changed', self.update_textbuffer_changed)
133 by jezra
better quitter crap
158
		update_frame = gtk.Frame()
145 by jezra
start of direct messages
159
		self.update_status_label = gtk.Label(self.string_status_frame)
133 by jezra
better quitter crap
160
		update_frame.add(tvframe)
161
		update_frame.set_label_widget(self.update_status_label)
162
		#make an hbox for the update frame and throbber
163
		update_hbox = gtk.HBox(False)
164
		self.throbber = gtk.Image()
165
		update_hbox.pack_start(update_frame,True,True)
166
		update_hbox.pack_start(self.throbber,False,False)
167
		self.main_vbox.pack_start(update_hbox,False,False,0)
168
		#make a message label that we might need to display to the user
169
		self.message_label = gtk.Label()
170
		self.main_vbox.pack_start(self.message_label,False,False,0)
171
		#check for a keypress
172
		self.connect('key-press-event',self.keypressed)
173
		
174
	def keypressed(self,widget,event):
175
		if event.keyval == 65475:
176
			self.toggle()
177
			
178
	def toggle(self):
179
		if self.is_fullscreen :
180
			self.unfullscreen()
181
			self.is_fullscreen=False
182
		else:
183
			self.fullscreen()
184
			self.is_fullscreen=True
185
	
186
	def run(self):
187
		#we don't want any signals until the app is running
184 by jezra
start of int
188
		self.notebook.connect('switch-page', self.notebook_page_switch )
133 by jezra
better quitter crap
189
	
190
	def show_some(self):
191
		self.show_all()
192
		#hide *some* stuff
193
		self.message_label.hide()
194
	
195
	def add_notebook_page(self,widget,title):
196
		self.notebook.append_page(widget,title)
197
	
198
	def set_notebook_page(self,index):
199
		self.notebook.set_current_page(index)
200
		
201
	def get_notebook_index(self):
202
		return self.notebook.get_current_page()
203
		
204
	def add_dent(self,data,target_index,is_conv=False,conv_backwards=False):
205
		d = Dent(data)
184 by jezra
start of int
206
		d.connect('reply-clicked', self.reply_clicked)
207
		d.connect('view-conversation-clicked', self.view_conversation)
208
		d.connect('user-clicked', self.view_user)
209
		d.connect('text-label-clicked',self.dent_text_clicked)
210
		d.connect('redent-clicked',self.redent_clicked)
133 by jezra
better quitter crap
211
		#add this to the dent it's targeting
212
		target = self.get_target_scroller(target_index)
213
		target.add_dent(d,is_conv,conv_backwards)	
214
		#return the dent
215
		return d
216
	#filters
217
	def add_tag_filter(self,filterframe,tag):
218
		self.emit('add-tag-filter',tag)
219
		
220
	def remove_tag_filter(self,filterframe,tag):
221
		self.emit('remove-tag-filter',tag)
222
	
223
	def set_tag_filters(self, filters ):
224
		self.filterpage.set_tag_filters(filters)
225
	
226
	def add_user_filter(self,filterframe,user):
227
		self.emit('add-user-filter',user)
228
		
229
	def remove_user_filter(self,filterframe,user):
230
		self.emit('remove-user-filter',user)
231
	
232
	def set_user_filters(self, filters ):
233
		self.filterpage.set_user_filters(filters)
234
	
235
	def add_group_filter(self,filterframe,group):
236
		self.emit('add-group-filter',group)
237
		
238
	def remove_group_filter(self,filterframe,group):
239
		self.emit('remove-group-filter',group)
240
	
241
	def set_group_filters(self, filters ):
242
		self.filterpage.set_group_filters(filters)
243
	
188 by jezra
fuck you pygtk for not letting me delete that damn newline char
244
	def update_textbuffer_insert(self, textbuffer, iter, text, length):
133 by jezra
better quitter crap
245
		if text=="\n" :
188 by jezra
fuck you pygtk for not letting me delete that damn newline char
246
			#TODO: delete the fucking \n. PS fuck you PYGTK for making this
247
			#so fucking hard
248
			#textbuffer.backspace(iter,True,True) doesn't work
133 by jezra
better quitter crap
249
			self.do_submit=True
188 by jezra
fuck you pygtk for not letting me delete that damn newline char
250
229 by jezra
I bet the horseshit time fucking shit will make lots of shit break
251
	def set_textlimit(self, limit):
252
		self.textlimit = int(limit)
253
		
170 by jezra
ctrl+things do stuff
254
	def emit_update_textview(self):
133 by jezra
better quitter crap
255
		#get the text from the buffer
256
		start_iter = self.update_textbuffer.get_start_iter()
257
		end_iter = self.update_textbuffer.get_end_iter()
258
		text=self.update_textbuffer.get_text(start_iter,end_iter).strip()
259
		if(text!=""):
188 by jezra
fuck you pygtk for not letting me delete that damn newline char
260
			#disable the textview
261
			self.update_textview.set_sensitive(False)
184 by jezra
start of int
262
			self.emit('update-status',text)
188 by jezra
fuck you pygtk for not letting me delete that damn newline char
263
			
264
	'''function process_update_response
265
	@param self self
266
	@param response the string response returned by the communicator
267
	'''
268
	def emit_update_textview_responsed(self, error = False):
269
		if not error:
133 by jezra
better quitter crap
270
			#detach the spellchecker
271
			self.detach_gtkspell()
272
			#clear the text area
184 by jezra
start of int
273
			self.update_textbuffer.set_text('')
133 by jezra
better quitter crap
274
			#reattach the spellchecker
275
			self.connect_gtkspell()
188 by jezra
fuck you pygtk for not letting me delete that damn newline char
276
		#enable the textview
277
		self.update_textview.set_sensitive(True)
133 by jezra
better quitter crap
278
			
188 by jezra
fuck you pygtk for not letting me delete that damn newline char
279
	'''function update_textbuffer_changed
280
	@param self self
281
	@param textbuffer - the textbuffer that called the function
282
	'''
133 by jezra
better quitter crap
283
	def update_textbuffer_changed(self,textbuffer):
284
		if self.do_submit:
170 by jezra
ctrl+things do stuff
285
			self.emit_update_textview()
133 by jezra
better quitter crap
286
			self.do_submit=False
188 by jezra
fuck you pygtk for not letting me delete that damn newline char
287
			return 
288
		#we aren't submitting, check the amount of characters
133 by jezra
better quitter crap
289
		char_count = textbuffer.get_char_count()
229 by jezra
I bet the horseshit time fucking shit will make lots of shit break
290
		self.string_update_textview_append_count(self.textlimit-char_count)
291
		if (char_count > self.textlimit ):
292
			#prune the text to self.textlimit chars
293
			start_iter = textbuffer.get_iter_at_offset(self.textlimit)
133 by jezra
better quitter crap
294
			end_iter = textbuffer.get_end_iter()
295
			textbuffer.delete(start_iter,end_iter)
145 by jezra
start of direct messages
296
		elif(char_count==0 and not self.is_direct_message_mode):
188 by jezra
fuck you pygtk for not letting me delete that damn newline char
297
			#the text has possibly been deleted, clear associated stuff
133 by jezra
better quitter crap
298
			self.emit('clear-respond-to-id')
299
300
	def notebook_page_switch(self,nb,page,page_num):
301
		old_page = self.notebook_current_page
302
		self.notebook_current_page=page_num
303
		self.emit('notebook-page-change',old_page,page_num)
304
305
170 by jezra
ctrl+things do stuff
306
	def string_update_textview_append_count(self,count):
229 by jezra
I bet the horseshit time fucking shit will make lots of shit break
307
		if count<self.textlimit:
145 by jezra
start of direct messages
308
			string = "%s %d" % (self.string_status_frame,count)
133 by jezra
better quitter crap
309
		else:
145 by jezra
start of direct messages
310
			string = self.string_status_frame
133 by jezra
better quitter crap
311
		self.update_status_label.set_text(string)
312
	
313
	def set_message(self,message,type=STATUS_MESSAGE):
314
		if type==ERROR_MESSAGE:
315
			markup = "<span color='#dd0000'>%s</span>" % message
316
		else:
317
			markup = message
318
		self.message_label.set_markup(markup)
319
		#show the self.message label
320
		self.message_label.show()
321
	
322
	def close_conversation(self,widget):
323
		self.conversation_vbox.hide_all()
324
		self.notebook.set_current_page(self.pre_conversation_page)
325
	
326
	def quit(self,accel_group, acceleratable, keyval, modifier):
327
		self.emit("quit")
328
	
329
	def userpage_hide(self,widget):
330
		self.userpage.hide_all()
331
		self.set_notebook_page(self.pre_user_page)
332
	
333
	def grouppage_hide(self,widget):
334
		self.grouppage.hide_all()
335
		self.set_notebook_page(self.pre_group_page)
336
	
337
	def follow_user(self,widget,name,bool):
338
		self.emit('follow-user',name,bool)
339
	
340
	def join_group(self,widget,name,bool):
341
		self.emit('join-group',name,bool)
342
		
343
	def copy(self,accel_group,acceleratable,keyval,modifier):
344
		'''the user want to copy some text'''
345
		#can we get the selected text?
346
		try:
347
			#get the bounds of the last clicked label
348
			bounds = self.last_clicked_label.get_selection_bounds()
349
			#is the bounds empty or not?
350
			if bounds != ():
351
				#get the text from the last clicked label
352
				text = self.last_clicked_label.get_text()
353
				#get the text within the bounds
354
				selection = text[bounds[0]:bounds[1]]
355
				# get the clipboard
356
				clipboard = gtk.Clipboard()
357
				#set clipboard text
358
				clipboard.set_text(selection)
359
				#store that shit!
360
				clipboard.store()
361
		except:
362
			pass
363
		
167 by jezra
ctrl+w start
364
	'''
365
	function window_to_tray
366
	emit 'window-to-tray' signal
367
	'''
368
	def window_to_tray(self,accel_group,acceleratable,keyval,modifier):
369
		self.emit('window-to-tray')
370
		
133 by jezra
better quitter crap
371
	def connect_gtkspell(self):
372
		if has_gtkspell and self.has_spell_library:
373
			self.spell = gtkspell.Spell(self.update_textview)
374
			
375
	def detach_gtkspell(self):
376
		if has_gtkspell and self.has_spell_library:
377
			self.spell.detach()
378
379
	def set_throbber(self,image_path):
380
		self.throbber.set_from_file(image_path)
381
		
382
	def dent_text_clicked(self,dent,text_label):
383
		self.last_clicked_label = text_label
145 by jezra
start of direct messages
384
	
385
	def set_is_direct_message_mode(self,mode,user=None):
386
		self.is_direct_message_mode=mode
387
		if mode:
388
			self.string_status_frame="%s %s" % (self.string_direct_message, user)
389
		else:
170 by jezra
ctrl+things do stuff
390
			self.string_status_frame=self.string_update_textview
150 by jezra
more shit
391
			#clear the text
392
			self.update_textbuffer.set_text("")
145 by jezra
start of direct messages
393
		#update the label text
394
		self.update_status_label.set_text(self.string_status_frame)
170 by jezra
ctrl+things do stuff
395
396
	#we may need to set the focus on the notebook
397
	def focus_notebook(self,accel_group, acceleratable, keyval, modifier):
398
		#set the focus on the notebook
399
		self.notebook.grab_focus()
400
	
401
	#we may need to set the focus on the status update textview
402
	def focus_update_textview(self,accel_group, acceleratable, keyval, modifier):
403
		#set the focus on the notebook
404
		self.update_textview.grab_focus()
405
		if keyval==gtk.keysyms.l:
184 by jezra
start of int
406
			self.update_textbuffer.set_text('')
170 by jezra
ctrl+things do stuff
407