fix for linux. copied the webbrowser hack over from wm.py Thanks Daniel Salazar for...
[blender-addons-contrib.git] / text_editor_pasteall.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 bl_info = {
20     "name": "PasteAll",
21     "author": "Dalai Felinto (dfelinto)",
22     "version": (0,6),
23     "blender": (2, 5, 7),
24     "api": 36007,
25     "location": "Text editor > Properties panel",
26     "description": "Send your selection or text to www.pasteall.org",
27     "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
28         "Scripts/Text_Editor/PasteAll",
29     "tracker_url": "https://projects.blender.org/tracker/index.php?"\
30         "func=detail&aid=23493",
31     "category": "Text Editor"}
32
33 # ########################################################
34 # PasteAll.org Text Sender Script
35 #
36 # Dalai Felinto (dfelinto)
37 # blenderecia.orgfree.com
38 #
39 # Rio de Janeiro - Brasil
40 # Vancouver - Canada
41 #
42 # Original code: 23rd August 2010 (Blender 2.5.3 rev. 31525)
43 #
44 # Important Note:
45 # This script is not official. I did it for fun and for my own usage.
46 # And please do not abuse of their generosity - use it wisely (a.k.a no flood).
47 #
48 # ########################################################
49
50
51 import bpy
52 import urllib
53 import urllib.request
54 import webbrowser
55
56 class TEXT_PT_pasteall(bpy.types.Panel):
57     bl_space_type = 'TEXT_EDITOR'
58     bl_region_type = 'UI'
59     bl_label = "PasteAll.org"
60
61     def draw(self, context):
62         layout = self.layout        
63         layout.operator("text.pasteall", icon='URL')
64         layout.prop(context.scene, "use_webbrowser")
65
66 class TEXT_OT_pasteall(bpy.types.Operator):
67     ''''''
68     bl_idname = "text.pasteall"
69     bl_label = "PasteAll.org"
70     bl_description = "Send the current text or selection to www.pasteall.org"
71
72     @classmethod
73     def poll(cls, context):
74         if context.area.type != 'TEXT_EDITOR':
75             return False
76         else:
77             return context.space_data.text != None
78
79     def invoke(self, context, event):
80         import webbrowser
81         st = context.space_data
82
83         # get the selected text
84         text = self.get_selected_text(st.text)
85         # if no text is selected send the whole file
86         if text is None: text = st.text.as_string()
87
88         # get the file type based on the extension
89         format = self.get_file_format(st.text)
90
91         # send the text and receive the returned page
92         html = self.send_text(text, format)
93
94         if html is None:
95             self.report('ERROR', "Error in sending the text to the server.")
96             return {'CANCELLED'}
97
98         # get the link of the posted page
99         page = self.get_page(str(html))
100         
101         if page is None or page == "":
102             self.report('ERROR', "Error in retrieving the page.")
103             return {'CANCELLED'}
104         else:
105             self.report('INFO', page)
106
107         # store the link in the clipboard
108         bpy.context.window_manager.clipboard = page
109
110         if context.scene.use_webbrowser:
111             try:
112                 _webbrowser_bug_fix()
113                 webbrowser.open_new_tab(page)
114             except:
115                 self.report('WARNING', "Error in opening the page %s." % (page))
116
117         return {'FINISHED'}
118             
119     def send_text(self, text, format):
120         ''''''
121         import urllib
122         url = "http://www.pasteall.org/index.php"
123         values = {  'action' : 'savepaste',
124                     'parent_id' : '0',
125                     'language_id': format,
126                     'code' : text }
127
128         try:
129             data = urllib.parse.urlencode(values).encode()
130             req = urllib.request.Request(url, data)
131             response = urllib.request.urlopen(req)
132             page_source = response.read()
133         except:
134             return None
135         else:
136             return page_source
137
138     def get_page(self, html):
139         ''''''
140         id = html.find('directlink')
141         id_begin = id + 12 # hardcoded: directlink">
142         id_end = html[id_begin:].find("</a>")
143
144         if id != -1 and id_end != -1:
145             return html[id_begin:id_begin + id_end]
146         else:
147             return None
148
149     def get_selected_text(self, text):
150         ''''''
151         current_line = text.current_line
152         select_end_line = text.select_end_line
153         
154         current_character = text.current_character
155         select_end_character = text.select_end_character
156         
157         # if there is no selected text return None
158         if current_line == select_end_line:
159             if current_character == select_end_character:
160                 return None
161             else:
162                 return current_line.body[min(current_character,select_end_character):max(current_character,select_end_character)]
163
164         text_return = None
165         writing = False
166         normal_order = True # selection from top to bottom
167
168         for line in text.lines:
169             if not writing:
170                 if line == current_line:
171                     text_return = current_line.body[current_character:] + "\n"
172                     writing = True
173                     continue
174                 elif line == select_end_line:
175                     text_return =  select_end_line.body[select_end_character:] + "\n"
176                     writing = True
177                     normal_order = False
178                     continue
179             else:
180                 if normal_order:
181                     if line == select_end_line:
182                         text_return += select_end_line.body[:select_end_character]
183                         break
184                     else:
185                         text_return += line.body + "\n"
186                         continue
187                 else:
188                     if line == current_line:
189                         text_return += current_line.body[:current_character]
190                         break
191                     else:
192                         text_return += line.body + "\n"
193                         continue
194
195         return text_return
196     
197     def get_file_format(self, text):
198         '''Try to guess what is the format based on the file extension'''
199         extensions =   {'diff':'24',
200                         'patch':'24',
201                         'py':'62',
202                         'c':'12',
203                         'cpp':'18'}
204
205         type = text.name.split(".")[-1]
206         return extensions.get(type, '0')
207
208 def register():
209     bpy.types.Scene.use_webbrowser = bpy.props.BoolProperty(
210         name='Launch Browser',
211         description='Opens the page with the submitted text.',
212         default=True)
213
214     bpy.utils.register_module(__name__)
215
216 def unregister():
217     del bpy.types.Scene.use_webbrowser
218     bpy.utils.unregister_module(__name__)
219
220 if __name__ == "__main__":
221     register()
222
223 def _webbrowser_bug_fix():
224     """hack copied from wm.py"""
225     # test for X11
226     import os
227
228     if os.environ.get("DISPLAY"):
229
230         # BSD licenced code copied from python, temp fix for bug
231         # http://bugs.python.org/issue11432, XXX == added code
232         def _invoke(self, args, remote, autoraise):
233             # XXX, added imports
234             import io
235             import subprocess
236             import time
237
238             raise_opt = []
239             if remote and self.raise_opts:
240                 # use autoraise argument only for remote invocation
241                 autoraise = int(autoraise)
242                 opt = self.raise_opts[autoraise]
243                 if opt:
244                     raise_opt = [opt]
245
246             cmdline = [self.name] + raise_opt + args
247
248             if remote or self.background:
249                 inout = io.open(os.devnull, "r+")
250             else:
251                 # for TTY browsers, we need stdin/out
252                 inout = None
253             # if possible, put browser in separate process group, so
254             # keyboard interrupts don't affect browser as well as Python
255             setsid = getattr(os, 'setsid', None)
256             if not setsid:
257                 setsid = getattr(os, 'setpgrp', None)
258
259             p = subprocess.Popen(cmdline, close_fds=True,  # XXX, stdin=inout,
260                                  stdout=(self.redirect_stdout and inout or None),
261                                  stderr=inout, preexec_fn=setsid)
262             if remote:
263                 # wait five secons. If the subprocess is not finished, the
264                 # remote invocation has (hopefully) started a new instance.
265                 time.sleep(1)
266                 rc = p.poll()
267                 if rc is None:
268                     time.sleep(4)
269                     rc = p.poll()
270                     if rc is None:
271                         return True
272                 # if remote call failed, open() will try direct invocation
273                 return not rc
274             elif self.background:
275                 if p.poll() is None:
276                     return True
277                 else:
278                     return False
279             else:
280                 return not p.wait()
281
282         import webbrowser
283         webbrowser.UnixBrowser._invoke = _invoke
284