1import os 2from ConfigParser import SafeConfigParser 3import geany 4import geany.console 5import gobject 6import gtk 7import gtk.gdk as gdk 8import pango 9 10 11WIDGET_STATES = [ gtk.STATE_NORMAL, gtk.STATE_ACTIVE, gtk.STATE_PRELIGHT, 12 gtk.STATE_SELECTED, gtk.STATE_INSENSITIVE ] 13 14 15class ConsolePlugin(geany.Plugin): 16 17 __plugin_name__ = "Python Console" 18 __plugin_description__ = ("Installs a Python console that allows you " + 19 "to use the Geany API.") 20 __plugin_version__ = "0.01" 21 __plugin_author__ = "Matthew Brush <mbrush@codebrainz.ca>" 22 23 _font = "Monospace 9" 24 _bg = "#FFFFFF" 25 _fg = "#000000" 26 _banner = ("Geany Python Console\n You can access the Geany Python " + 27 "API by importing the `geany' module.\n") 28 _use_rl_completer = True 29 30 _builder = None 31 32 def __init__(self): 33 geany.Plugin.__init__(self) 34 self.load_config() 35 self.install_console() 36 37 38 def cleanup(self): 39 #self.save_config() 40 self.on_save_config_timeout() # do it now 41 self.uninstall_console() 42 43 44 def load_config(self): 45 self.cfg_path = os.path.join(geany.app.configdir, "plugins", "pyconsole.conf") 46 self.cfg = SafeConfigParser() 47 self.cfg.read(self.cfg_path) 48 49 50 def save_config(self): 51 gobject.idle_add(self.on_save_config_timeout) 52 53 54 def on_save_config_timeout(self, data=None): 55 self.cfg.write(open(self.cfg_path, 'w')) 56 return False 57 58 59 def install_console(self): 60 61 # load general settings 62 self.banner = self.banner 63 self.use_rl_completer = self.use_rl_completer 64 65 self.swin = gtk.ScrolledWindow() 66 self.swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS) 67 self.console = geany.console.Console(banner = self.banner, 68 use_rlcompleter = self.use_rl_completer) 69 self.console.connect("populate-popup", self.on_console_populate_popup) 70 71 # apply appearance settings 72 self.font = self.font 73 self.bg = self.bg 74 self.fg = self.fg 75 76 self.swin.add(self.console) 77 geany.main_widgets.message_window_notebook.append_page(self.swin, 78 gtk.Label("Python")) 79 80 self.swin.show_all() 81 self.save_config() 82 83 def uninstall_console(self): 84 self.swin.destroy() 85 86 87 def _get_font(self): 88 if self.cfg.has_section('appearances'): 89 if self.cfg.has_option('appearances', 'font'): 90 return self.cfg.get('appearances', 'font') 91 return self._font 92 def _set_font(self, font): 93 self._font = font 94 font_desc = pango.FontDescription(font) 95 self.console.modify_font(font_desc) 96 if not self.cfg.has_section('appearances'): 97 self.cfg.add_section('appearances') 98 self.cfg.set('appearances', 'font', self._font) 99 self.save_config() 100 font = property(_get_font, _set_font) 101 102 103 def _get_bg(self): 104 if self.cfg.has_section('appearances'): 105 if self.cfg.has_option('appearances', 'bg_color'): 106 return self.cfg.get('appearances', 'bg_color') 107 return self._bg 108 def _set_bg(self, bg): 109 self._bg = bg 110 color = gdk.color_parse(self._bg) 111 for state in WIDGET_STATES: 112 self.console.modify_bg(state, color) 113 self.console.modify_base(state, color) 114 if not self.cfg.has_section('appearances'): 115 self.cfg.add_section('appearances') 116 self.cfg.set('appearances', 'bg_color', self._bg) 117 self.save_config() 118 bg = property(_get_bg, _set_bg) 119 120 121 def _get_fg(self): 122 if self.cfg.has_section('appearances'): 123 if self.cfg.has_option('appearances', 'fg_color'): 124 return self.cfg.get('appearances', 'fg_color') 125 return self._fg 126 def _set_fg(self, fg): 127 self._fg = fg 128 color = gdk.color_parse(self._fg) 129 for state in WIDGET_STATES: 130 self.console.modify_fg(state, color) 131 self.console.modify_text(state, color) 132 if not self.cfg.has_section('appearances'): 133 self.cfg.add_section('appearances') 134 self.cfg.set('appearances', 'fg_color', self._fg) 135 self.save_config() 136 fg = property(_get_fg, _set_fg) 137 138 139 def _get_banner(self): 140 if self.cfg.has_section('general'): 141 if self.cfg.has_option('general', 'banner'): 142 return self.cfg.get('general', 'banner') 143 return self._banner 144 def _set_banner(self, banner): 145 self._banner = banner 146 if not self.cfg.has_section('general'): 147 self.cfg.add_section('general') 148 self.cfg.set('general', 'banner', self._banner) 149 self.save_config() 150 banner = property(_get_banner, _set_banner) 151 152 153 def _get_use_rl_completer(self): 154 if self.cfg.has_section('general'): 155 if self.cfg.has_option('general', 'use_rl_completer'): 156 return self.cfg.getboolean('general', 'use_rl_completer') 157 return self._use_rl_completer 158 def _set_use_rl_completer(self, use_rl_completer): 159 self._use_rl_completer = use_rl_completer 160 if not self.cfg.has_section('general'): 161 self.cfg.add_section('general') 162 self.cfg.set('general', 'use_rl_completer', 163 str(self._use_rl_completer).lower()) 164 self.save_config() 165 use_rl_completer = property(_get_use_rl_completer, _set_use_rl_completer) 166 167 168 def on_console_populate_popup(self, textview, menu, data=None): 169 item = gtk.SeparatorMenuItem() 170 item.show() 171 menu.append(item) 172 item = gtk.ImageMenuItem(stock_id=gtk.STOCK_PREFERENCES) 173 item.show() 174 menu.append(item) 175 item.connect("activate", lambda w,d=None: self.show_configure()) 176 177 178 def on_banner_changed(self, text_buf, data=None): 179 self.banner = text_buf.get_text(text_buf.get_start_iter(), text_buf.get_end_iter()) 180 181 def on_use_rl_completer_toggled(self, chk_btn, data=None): 182 self.use_rl_completer = chk_btn.get_active() 183 184 def on_font_changed(self, font_btn, data=None): 185 self.font = font_btn.get_font_name() 186 187 def on_fg_color_changed(self, clr_btn, data=None): 188 self.fg = clr_btn.get_color().to_string() 189 190 def on_bg_color_changed(self, clr_btn, data=None): 191 self.bg = clr_btn.get_color().to_string() 192 193 194 def configure(self, dialog): 195 196 vbox = gtk.VBox(spacing=6) 197 vbox.set_border_width(6) 198 199 lbl = gtk.Label() 200 lbl.set_use_markup(True) 201 lbl.set_markup("<b>General</b>") 202 203 fra_general = gtk.Frame("") 204 fra_general.set_shadow_type(gtk.SHADOW_NONE) 205 fra_general.set_label_widget(lbl) 206 207 al_general = gtk.Alignment(0.0, 0.0, 1.0, 1.0) 208 al_general.set_padding(0, 0, 12, 0) 209 fra_general.add(al_general) 210 211 tbl = gtk.Table(3, 2, False) 212 tbl.set_row_spacings(6) 213 tbl.set_col_spacings(6) 214 tbl.set_border_width(6) 215 216 lbl = gtk.Label("Banner:") 217 lbl.set_alignment(0.0, 0.0) 218 219 tvw = gtk.TextView() 220 tvw.get_buffer().set_text(self.banner) 221 tvw.get_buffer().connect("changed", self.on_banner_changed) 222 223 swin = gtk.ScrolledWindow() 224 swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) 225 swin.set_shadow_type(gtk.SHADOW_ETCHED_IN) 226 swin.add(tvw) 227 228 tbl.attach(lbl, 0, 1, 0, 1, gtk.FILL, gtk.FILL, 0, 0) 229 tbl.attach(swin, 1, 2, 0, 1, gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL, 0, 0) 230 231 lbl = gtk.Label("") 232 lbl.set_alignment(0.0, 0.5) 233 234 check = gtk.CheckButton("Use Readline") 235 if self.use_rl_completer: 236 check.set_active(True) 237 check.connect("toggled", self.on_use_rl_completer_toggled) 238 239 tbl.attach(lbl, 0, 1, 1, 2, gtk.FILL, gtk.FILL, 0, 0) 240 tbl.attach(check, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 0, 0) 241 242 lbl = gtk.Label("") 243 lbl.set_alignment(0.0, 0.5) 244 lbl.set_use_markup(True) 245 lbl.set_markup('<span size="small" style="italic">' + 246 'Note: General settings will be applied when console is reloaded.' + 247 '</span>') 248 tbl.attach(lbl, 0, 2, 2, 3, gtk.FILL, gtk.FILL, 0, 0) 249 250 al_general.add(tbl) 251 252 lbl = gtk.Label() 253 lbl.set_use_markup(True) 254 lbl.set_markup("<b>Appearances</b>") 255 256 fra_appearances = gtk.Frame("") 257 fra_appearances.set_shadow_type(gtk.SHADOW_NONE) 258 fra_appearances.set_label_widget(lbl) 259 260 al_appearances = gtk.Alignment(0.0, 0.0, 1.0, 1.0) 261 al_appearances.set_padding(0, 0, 12, 0) 262 fra_appearances.add(al_appearances) 263 264 tbl = gtk.Table(3, 2, False) 265 tbl.set_row_spacings(6) 266 tbl.set_col_spacings(6) 267 tbl.set_border_width(6) 268 269 lbl = gtk.Label("Font:") 270 lbl.set_alignment(0.0, 0.5) 271 272 btn = gtk.FontButton(self.font) 273 btn.connect("font-set", self.on_font_changed) 274 275 tbl.attach(lbl, 0, 1, 0, 1, gtk.FILL, gtk.FILL, 0, 0) 276 tbl.attach(btn, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL, 0, 0) 277 278 lbl = gtk.Label("FG Color:") 279 lbl.set_alignment(0.0, 0.5) 280 281 btn = gtk.ColorButton(gdk.color_parse(self.fg)) 282 btn.connect("color-set", self.on_fg_color_changed) 283 284 tbl.attach(lbl, 0, 1, 1, 2, gtk.FILL, gtk.FILL, 0, 0) 285 tbl.attach(btn, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL, 0, 0) 286 287 lbl = gtk.Label("BG Color:") 288 lbl.set_alignment(0.0, 0.5) 289 290 btn = gtk.ColorButton(gdk.color_parse(self.bg)) 291 btn.connect("color-set", self.on_bg_color_changed) 292 293 tbl.attach(lbl, 0, 1, 2, 3, gtk.FILL, gtk.FILL, 0, 0) 294 tbl.attach(btn, 1, 2, 2, 3, gtk.FILL | gtk.EXPAND, gtk.FILL, 0, 0) 295 296 al_appearances.add(tbl) 297 298 vbox.pack_start(fra_general, True, True, 0) 299 vbox.pack_start(fra_appearances, False, True, 0) 300 301 return vbox 302