Eduardo Mucelli Rezende Oliveira has proposed merging 
lp:~eduardo-mucelli/cairo-dock-plug-ins-extras/Twitter into 
lp:cairo-dock-plug-ins-extras.

Requested reviews:
  Cairo-Dock Team (cairo-dock-team)

For more details, see:
https://code.launchpad.net/~eduardo-mucelli/cairo-dock-plug-ins-extras/Twitter/+merge/97325

Direct messages are shown in a gtk-based menu, and it is possible to reply 
them. Fixing the post method, and the stream callback.
-- 
https://code.launchpad.net/~eduardo-mucelli/cairo-dock-plug-ins-extras/Twitter/+merge/97325
Your team Cairo-Dock Team is requested to review the proposed merge of 
lp:~eduardo-mucelli/cairo-dock-plug-ins-extras/Twitter into 
lp:cairo-dock-plug-ins-extras.
=== modified file 'Twitter/ChangeLog'
--- Twitter/ChangeLog	2012-03-10 20:27:57 +0000
+++ Twitter/ChangeLog	2012-03-14 00:09:17 +0000
@@ -1,3 +1,4 @@
+0.1.3: (March/14/2012): Direct messages are shown in a gtk-based menu, and it is possible to reply them. Fixing the post method, and the stream callback.
 0.1.2: (March/8/2012): Adding the emblem maker to inform the number of new tweets from the stream.
 0.1.1: (March/6/2012): Using callback instead of a thread to check for the new tweet from the stream, faster, better, and cleaner. Fixed new tweets count that was not being updated. Increased modularization.
 0.1: (March/5/2012): Finally, after long work, compatible with Twitter Stream, and using it to show the tweets that just arrived. Changed the "received" icon for direct messages, and added the "new" for new tweets, both are from the icon pack Basic made by Pixel Maker, http://pixel-mixer.com

=== modified file 'Twitter/Twitter'
--- Twitter/Twitter	2012-03-10 20:27:57 +0000
+++ Twitter/Twitter	2012-03-14 00:09:17 +0000
@@ -24,14 +24,14 @@
 # The plugin is going to inform that you are successfully connected.
 
 # To see the received tweets right-click on the icon -> Twitter -> New tweets.
-# To see the received direct messages right-click on the icon -> Twitter -> Received direct messages
+# To see the received direct messages right-click on the icon -> Twitter -> Received direct messages. You can reply one of them just by left-clicking on it.
 # To see some user's info right-click on the icon -> Twitter -> Info
 
 import os, webbrowser, simplejson, threading, Queue, urllib2
 from oauth import oauth
 from http import post, get #, stream
 from util import *
-import emblem
+import emblem, menu
 from CDApplet import CDApplet, _
 # TODO import ConfigParser later conver files to config syntax
 
@@ -54,7 +54,7 @@
                                                                http_url = self.authorize_url)
     oauth_request.sign_request(self.signature_method, self.consumer, self.request_token)
     return oauth_request.to_url()
-  
+
   def get_unauthorized_request_token(self):
     oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, http_url = self.request_token_url)
     oauth_request.sign_request(self.signature_method, self.consumer, None)
@@ -103,39 +103,51 @@
    
     buffer = ''
     while True:
-      chunk = req.read(1)                                                           # read character per character from the connection ...
+      chunk = req.read(1)                                               # read character per character from the connection ...
       if not chunk:
         break
 
       buffer += chunk
-      tweets = buffer.split("\n",1)                                                 # ... until find the end of a tweet marked with a '\n'
+      tweets = buffer.split("\n",1)                                     # ... until find the end of a tweet marked with a '\n'
       if len(tweets) > 1:
         content = tweets[0]
         if "text" in content:
           content = simplejson.loads(content)
           logp("Received from Twitter Stream: %s" % content)
-          self.callback(content)                                                    # at the moment this method is called 'on_receive_new_tweet_callback'
+          self.callback(content)                                        # at the moment this method is called 'on_receive_new_entry_into_stream_callback'
         buffer = tweets[1]
  
 class TwitterAPI(API):
   def __init__(self, access_key, access_secret):
     API.__init__(self, access_key, access_secret)
     
-    self.update_url             = 'http://twitter.com/statuses/update.json'
-    self.home_timeline_url      = 'http://twitter.com/statuses/home_timeline.json'
-    self.direct_messages_url    = 'https://api.twitter.com/1/direct_messages.json'
-    self.verify_credentials_url = 'https://api.twitter.com/1/account/verify_credentials.json'
+    self.update_url               = 'http://twitter.com/statuses/update.json'
+    self.home_timeline_url        = 'http://twitter.com/statuses/home_timeline.json'
+    self.direct_messages_url      = 'https://api.twitter.com/1/direct_messages.json'
+    self.new_direct_messages_url  = 'https://api.twitter.com/1/direct_messages/new.json'
+    self.verify_credentials_url   = 'https://api.twitter.com/1/account/verify_credentials.json'
 
   def tweet(self, message):                                                         # popularly "send a tweet"
+    params = {'status':message}
     oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
                                                                token = self.access_token,
                                                                http_url = self.update_url,
-                                                               parameters = {'status':message},
+                                                               parameters = params,
                                                                http_method = "POST")
     oauth_request.sign_request(self.signature_method, self.consumer, self.access_token)
-    post_data = oauth_request.to_postdata()
-    return post(self.update_url, post_data)
+    header = oauth_request.to_header()
+    post(self.update_url, params, header)
 
+  def new_direct_message(self, message, destinatary):
+    params = {'text':message, 'screen_name':destinatary}
+    oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
+                                                               token = self.access_token,
+                                                               http_url = self.new_direct_messages_url,
+                                                               parameters = params,
+                                                               http_method = "POST")
+    oauth_request.sign_request(self.signature_method, self.consumer, self.access_token)
+    header = oauth_request.to_header()
+    post(self.new_direct_messages_url, params, header)
 
   def home_timeline(self):
     oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
@@ -167,6 +179,11 @@
     response = get(url) 
     return simplejson.loads(response)
 
+class Message:
+  def __init__(self, text, sender):
+    self.text = text
+    self.sender = sender
+
 class User:
   def __init__(self, screen_name="", access_key="", access_secret=""):
     self.screen_name = screen_name
@@ -183,18 +200,22 @@
 
   # Twitter methods
 
-  # This method is a callback that is called as soon as a new tweet that arrives on the stream
+  # This method is a callback that is called as soon as a new entry arrives on the stream
   # It is passed as parameter when creating the instance for the TwitterStreamAPI
-  # TwitterStreamAPI(access_key, access_secret, self.on_receive_new_tweet_callback)
-  # TODO: Make available an "Animation" option upon a new tweet arrival
-  def on_receive_new_tweet_callback(self, tweet):
-    if not tweet['user']['screen_name'] == self.user.screen_name:
-      logp("Inserting new tweet on the stream Queue: %s" % tweet)                   # not sent by the own user
-      self.stream.put(tweet)                                                        # put the new tweet on the stream queue
-      self.emblem.update(self.stream.qsize())                                       # create the emblem with the counter
-      self.icon.SetEmblem(self.emblem.emblem, CDApplet.EMBLEM_TOP_RIGHT + CDApplet.EMBLEM_PERSISTENT)  # add emblem
-      #self.icon.SetQuickInfo(str(self.stream.qsize()))                             # update the new tweets counter on the icon
+  # TwitterStreamAPI(access_key, access_secret, self.on_receive_new_entry_into_stream_callback)
+  # TODO: Make available an "Animation" option upon a new entry arrival
+  # TODO: Consider the direct messages arriving on the stream
+  #       Create two Queues to deal with tweets and messages separately
+  def on_receive_new_entry_into_stream_callback(self, entry):
+    #if 'direct_message' in entry:                                                    #TODO direct message
+    if 'user' in entry:                                                               # tweet
+      if not entry['user']['screen_name'] == self.user.screen_name:
+        logp("Inserting new tweet on the stream Queue: %s" % entry)                   # not sent by the own user
+        self.stream.put(entry)                                                        # put the new tweet on the stream queue
+        self.emblem.update(self.stream.qsize())                                       # create the emblem with the counter
+        self.icon.SetEmblem(self.emblem.emblem, CDApplet.EMBLEM_TOP_RIGHT + CDApplet.EMBLEM_PERSISTENT)  # add emblem
 
+  # TODO: Use the Menu class
   def show_new_tweets(self):
     self.inform_start_of_waiting_process()
     message = ''
@@ -206,11 +227,12 @@
     self.inform_end_of_waiting_process()
     self.show_popup_message(message, dialog)
 
+  # TODO: Use the Menu class
   def show_home_timeline(self):
     self.inform_start_of_waiting_process()
     timeline = self.api.home_timeline()
     if len(timeline) > 0:
-      message = "".join (["[<b>%s</b>] %s\n" % (status['user']['name'], status['text']) for status in timeline])
+      message = "".join (["[<b>%s</b>] %s\n" % (status['user']['screen_name'], status['text']) for status in timeline])
     else:
       message = _("Oh, dear, your timeline is empty :-(")
     dialog = {'use-markup':True}
@@ -220,13 +242,30 @@
   def show_direct_messages(self):
     self.inform_start_of_waiting_process()
     messages = self.api.direct_messages()
+    # message = ""
+    itens = []
     if len(messages) > 0:
-      message = "".join (["[<b>%s</b>] %s\n" % (status['sender']['name'], status['text']) for status in messages])
+      # Message (content of text, nick name of who sent it)
+      ([itens.append(Message(status['text'], status['sender']['screen_name'])) for status in messages])
+        #message += "[<b>%s</b>] %s\n" % (sender, text)
+      direct_messages_list_menu = menu.Menu(itens, self.on_direct_messages_list_menu_clicked)
+      direct_messages_list_menu.pop_up(self.icon)
+      #message = "".join (["[<b>%s</b>] %s\n" % (status['sender']['screen_name'], status['text']) for status in messages])
     else:
       message = _("Oh, dear, you do not have direct messages :-(")
     dialog = {'use-markup':True}
     self.inform_end_of_waiting_process()
-    self.show_popup_message(message, dialog)
+    #self.show_popup_message(message, dialog)
+    
+  def on_direct_messages_list_menu_clicked(self, widget):
+    self.ask_for_direct_message_reply(widget.get_label())                           # label holds the sender of the message, reply to him/her now
+
+  def ask_for_direct_message_reply(self, destinatary):
+    dialog = {'buttons':'ok;cancel'}
+    widget = {'widget-type':'text-entry', 'nb-chars':140}                           # 140 characters max, a direct message
+    self.show_popup_message((_("%s, write a reply to %s")) % (self.user.screen_name, destinatary), dialog, widget)
+    self.dialog_type = self.responding_sending_direct_message_reply
+    self.replying_direct_message_to = destinatary
 
   def tweet(self, message):                                                         # popularly "send a tweet"
     self.inform_start_of_waiting_process()
@@ -349,7 +388,8 @@
     self.api = None
     self.stream_api = None
     (self.responding_screen_name, self.responding_authorization, self.responding_pin,
-    self.responding_success, self.responding_tweet, self.responding_initial_informations) = range(6)
+    self.responding_success, self.responding_tweet, self.responding_initial_informations,
+    self.responding_sending_direct_message_reply) = range(7)
     self.dialog_type = None
     self.emblem = emblem.Emblem()                                                                     # emblem maker, see emblem.py
 
@@ -358,6 +398,7 @@
     self.user_stream_menu_id = 3000
     
     self.stream = Queue.Queue()
+    #self.direct_messages = {}
 
     CDApplet.__init__(self)                                                                           # call CDApplet interface init
 
@@ -371,7 +412,7 @@
       logp("User '%s' found" % self.user.screen_name)
       self.api = TwitterAPI(self.user.access_key, self.user.access_secret)                            # getting control over the api
       # setting the callback to receive the data of every entry on the stream
-      self.stream_api = TwitterStreamAPI(self.user.access_key, self.user.access_secret, self.on_receive_new_tweet_callback)
+      self.stream_api = TwitterStreamAPI(self.user.access_key, self.user.access_secret, self.on_receive_new_entry_into_stream_callback)
 
   #def reload(self):
     #self.read_user_data()
@@ -401,6 +442,9 @@
       elif self.dialog_type == self.responding_tweet:
         logp("Sending a tweet '%s'" % content)
         self.api.tweet(content)
+      elif self.dialog_type == self.responding_sending_direct_message_reply:
+        logp("Sending a direct message '%s'" % content)
+        self.api.new_direct_message(content, self.replying_direct_message_to)
 
   def on_click(self, key):
     self.ask_for_tweet()

=== modified file 'Twitter/Twitter.conf'
--- Twitter/Twitter.conf	2012-03-10 17:13:47 +0000
+++ Twitter/Twitter.conf	2012-03-14 00:09:17 +0000
@@ -1,4 +1,4 @@
-#!en;0.1.2
+#!en;0.1.3
 
 #[gtk-about]
 [Icon]

=== modified file 'Twitter/auto-load.conf'
--- Twitter/auto-load.conf	2012-03-10 20:27:57 +0000
+++ Twitter/auto-load.conf	2012-03-14 00:09:17 +0000
@@ -4,13 +4,13 @@
 author = Eduardo Mucelli Rezende Oliveira
 
 # A short description of the applet and how to use it.
-description = You can send tweets, see your timeline, the received directed messages, and new tweets.\nOn the first time, the applet is going to ask your nickname and authorization to connect with Twitter.\nThe applet is going to open your browser with the authorization page\nAs soon as you authorize it, a PIN number will be shown on the page, copy this number\nPaste this number on the next dialog box will be shown.\nThe plugin is going to inform that you are successfully connected.\nTo see the received direct messages right-click on the icon -> Twitter -> Received direct messages.\nTo see some user's info right-click on the icon -> Twitter -> Info.\nTo see the received tweets right-click on the icon -> Twitter -> New tweets.
+description = You can send tweets, see your timeline, the received directed messages, and new tweets.\nOn the first time, the applet is going to ask your nickname and authorization to connect with Twitter.\nThe applet is going to open your browser with the authorization page\nAs soon as you authorize it, a PIN number will be shown on the page, copy this number\nPaste this number on the next dialog box will be shown.\nThe plugin is going to inform that you are successfully connected.\nTo see the received direct messages right-click on the icon -> Twitter -> Received direct messages. You can reply one of them just by left-clicking on it.\nTo see some user's info right-click on the icon -> Twitter -> Info.\nTo see the received tweets right-click on the icon -> Twitter -> New tweets.
 
 # Category of the applet : 2 = files, 3 = internet, 4 = Desktop, 5 = accessory, 6 = system, 7 = fun
 category = 3
 
 # Version of the applet; change it everytime you change something in the config file. Don't forget to update the version both in this file and in the config file.
-version = 0.1.2
+version = 0.1.3
 
 # Whether the applet can be instanciated several times or not.
 multi-instance = true

=== added file 'Twitter/data/received_menu.png'
Binary files Twitter/data/received_menu.png	1970-01-01 00:00:00 +0000 and Twitter/data/received_menu.png	2012-03-14 00:09:17 +0000 differ
=== modified file 'Twitter/http.py'
--- Twitter/http.py	2012-03-05 14:44:13 +0000
+++ Twitter/http.py	2012-03-14 00:09:17 +0000
@@ -5,32 +5,36 @@
 # Author: Eduardo Mucelli Rezende Oliveira
 # E-mail: edumuce...@gmail.com or eduar...@dcc.ufmg.br
 
-import urllib2, json
+import urllib2, urllib
 from util import logp, logm
 
 # HTTP GET
 def get(url, tries = 0):
-	while True:
-		try:
-			logp("Trying to connect to %s" % url)
-			request = urllib2.Request(url)
-			response = urllib2.urlopen(request)
-			return response.read()
-		except urllib2.HTTPError:
-			tries += 1
-			if tries > 3:
-				raise
+  while True:
+    try:
+      logp("GET: Trying to connect to %s" % url)
+      request = urllib2.Request(url)
+      response = urllib2.urlopen(request)
+      return response.read()
+    except urllib2.HTTPError:
+      tries += 1
+      if tries > 3:
+        raise
 
 # HTTP POST
-def post(url, post_data, tries = 0):
-	while True:
-		try:
-			return urllib2.urlopen(url, post_data)
-		except urllib2.HTTPError:
-			tries += 1
-			if tries > 3:
-				raise
-				
+def post(url, params, header, tries = 0):
+  while True:
+    try:
+      logp("POST: Trying to connect to %s" % url)
+      data = urllib.urlencode(params)
+      request = urllib2.Request(url, data, headers=header)
+      response = urllib2.urlopen(request)
+      return response.read()
+    except urllib2.HTTPError:
+      tries += 1
+      if tries > 3:
+        raise
+        
 #def stream(url):
 #  req = urllib2.urlopen(url)
 #  buffer = ''

=== added file 'Twitter/menu.py'
--- Twitter/menu.py	1970-01-01 00:00:00 +0000
+++ Twitter/menu.py	2012-03-14 00:09:17 +0000
@@ -0,0 +1,65 @@
+#!/usr/bin/python
+
+# This is a part of the external Twitter applet for Cairo-Dock
+#
+# Author: Eduardo Mucelli Rezende Oliveira
+# E-mail: edumuce...@gmail.com or eduar...@dcc.ufmg.br
+
+import gtk, os
+
+class Menu(gtk.Menu):
+
+  def __init__(self, messages, callback):
+    gtk.Menu.__init__(self)
+        
+    for message in messages:
+      text = "<b>%s</b>\n%s" % (message.sender, message.text)
+      item = gtk.ImageMenuItem()
+      # the true label is set after with set_markup()
+      item.set_label(message.sender)
+      item.set_image(gtk.image_new_from_file(os.path.abspath("./data/received_menu.png")))
+      item.get_children()[0].set_markup(text)
+      item.connect('activate', callback)
+      self.append(item)
+      item.show()
+      # add a separator if mail is not last in list
+      if messages.index(message) != len(messages) - 1:
+        separator = gtk.SeparatorMenuItem()
+        self.append(separator)
+
+    self.show_all()
+    
+  def pop_up(self, icon):
+    self.icon = icon
+    self.popup(parent_menu_shell=None, parent_menu_item=None, func=self.get_xy, data=(400, 400), button=1, activate_time=0)
+
+  def get_xy(self, m, data):
+    # fetch icon geometry
+    icondata = self.icon.GetAll()
+    iconContainer  = icondata['container']
+    iconOrientation = icondata['orientation']
+    iconWidth = icondata['width']
+    iconHeight = icondata['height']
+    iconPosX = icondata['x']
+    iconPosY = icondata['y']
+
+    # get menu geometry
+    menuWidth, menuHeight = m.size_request()
+
+    # adapt to container and orientation
+    if iconContainer == 1:  # Then it's a desklet, always oriented in a bottom-like way.
+      if iconPosY['y'] < (gtk.gdk.screen_height() / 2):
+        iconOrientation = 1
+      else:
+        iconOrientation = 0
+
+    if iconOrientation == 0:
+      # compute position of menu
+      x = iconPosX - (menuWidth / 2)
+      y = iconPosY - (iconHeight / 2) - menuHeight
+
+    else:
+      x = iconPosX - (menuWidth / 2)
+      y = iconPosY + (iconHeight / 2)
+
+    return (x, y, True)

_______________________________________________
Mailing list: https://launchpad.net/~cairo-dock-team
Post to     : cairo-dock-team@lists.launchpad.net
Unsubscribe : https://launchpad.net/~cairo-dock-team
More help   : https://help.launchpad.net/ListHelp

Reply via email to