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