summaryrefslogtreecommitdiff
path: root/grc/gui/PropsDialog.py
diff options
context:
space:
mode:
Diffstat (limited to 'grc/gui/PropsDialog.py')
-rw-r--r--grc/gui/PropsDialog.py239
1 files changed, 115 insertions, 124 deletions
diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py
index a5b46cbbac..5f39770e78 100644
--- a/grc/gui/PropsDialog.py
+++ b/grc/gui/PropsDialog.py
@@ -17,116 +17,91 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-import pygtk
-pygtk.require('2.0')
-import gtk
+from __future__ import absolute_import
+from gi.repository import Gtk, Gdk, GObject, Pango
-import Actions
-from Dialogs import SimpleTextDisplay
-from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT, FONT_SIZE
-import Utils
-import pango
+from . import Actions, Utils, Constants
+from .Dialogs import SimpleTextDisplay
+import six
-TAB_LABEL_MARKUP_TMPL="""\
-#set $foreground = $valid and 'black' or 'red'
-<span foreground="$foreground">$encode($tab)</span>"""
-
-def get_title_label(title):
- """
- Get a title label for the params window.
- The title will be bold, underlined, and left justified.
-
- Args:
- title: the text of the title
-
- Returns:
- a gtk object
- """
- label = gtk.Label()
- label.set_markup('\n<b><span underline="low">%s</span>:</b>\n'%title)
- hbox = gtk.HBox()
- hbox.pack_start(label, False, False, padding=11)
- return hbox
-
-
-class PropsDialog(gtk.Dialog):
+class PropsDialog(Gtk.Dialog):
"""
A dialog to set block parameters, view errors, and view documentation.
"""
- def __init__(self, block):
+ def __init__(self, parent, block):
"""
Properties dialog constructor.
- Args:
+ Args:%
block: a block instance
"""
- self._hash = 0
- gtk.Dialog.__init__(
+ Gtk.Dialog.__init__(
self,
- title='Properties: %s' % block.get_name(),
- buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT,
- gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
- gtk.STOCK_APPLY, gtk.RESPONSE_APPLY)
+ title='Properties: ' + block.name,
+ transient_for=parent,
+ modal=True,
+ destroy_with_parent=True,
+ )
+ self.add_buttons(
+ Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT,
+ Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT,
+ Gtk.STOCK_APPLY, Gtk.ResponseType.APPLY,
)
- self.set_response_sensitive(gtk.RESPONSE_APPLY, False)
+ self.set_response_sensitive(Gtk.ResponseType.APPLY, False)
self.set_size_request(*Utils.scale(
- (MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT)
+ (Constants.MIN_DIALOG_WIDTH, Constants.MIN_DIALOG_HEIGHT)
))
+
self._block = block
+ self._hash = 0
- vpaned = gtk.VPaned()
- self.vbox.pack_start(vpaned)
+ vpaned = Gtk.VPaned()
+ self.vbox.pack_start(vpaned, True, True, 0)
# Notebook to hold param boxes
- notebook = gtk.Notebook()
+ notebook = self.notebook = Gtk.Notebook()
notebook.set_show_border(False)
notebook.set_scrollable(True) # scroll arrows for page tabs
- notebook.set_tab_pos(gtk.POS_TOP)
+ notebook.set_tab_pos(Gtk.PositionType.TOP)
vpaned.pack1(notebook, True)
# Params boxes for block parameters
- self._params_boxes = list()
- for tab in block.get_param_tab_labels():
- label = gtk.Label()
- vbox = gtk.VBox()
- scroll_box = gtk.ScrolledWindow()
- scroll_box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- scroll_box.add_with_viewport(vbox)
- notebook.append_page(scroll_box, label)
- self._params_boxes.append((tab, label, vbox))
+ self._params_boxes = []
+ self._build_param_tab_boxes(block.params)
# Docs for the block
self._docs_text_display = doc_view = SimpleTextDisplay()
- doc_view.get_buffer().create_tag('b', weight=pango.WEIGHT_BOLD)
- self._docs_box = gtk.ScrolledWindow()
- self._docs_box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self._docs_box.add_with_viewport(self._docs_text_display)
- notebook.append_page(self._docs_box, gtk.Label("Documentation"))
+ doc_view.get_buffer().create_tag('b', weight=Pango.Weight.BOLD)
+ self._docs_box = Gtk.ScrolledWindow()
+ self._docs_box.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+ self._docs_box.add(self._docs_text_display)
+ notebook.append_page(self._docs_box, Gtk.Label(label="Documentation"))
# Generated code for the block
if Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB.get_active():
self._code_text_display = code_view = SimpleTextDisplay()
- code_view.set_wrap_mode(gtk.WRAP_NONE)
- code_view.get_buffer().create_tag('b', weight=pango.WEIGHT_BOLD)
- code_view.modify_font(pango.FontDescription(
- 'monospace %d' % FONT_SIZE))
- code_box = gtk.ScrolledWindow()
- code_box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- code_box.add_with_viewport(self._code_text_display)
- notebook.append_page(code_box, gtk.Label("Generated Code"))
+ code_view.set_wrap_mode(Gtk.WrapMode.NONE)
+ code_view.get_buffer().create_tag('b', weight=Pango.Weight.BOLD)
+ code_view.set_monospace(True)
+ # todo: set font size in non-deprecated way
+ # code_view.override_font(Pango.FontDescription('monospace %d' % Constants.FONT_SIZE))
+ code_box = Gtk.ScrolledWindow()
+ code_box.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+ code_box.add(self._code_text_display)
+ notebook.append_page(code_box, Gtk.Label(label="Generated Code"))
else:
self._code_text_display = None
# Error Messages for the block
self._error_messages_text_display = SimpleTextDisplay()
- self._error_box = gtk.ScrolledWindow()
- self._error_box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self._error_box.add_with_viewport(self._error_messages_text_display)
+ self._error_box = Gtk.ScrolledWindow()
+ self._error_box.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+ self._error_box.add(self._error_messages_text_display)
vpaned.pack2(self._error_box)
- vpaned.set_position(int(0.65 * MIN_DIALOG_HEIGHT))
+ vpaned.set_position(int(0.65 * Constants.MIN_DIALOG_HEIGHT))
# Connect events
self.connect('key-press-event', self._handle_key_press)
@@ -134,6 +109,27 @@ class PropsDialog(gtk.Dialog):
self.connect('response', self._handle_response)
self.show_all() # show all (performs initial gui update)
+ def _build_param_tab_boxes(self, params):
+ tab_labels = (p.tab_label for p in self._block.params.values())
+
+ def unique_tab_labels():
+ seen = {Constants.DEFAULT_PARAM_TAB}
+ yield Constants.DEFAULT_PARAM_TAB
+ for tab_label in tab_labels:
+ if tab_label in seen:
+ continue
+ yield tab_label
+ seen.add(tab_label)
+
+ for tab in unique_tab_labels():
+ label = Gtk.Label()
+ vbox = Gtk.VBox()
+ scroll_box = Gtk.ScrolledWindow()
+ scroll_box.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+ scroll_box.add(vbox)
+ self.notebook.append_page(scroll_box, label)
+ self._params_boxes.append((tab, label, vbox))
+
def _params_changed(self):
"""
Have the params in this dialog changed?
@@ -146,25 +142,23 @@ class PropsDialog(gtk.Dialog):
true if changed
"""
old_hash = self._hash
- # create a tuple of things from each param that affects the params box
- self._hash = hash(tuple([(
- hash(param), param.get_name(), param.get_type(),
- param.get_hide() == 'all',
- ) for param in self._block.get_params()]))
- return self._hash != old_hash
+ new_hash = self._hash = hash(tuple(
+ (hash(param), param.name, param.get_type(), param.get_hide() == 'all',)
+ for param in self._block.params.values()
+ ))
+ return new_hash != old_hash
def _handle_changed(self, *args):
"""
A change occurred within a param:
Rewrite/validate the block and update the gui.
"""
- # update for the block
self._block.rewrite()
self._block.validate()
self.update_gui()
def _activate_apply(self, *args):
- self.set_response_sensitive(gtk.RESPONSE_APPLY, True)
+ self.set_response_sensitive(Gtk.ResponseType.APPLY, True)
def update_gui(self, widget=None, force=False):
"""
@@ -175,45 +169,48 @@ class PropsDialog(gtk.Dialog):
Update the documentation block.
Hide the box if there are no docs.
"""
- # update the params box
if force or self._params_changed():
# hide params box before changing
for tab, label, vbox in self._params_boxes:
- vbox.hide_all()
+ vbox.hide()
# empty the params box
for child in vbox.get_children():
vbox.remove(child)
- child.destroy()
+ # child.destroy() # disabled because it throws errors...
# repopulate the params box
box_all_valid = True
- for param in filter(lambda p: p.get_tab_label() == tab, self._block.get_params()):
- if param.get_hide() == 'all':
+ for param in self._block.params.values():
+ # todo: why do we even rebuild instead of really hiding params?
+ if param.get_tab_label() != tab or param.get_hide() == 'all':
continue
box_all_valid = box_all_valid and param.is_valid()
+
input_widget = param.get_input(self._handle_changed, self._activate_apply)
- vbox.pack_start(input_widget, input_widget.expand)
- label.set_markup(Utils.parse_template(TAB_LABEL_MARKUP_TMPL, valid=box_all_valid, tab=tab))
- # show params box with new params
- vbox.show_all()
- # update the errors box
+ input_widget.show_all()
+ vbox.pack_start(input_widget, input_widget.expand, True, 1)
+
+ label.set_markup('<span foreground="{color}">{name}</span>'.format(
+ color='black' if box_all_valid else 'red', name=Utils.encode(tab)
+ ))
+ vbox.show() # show params box with new params
+
if self._block.is_valid():
self._error_box.hide()
else:
self._error_box.show()
messages = '\n\n'.join(self._block.get_error_messages())
self._error_messages_text_display.set_text(messages)
- # update the docs box
+
self._update_docs_page()
- # update the generated code
self._update_generated_code_page()
def _update_docs_page(self):
"""Show documentation from XML and try to display best matching docstring"""
- buffer = self._docs_text_display.get_buffer()
- buffer.delete(buffer.get_start_iter(), buffer.get_end_iter())
- pos = buffer.get_end_iter()
+ buf = self._docs_text_display.get_buffer()
+ buf.delete(buf.get_start_iter(), buf.get_end_iter())
+ pos = buf.get_end_iter()
- docstrings = self._block.get_doc()
+ docstrings = self._block.documentation
if not docstrings:
return
@@ -221,11 +218,11 @@ class PropsDialog(gtk.Dialog):
from_xml = docstrings.pop('', '')
for line in from_xml.splitlines():
if line.lstrip() == line and line.endswith(':'):
- buffer.insert_with_tags_by_name(pos, line + '\n', 'b')
+ buf.insert_with_tags_by_name(pos, line + '\n', 'b')
else:
- buffer.insert(pos, line + '\n')
+ buf.insert(pos, line + '\n')
if from_xml:
- buffer.insert(pos, '\n')
+ buf.insert(pos, '\n')
# if given the current parameters an exact match can be made
block_constructor = self._block.get_make().rsplit('.', 2)[-1]
@@ -234,19 +231,19 @@ class PropsDialog(gtk.Dialog):
docstrings = {block_class: docstrings[block_class]}
# show docstring(s) extracted from python sources
- for cls_name, docstring in docstrings.iteritems():
- buffer.insert_with_tags_by_name(pos, cls_name + '\n', 'b')
- buffer.insert(pos, docstring + '\n\n')
+ for cls_name, docstring in six.iteritems(docstrings):
+ buf.insert_with_tags_by_name(pos, cls_name + '\n', 'b')
+ buf.insert(pos, docstring + '\n\n')
pos.backward_chars(2)
- buffer.delete(pos, buffer.get_end_iter())
+ buf.delete(pos, buf.get_end_iter())
def _update_generated_code_page(self):
if not self._code_text_display:
return # user disabled code preview
- buffer = self._code_text_display.get_buffer()
+ buf = self._code_text_display.get_buffer()
block = self._block
- key = block.get_key()
+ key = block.key
if key == 'epy_block':
src = block.get_param('_source_code').get_value()
@@ -258,40 +255,34 @@ class PropsDialog(gtk.Dialog):
def insert(header, text):
if not text:
return
- buffer.insert_with_tags_by_name(buffer.get_end_iter(), header, 'b')
- buffer.insert(buffer.get_end_iter(), text)
+ buf.insert_with_tags_by_name(buf.get_end_iter(), header, 'b')
+ buf.insert(buf.get_end_iter(), text)
- buffer.delete(buffer.get_start_iter(), buffer.get_end_iter())
+ buf.delete(buf.get_start_iter(), buf.get_end_iter())
insert('# Imports\n', '\n'.join(block.get_imports()))
- if key.startswith('variable'):
+ if block.is_variable:
insert('\n\n# Variables\n', block.get_var_make())
insert('\n\n# Blocks\n', block.get_make())
if src:
insert('\n\n# External Code ({}.py)\n'.format(block.get_id()), src)
def _handle_key_press(self, widget, event):
- """
- Handle key presses from the keyboard.
- Call the ok response when enter is pressed.
-
- Returns:
- false to forward the keypress
- """
- if (event.keyval == gtk.keysyms.Return and
- event.state & gtk.gdk.CONTROL_MASK == 0 and
- not isinstance(widget.get_focus(), gtk.TextView)
- ):
- self.response(gtk.RESPONSE_ACCEPT)
+ close_dialog = (
+ event.keyval == Gdk.KEY_Return and
+ event.get_state() & Gdk.ModifierType.CONTROL_MASK == 0 and
+ not isinstance(widget.get_focus(), Gtk.TextView)
+ )
+ if close_dialog:
+ self.response(Gtk.ResponseType.ACCEPT)
return True # handled here
+
return False # forward the keypress
def _handle_response(self, widget, response):
- if response in (gtk.RESPONSE_APPLY, gtk.RESPONSE_ACCEPT):
+ if response in (Gtk.ResponseType.APPLY, Gtk.ResponseType.ACCEPT):
for tab, label, vbox in self._params_boxes:
for child in vbox.get_children():
child.apply_pending_changes()
- self.set_response_sensitive(gtk.RESPONSE_APPLY, False)
+ self.set_response_sensitive(Gtk.ResponseType.APPLY, False)
return True
return False
-
-