~m-buck/+junk/gtk-desktop-info

« back to all changes in this revision

Viewing changes to plugin_tomboy.py

  • Committer: Mark Buck (Kaivalagi)
  • Date: 2009-06-19 17:13:00 UTC
  • Revision ID: m_buck@hotmail.com-20090619171300-5cbhr90xwg62z27y
Added --backgroundblend and --backgroundcolour options for visual seperation of output from wallpaper if required, Fixed song length output in the rhythmbox plugin when songs are an hour long or more, Added copy option to right click, enabling the copying of html content to the clipboard for testing, Moved common functions into a plugin_common module

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
#
6
6
#  Author: Kaivalagi
7
7
# Created: 23/11/2008
8
 
from htmlentitydefs import name2codepoint, codepoint2name
9
8
from optparse import OptionParser
10
 
import traceback
 
9
from plugin_common import getHTMLText, getTypedValue
 
10
import codecs
 
11
import fileinput
 
12
import logging
11
13
import os
 
14
import re
12
15
import shutil
13
 
import codecs
14
 
import re
15
 
import logging
16
 
import fileinput
 
16
import traceback
17
17
 
18
18
try:
19
19
    import dbus
42
42
    HEADERTEMPLATE = None
43
43
    TEMPLATE = None
44
44
    TAGSLIST = None
45
 
    
 
45
 
46
46
class Output:
47
 
    
 
47
 
48
48
    def __init__(self, options):
49
49
        self.options = options
50
50
        self.logger = logging.getLogger(app_name+"."+module_name)
51
51
        self.loadConfigData()
52
 
            
 
52
 
53
53
    def loadConfigData(self):
54
54
        try:
55
 
            
 
55
 
56
56
            self.config = TomboyConfig()
57
 
            
 
57
 
58
58
            if self.options.config != None:
59
59
                # load the config based on options passed in from the main app
60
60
                configfilepath = self.options.config
61
61
            else:
62
62
                # load plugin config from home directory of the user
63
63
                configfilepath = os.path.join(os.path.expanduser('~'), ".config/"+app_name+"/"+module_name+".config")
64
 
                            
 
64
 
65
65
            if os.path.exists(configfilepath):
66
 
                
 
66
 
67
67
                self.logger.info("Loading config settings from \"%s\""%configfilepath)
68
68
 
69
69
                for line in fileinput.input(os.path.expanduser(configfilepath)):
70
70
                    line = line.strip()
71
71
                    if len(line) > 0 and line[0:1] != "#": # ignore commented lines or empty ones
72
 
    
 
72
 
73
73
                        name = line.split("=")[0].strip().upper() # config setting name on the left of =
74
74
                        value = line.split("=")[1].split("#")[0].strip() # config value on the right of = (minus any trailing comments)
75
 
    
 
75
 
76
76
                        if len(value) > 0:
77
77
                            if name == "HEADERTEMPLATE":
78
 
                                self.config.HEADERTEMPLATE = self.getTypedValue(value, "string")                            
 
78
                                self.config.HEADERTEMPLATE = getTypedValue(value, "string")
79
79
                            elif name == "TEMPLATE":
80
 
                                self.config.TEMPLATE = self.getTypedValue(value, "string")
 
80
                                self.config.TEMPLATE = getTypedValue(value, "string")
81
81
                            elif name == "TAGSLIST":
82
 
                                self.config.TAGSLIST = self.getTypedValue(value, "string")                                                                
 
82
                                self.config.TAGSLIST = getTypedValue(value, "string")
83
83
                            else:
84
84
                                self.logger.error("Unknown option in config file: " + name)
85
85
            else:
86
86
                self.logger.info("Config data file %s not found, using defaults and setting up config file for next time" % configfilepath)
87
 
                
 
87
 
88
88
                userconfigpath = os.path.join(os.path.expanduser('~'), ".config/"+app_name+"/")
89
89
                configsource = os.path.join(app_path, "config/"+module_name+".config")
90
 
                
 
90
 
91
91
                if os.path.exists(userconfigpath) == False:
92
92
                    os.makedirs(userconfigpath)
93
93
 
94
94
                shutil.copy(configsource, configfilepath)
95
 
                
 
95
 
96
96
        except Exception, e:
97
97
            self.logger.error(e.__str__()+"\n"+traceback.format_exc())
98
98
 
99
 
    def getTypedValue(self, value, expectedtype):
100
 
        
101
 
        try:
102
 
            if len(value.strip(" ")) == 0:
103
 
                return None
104
 
            
105
 
            elif value.lower() == "true":
106
 
                if expectedtype == "boolean":
107
 
                    return True
108
 
                else:
109
 
                    self.logger.error("Expected type was '%s', but the value '%s' was given"%(expectedtype, value))
110
 
                    
111
 
            elif value.lower() == "false":
112
 
                if expectedtype == "boolean":
113
 
                    return False
114
 
                else:
115
 
                    self.logger.error("Expected type was '%s', but the value '%s' was given"%(expectedtype, value))
116
 
                    
117
 
            elif self.isNumeric(value) == True:
118
 
                if expectedtype == "integer":
119
 
                    return int(value)
120
 
                else:
121
 
                    self.logger.error("Expected type was '%s', but the value '%s' was given"%(expectedtype, value))
122
 
                    
123
 
            else:
124
 
                return value
125
 
 
126
 
        except (TypeError, ValueError):
127
 
            self.logger.error("Cannot convert '%s' to expected type of '%s'"%(value,expectedtype))
128
 
            return value
129
 
        
130
99
    def testDBus(self, bus, interface):
131
100
        obj = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
132
101
        dbus_iface = dbus.Interface(obj, 'org.freedesktop.DBus')
134
103
        return interface in avail
135
104
 
136
105
    def getTemplateOutput(self, template, title, content):
137
 
        
 
106
 
138
107
        try:
139
 
            
 
108
 
140
109
            output = template
141
 
    
 
110
 
142
111
            output = output.replace("[title]",title)
143
112
            output = output.replace("[content]",content)
144
 
            
 
113
 
145
114
            return output.encode("utf-8")
146
 
        
 
115
 
147
116
        except Exception,e:
148
117
            self.logger.error(e.__str__()+"\n"+traceback.format_exc())
149
118
            return ""
150
 
        
 
119
 
151
120
    def getOutput(self):
152
121
 
153
122
        if self.options.noheader == True:
172
141
            headertemplate = inputfile.read()
173
142
        finally:
174
143
            inputfile.close()
175
 
            
 
144
 
176
145
        if self.options.template != None:
177
146
            templatefilepath = self.options.template
178
147
            self.logger.info("Using custom template file '%s'"%templatefilepath)
182
151
        else:
183
152
            templatefilepath = app_path+"/templates/tomboy.template"
184
153
            self.logger.info("Using default template")
185
 
             
 
154
 
186
155
        # load the file
187
156
        try:
188
157
            inputfile = codecs.open(os.path.expanduser(templatefilepath), encoding='utf-8')
194
163
            inputfile.close()
195
164
 
196
165
        if DBUS_AVAIL == True:
197
 
            
 
166
 
198
167
            try:
199
 
                    
 
168
 
200
169
                bus = dbus.SessionBus()
201
 
    
 
170
 
202
171
                if self.testDBus(bus, 'org.gnome.Tomboy'):
203
 
                    
 
172
 
204
173
                        self.logger.info("Setting up dbus interface")
205
 
                        
 
174
 
206
175
                        remote_object = bus.get_object("org.gnome.Tomboy","/org/gnome/Tomboy/RemoteControl")
207
176
                        iface = dbus.Interface(remote_object, "org.gnome.Tomboy.RemoteControl")
208
 
                        
 
177
 
209
178
                        self.logger.info("Calling dbus interface for Tomboy Notes data")
210
 
    
 
179
 
211
180
                        # either get specific notes by tag or all notes
212
181
                        if self.config.TAGSLIST != None:
213
182
                            notesfortag = []
218
187
                                    notes.append(notesfortag)
219
188
                        else:
220
189
                            notes = iface.ListAllNotes()
221
 
                        
 
190
 
222
191
                        output = headertemplate
223
 
                        
 
192
 
224
193
                        for note in notes:
225
 
                            
 
194
 
226
195
                            # get notes text and convert to html format
227
 
                            title = self.getHTMLText(iface.GetNoteTitle(note))
 
196
                            title = getHTMLText(iface.GetNoteTitle(note))
228
197
                            content = self.getHTMLFromXMLContent(iface.GetNoteContentsXml(note),title)
229
 
                            
 
198
 
230
199
                            # output note data using the template
231
200
                            output = output + self.getTemplateOutput(template, title, content)
232
201
 
234
203
                self.logger.error(e.__str__()+"\n"+traceback.format_exc())
235
204
 
236
205
            return output.encode("utf-8")
237
 
                
 
206
 
238
207
    def getHTMLFromXMLContent(self,xml,title):
239
208
 
240
209
        # the tags we need to convert, and what they should become
248
217
                    "italic"        : "i",
249
218
                    "strikethrough" : "strike"
250
219
                    }
251
 
        
 
220
 
252
221
        # remove the title text from the first line of xml
253
222
        html = xml.replace(title+"\n","\n")
254
 
        
 
223
 
255
224
        # remove size tags from xml, we want css styles determining that
256
225
        html = re.sub("</?size[^<]*?>", "",html)
257
226
 
264
233
        html = re.sub("\n{2,}","\n",html) # remove excess new lines
265
234
        html = html.replace("\n","<br>\n") # switch out new line for html breaks
266
235
        return html
267
 
        
268
 
    def getHTMLText(self,text):
269
 
        try:
270
 
            htmlentities = []               
271
 
            for char in text: #html:
272
 
                if ord(char) < 128:
273
 
                    htmlentities.append(char)
274
 
                else:
275
 
                    htmlentities.append('&%s;' % codepoint2name[ord(char)])
276
 
            html = "".join(htmlentities)
277
 
            
278
 
            html = html.replace("\n","<br>\n") # switch out new line for html breaks
279
 
            return html            
280
 
        except:
281
 
            return text
282
 
 
283
 
    def getCleanText(self,html):
284
 
        try:
285
 
            text = str(html)
286
 
            text = text.replace("\n","") # remove new lines from html
287
 
            text = text.replace("&apos;","'") # workaround for shitty xml codes not compliant with html
288
 
            text = text.replace("<br>","\n") # switch out html breaks for new line
289
 
            text = re.sub('<(.|\n)+?>','',text) # remove any html tags
290
 
            text =  re.sub('&(%s);' % '|'.join(name2codepoint), lambda m: chr(name2codepoint[m.group(1)]), text)
291
 
            return text            
292
 
        except:
293
 
            return html
294
 
        
295
 
    def isNumeric(self,value):
296
 
        try:
297
 
            temp = int(value)
298
 
            return True
299
 
        except:
300
 
            return False
301
236
 
302
237
def getHTML(options):
303
238
    output = Output(options)
307
242
 
308
243
# to enable testing in isolation
309
244
if __name__ == "__main__":
310
 
    
 
245
 
311
246
    parser = OptionParser()
312
 
    parser.add_option("--noheader", dest="noheader", default=False, action="store_true", help=u"Turn off header output. This will override any header template setting to be nothing")        
 
247
    parser.add_option("--noheader", dest="noheader", default=False, action="store_true", help=u"Turn off header output. This will override any header template setting to be nothing")
313
248
    parser.add_option("--headertemplate", dest="headertemplate", type="string", metavar="FILE", help=u"Override the header template for the plugin, default or config based template ignored.")
314
249
    parser.add_option("--template", dest="template", type="string", metavar="FILE", help=u"Override the template for the plugin, default or config based template ignored.")
315
250
    parser.add_option("--verbose", dest="verbose", default=False, action="store_true", help=u"Outputs verbose info to the terminal")
316
251
    parser.add_option("--version", dest="version", default=False, action="store_true", help=u"Displays the version of the script.")
317
 
    parser.add_option("--logfile", dest="logfile", type="string", metavar="FILE", help=u"If a filepath is set, the script logs to the filepath.")                
318
 
    
 
252
    parser.add_option("--logfile", dest="logfile", type="string", metavar="FILE", help=u"If a filepath is set, the script logs to the filepath.")
 
253
 
319
254
    (options, args) = parser.parse_args()
320
 
        
 
255
 
321
256
    output = Output(options)
322
257
    html = output.getOutput()
323
258
    del output