← Back to team overview

cairo-dock-team team mailing list archive

[Merge] lp:~eduardo-mucelli/cairo-dock-plug-ins-extras/Google into lp:cairo-dock-plug-ins-extras

 

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

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


Applet Google, search in Google with this.
-- 
https://code.launchpad.net/~eduardo-mucelli/cairo-dock-plug-ins-extras/Google/+merge/43222
Your team Cairo-Dock Team is requested to review the proposed merge of lp:~eduardo-mucelli/cairo-dock-plug-ins-extras/Google into lp:cairo-dock-plug-ins-extras.
=== added directory 'Google'
=== added file 'Google/ChangeLog'
--- Google/ChangeLog	1970-01-01 00:00:00 +0000
+++ Google/ChangeLog	2010-12-09 14:58:27 +0000
@@ -0,0 +1,1 @@
+0.0.1:(December/9/2010): Support to Google search.

=== added file 'Google/Google'
--- Google/Google	1970-01-01 00:00:00 +0000
+++ Google/Google	2010-12-09 14:58:27 +0000
@@ -0,0 +1,202 @@
+#!/usr/bin/python
+
+# This is a part of the external Google applet for Cairo-Dock
+#
+# Author: Eduardo Mucelli Rezende Oliveira
+# E-mail: edumucelli@xxxxxxxxx or eduardom@xxxxxxxxxxx
+#
+# This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#    GNU General Public License for more details.
+
+# This applet provides an interface to Google search engine.
+# Left click on the main icon to open the search dialog.
+# Each result will be shown as a sub-icon.
+# Left-click to open the result in the default Web Browser.
+
+import gobject, dbus, os, urllib, gtk, ConfigParser, webbrowser
+from dbus.mainloop.glib import DBusGMainLoop
+from dbus import glib
+from sgmllib import SGMLParser
+from urllib import FancyURLopener
+from util import log
+
+from GoogleParser import GoogleParser
+
+DBusGMainLoop(set_as_default=True)
+
+class AgentOpener(FancyURLopener):
+    """Masked user-agent otherwise the access would be forbidden"""
+    version = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11'
+
+class Link:
+    identification = 0
+    def __init__(self, url, description):
+        self.url = url
+        self.description = description
+        self.identification = Link.identification
+        Link.identification += 1
+
+class Interface:
+
+    def __init__(self, query, offset):
+        self.query = query
+        self.links = []
+        self.offset = offset
+
+    def fetch(self):
+        parser = GoogleParser()
+        opener = AgentOpener()                                                      # opens the web connection with masked user-agent
+
+        # http://www.google.com/search?q={self.query}&start={self.offset}
+        search = "%s%s&start=%s" % (parser.url, self.adjust(self.query), str(self.offset))
+
+        try:
+            page = opener.open(search)                                              # get the HTML
+        except IOError:
+            log ("Problem to open %s" % (parser.url))
+        else:
+            parser.parse(page.read())                                               # feed the parser to get the specific content: translated text
+            page.close()                                                            # lets close the page connection
+        for (url, description) in zip(parser.urls, parser.descriptions):
+            link = Link(url, description)
+            self.links.append(link)
+        return self.links
+
+    # Google uses plus character instead of space in the search URL
+    def adjust(self, text):
+        return text.replace(' ', '+').encode('utf-8')
+
+class Google:
+
+    def start(self):
+        bus = dbus.SessionBus()
+        applet_name = os.path.basename(os.path.abspath("."))                        # name of the applet must the same as the folder
+        applet_path = "/org/cairodock/CairoDock/%s" % applet_name                   # path where our object is stored on the bus
+
+        applet_object = bus.get_object("org.cairodock.CairoDock", applet_path)
+        icon = dbus.Interface(applet_object, "org.cairodock.CairoDock.applet")
+
+        applet_sub_icons_object = bus.get_object("org.cairodock.CairoDock", applet_path+"/sub_icons")
+        sub_icons = dbus.Interface(applet_sub_icons_object, "org.cairodock.CairoDock.subapplet")  # the list of icons contained in 
+
+        configuration = os.path.expanduser("~/.config/cairo-dock/current_theme/plug-ins/%s/%s.conf") % (applet_name, applet_name)
+
+        applet = Applet(icon, sub_icons, configuration)
+        applet.start()
+        
+        loop = gobject.MainLoop()
+        loop.run()
+        sys.exit(0)
+
+class Applet:
+
+    def __init__(self, icon, sub_icons, configuration):
+        self.icon = icon
+        self.sub_icons = sub_icons
+        self.configuration = configuration                                          # configuration file
+        self.query = ""
+        self.reset_search_settings()
+        self.number_of_displayed_links = 10
+        
+    def start(self):
+        log ("Applet started")
+        self.connect_to_callbacks()
+
+    def connect_to_callbacks(self):                                                 # when reiceves the signal named as 1st parameter ...
+        self.icon.connect_to_signal("on_click", self.action_on_click)               # ... chama a funcao callback que eh o segundo parametro
+        self.icon.connect_to_signal("on_answer", self.action_on_answer)
+        self.icon.connect_to_signal("on_reload_module", self.action_on_reload)
+        self.sub_icons.connect_to_signal("on_click_sub_icon", self.action_on_click_sub_icon)
+        self.icon.connect_to_signal("on_scroll", self.action_on_scroll)
+
+    def action_on_click(self, param):
+        if self.query == "":                                                        # first query
+            self.ask_for_search_query()
+        else:                                                                       # already searched before
+            self.reset_search_settings()                                            # clean all the stuff
+            self.ask_for_search_query(self.query)                                   # open the search dialog with the query of the previous search
+
+    def ask_for_search_query(self, query=""):
+        self.icon.AskText("Search for", query)                                      # heya user, tell me what do you wanna and I will translate
+
+    def action_on_reload(self, config_has_changed):
+	    if config_has_changed:
+		    self.read_configuration_parameters()
+
+    def action_on_answer(self, answer):
+        if not answer == self.query:
+            self.query = answer
+            self.fetch_next_resulting_page()
+
+    def action_on_scroll(self, scroll_up):
+        if scroll_up:
+           self.fetch_next_resulting_page()
+        else:
+           self.fetch_previous_resulting_page()
+
+    def action_on_click_sub_icon(self, param, sub_icon_id):
+        webbrowser.open(self.links[int(sub_icon_id)].url)
+
+    def inform_start_of_waiting_process(self):
+        self.icon.SetQuickInfo("...")
+
+    def inform_end_of_waiting_process(self):
+        self.icon.SetQuickInfo("")
+
+    def inform_current_page(self):
+       	self.icon.SetQuickInfo(str(self.page_of_displayed_links))
+
+    # Since the previous results are already stored in self.links, it is necessary just to 
+	# select its correct interval that starts with the first link of the previous page.
+	# An easier approach would be to query the engine again with page-1 but it would result
+	# more queries to the page, consequently it has some drawbacks such as increasing the 
+	# probability of forbidden mechanized access, more bandwith, etc.
+    def fetch_previous_resulting_page(self):
+        if self.page_of_displayed_links > 1:											# there is no previous page from the first one
+            self.page_of_displayed_links -= 1										    # one page back
+            inicio = (self.page_of_displayed_links-1) * self.number_of_displayed_links	# the first position of the link in the previous page
+            sub_icon_list = self.construct_sub_icon_list(inicio)
+            self.refresh_sub_icon_list (sub_icon_list)
+            self.inform_current_page()
+
+    def fetch_next_resulting_page(self):
+        self.inform_start_of_waiting_process()
+
+        offset = self.page_of_displayed_links * self.number_of_displayed_links      # the position of the first link in the self.links array
+        links = Interface(self.query, offset).fetch()
+        self.links.extend(links)                                                    # concatena um array em outro, nao usar append como em Ruby
+        self.page_of_displayed_links += 1                                           # sequential page identification, lets go to the next
+
+        sub_icon_list = self.construct_sub_icon_list(offset)
+        self.refresh_sub_icon_list(sub_icon_list)
+
+        self.inform_end_of_waiting_process()
+        self.inform_current_page()
+
+    def construct_sub_icon_list(self, inicio):
+        sub_icon_list = []
+        for link in self.links[inicio:(inicio + self.number_of_displayed_links)]:
+            sub_icon_list.append(link.description)                                  # title
+            sub_icon_list.append(os.path.abspath(".") + '/icon')                    # icon
+            sub_icon_list.append(str(link.identification))                          # id
+        return sub_icon_list
+
+    def refresh_sub_icon_list(self, sub_icon_list):
+        self.sub_icons.RemoveSubIcon("any")
+        self.sub_icons.AddSubIcons(sub_icon_list)
+
+    def reset_search_settings(self):
+        self.links =[]
+        self.page_of_displayed_links = 0									        # current pagination of displayed links
+        Link.identification = 0
+        self.sub_icons.RemoveSubIcon("any")
+
+if __name__ == '__main__':
+    Google().start()

=== added file 'Google/Google.conf'
--- Google/Google.conf	1970-01-01 00:00:00 +0000
+++ Google/Google.conf	2010-12-09 14:58:27 +0000
@@ -0,0 +1,91 @@
+#!en;0.0.1
+
+#[gtk-about]
+[Icon]
+#j+[0;128] Desired icon size for this applet
+#{Set to 0 to use the default applet size}
+icon size = 0;0
+
+#s Name of the icon as it will appear in its label in the dock :
+name = Google
+
+#S+ Image's filename :
+#{Let empty to use the default one.}
+icon = 
+
+#d Name of the dock it belongs to:
+dock name = 
+
+order=
+
+#F[Applet's Handbook]
+frame_hand=
+#A
+handbook=Google
+
+#[gtk-convert]
+[Desklet]
+
+#j+[48;512] Desklet's dimension (width x height) :
+#{Depending on your WindowManager, you can resize it with ALT + middle_click or ALT + left_click for exemple.}
+size = 164;96
+
+#i[-2048;2048] Desklet's position (x ; y) :
+#{Depending on your WindowManager, you can move it with ALT + left_click}
+x position=0
+#i[-2048;2048] ...
+y position=0
+
+#b Is detached from the dock ?
+initially detached=false
+#l[Normal;Keep above;Keep below;On Widget Layer;Reserve space] Accessibility :
+#{for CompizFusion's "widget layer", set behaviour in Compiz to: (class=Cairo-dock & type=utility)}
+accessibility=0
+#b Should be visible on all desktops ?
+sticky=true
+
+#b Lock position ?
+#{If locked, the desklet can't be moved by simply dragging it with the left mouse button. Of course you can still move it with ALT + left_click.}
+locked = false
+
+#I[-180;180] Rotation :
+#{in degrees.}
+rotation = 0
+
+use size=
+
+#F[Decorations;gtk-orientation-portrait]
+frame_deco=
+
+#o+ Choose a decoration theme for this desklet :
+#{Choose the 'personnal' one to define your own decorations below.}
+decorations = default
+
+#v
+sep_deco =
+
+#S+ Background image :
+#{It's an image that will be displayed below the drawings, like a frame for exemple. Let empty to not use any.}
+bg desklet =
+#e+[0;1] Background tansparency :
+bg alpha = 1
+#i+[0;256] Left offset :
+#{in pixels. Use this to adjust the left position of the drawings.}
+left offset = 0
+#i+[0;256] Top offset :
+#{in pixels. Use this to adjust the top position of the drawings.}
+top offset = 0
+#i+[0;256] Right offset :
+#{in pixels. Use this to adjust the right position of the drawings.}
+right offset = 0
+#i+[0;256] Bottom offset :
+#{in pixels. Use this to adjust the bottom position of the drawings.}
+bottom offset = 0
+#S+ Foreground image :
+#{It's an image that will be displayed above the drawings, like a reflect for exemple. Let empty to not use any.}
+fg desklet =
+#e+[0;1] Foreground tansparency :
+fg alpha = 1
+
+#[gtk-preferences]
+[Configuration]

=== added file 'Google/GoogleParser.py'
--- Google/GoogleParser.py	1970-01-01 00:00:00 +0000
+++ Google/GoogleParser.py	2010-12-09 14:58:27 +0000
@@ -0,0 +1,46 @@
+# This is a part of the external Google applet for Cairo-Dock
+#
+# Author: Eduardo Mucelli Rezende Oliveira
+# E-mail: edumucelli@xxxxxxxxx or eduardom@xxxxxxxxxxx
+
+from sgmllib import SGMLParser
+
+class GoogleParser(SGMLParser):
+
+    def reset(self):                              
+        SGMLParser.reset(self)
+        self.url = "http://www.google.com/search?q=";
+        self.inside_h3_element = False                                              # indica se o parser esta dentro de <h3></h3> tag
+        self.inside_h3_a_element = False                                            # indica se o parser esta dentro de <h3><a></a></h3> tag
+        self.urls = []
+        self.descriptions = []
+        self.current_description_piece = ""
+
+    def start_h3(self, attrs):
+        for name, value in attrs:
+            if name == "class" and value == "r":                                    # <h3 class="r">...</h3>
+                self.inside_h3_element = True
+    
+    def end_h3(self):
+        self.inside_h3_element = False
+        self.descriptions.append(self.current_description_piece)                    # adiciona o conteudo completo da tag
+        self.current_description_piece = ""                                         # reinicia o armazenador do conteudo
+
+    def start_a(self, attrs):
+        if self.inside_h3_element:
+            self.inside_h3_a_element = True                                         # <h3 class="r"><a>...</a></h3>
+            for name, value in attrs:
+                if name == "href":
+                    self.urls.append(value)
+
+    def end_a(self):
+        if self.inside_h3_element:
+            self.inside_h3_a_element = False
+
+    def handle_data(self, text):
+        if self.inside_h3_a_element:                                                # estamos dentro de <h3 class="r"><a>...</a></h3>
+            self.current_description_piece += text                                  # concatena tudo que tiver dentro da tag
+
+    def parse(self, page):
+        self.feed(page)                                                             # feed the parser with the page's html
+        self.close()

=== added file 'Google/README'
--- Google/README	1970-01-01 00:00:00 +0000
+++ Google/README	2010-12-09 14:58:27 +0000
@@ -0,0 +1,6 @@
+# Contact me
+
+Any doubt, suggestion or anything else, except asking for some money, I would be pleased to received a message from you. :¬)
+
+Author: Eduardo Mucelli Rezende Oliveira
+E-mail: edumucelli@xxxxxxxxx or eduardom@xxxxxxxxxxx

=== added file 'Google/auto-load.conf'
--- Google/auto-load.conf	1970-01-01 00:00:00 +0000
+++ Google/auto-load.conf	2010-12-09 14:58:27 +0000
@@ -0,0 +1,13 @@
+[Register]
+
+# Author of the applet
+author = Eduardo Mucelli Rezende Oliveira
+
+# A short description of the applet and how to use it.
+description = This applet provides an interface to Google search engine.\nLeft click on the main icon to open the search dialog.\nEach result will be shown as a sub-icon.\nLeft-click to open the result in the default Web Browser.
+
+# Category of the applet : 2 = files, 3 = internet, 4 = Desktop, 5 = accessory, 6 = system, 7 = fun
+category = 5
+
+# 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.0.1

=== added file 'Google/icon'
Binary files Google/icon	1970-01-01 00:00:00 +0000 and Google/icon	2010-12-09 14:58:27 +0000 differ
=== added file 'Google/preview'
Binary files Google/preview	1970-01-01 00:00:00 +0000 and Google/preview	2010-12-09 14:58:27 +0000 differ
=== added file 'Google/util.py'
--- Google/util.py	1970-01-01 00:00:00 +0000
+++ Google/util.py	2010-12-09 14:58:27 +0000
@@ -0,0 +1,9 @@
+#!/usr/bin/python
+
+# This is a part of the external Google applet for Cairo-Dock
+#
+# Author: Eduardo Mucelli Rezende Oliveira
+# E-mail: edumucelli@xxxxxxxxx or eduardom@xxxxxxxxxxx
+
+def log (string):
+    print "[+] Google: %s" % string


Follow ups