summaryrefslogtreecommitdiff
path: root/grc
diff options
context:
space:
mode:
Diffstat (limited to 'grc')
-rw-r--r--grc/gui/ActionHandler.py6
-rw-r--r--grc/gui/Actions.py2
-rw-r--r--grc/gui/BlockTreeWindow.py52
-rw-r--r--grc/gui/Colors.py3
-rw-r--r--grc/gui/DrawingArea.py27
-rw-r--r--grc/gui/FileDialogs.py15
-rw-r--r--grc/gui/Preferences.py4
-rw-r--r--grc/gui/PropsDialog.py38
-rw-r--r--grc/python/Block.py7
-rw-r--r--grc/python/Platform.py25
-rw-r--r--grc/python/extract_docs.py2
11 files changed, 137 insertions, 44 deletions
diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py
index 7766a0a853..0f227d08f5 100644
--- a/grc/gui/ActionHandler.py
+++ b/grc/gui/ActionHandler.py
@@ -34,7 +34,7 @@ from .ParserErrorsDialog import ParserErrorsDialog
from .MainWindow import MainWindow
from .PropsDialog import PropsDialog
from .FileDialogs import (OpenFlowGraphFileDialog, SaveFlowGraphFileDialog,
- SaveReportsFileDialog, SaveImageFileDialog,
+ SaveReportsFileDialog, SaveScreenShotDialog,
OpenQSSFileDialog)
from .Constants import DEFAULT_CANVAS_SIZE, IMAGE_FILE_EXTENSION, GR_PREFIX
@@ -521,9 +521,9 @@ class ActionHandler:
self.main_window.tool_bar.refresh_submenus()
self.main_window.menu_bar.refresh_submenus()
elif action == Actions.FLOW_GRAPH_SCREEN_CAPTURE:
- file_path = SaveImageFileDialog(self.get_page().get_file_path()).run()
+ file_path, background_transparent = SaveScreenShotDialog(self.get_page().get_file_path()).run()
if file_path is not None:
- pixbuf = self.get_flow_graph().get_drawing_area().get_pixbuf()
+ pixbuf = self.get_flow_graph().get_drawing_area().get_screenshot(background_transparent)
pixbuf.save(file_path, IMAGE_FILE_EXTENSION[1:])
##################################################
# Gen/Exec/Stop
diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py
index 9b32b3e601..d53375f291 100644
--- a/grc/gui/Actions.py
+++ b/grc/gui/Actions.py
@@ -386,7 +386,7 @@ FLOW_GRAPH_KILL = Action(
keypresses=(gtk.keysyms.F7, NO_MODS_MASK),
)
FLOW_GRAPH_SCREEN_CAPTURE = Action(
- label='Sc_reen Capture',
+ label='Screen Ca_pture',
tooltip='Create a screen capture of the flow graph',
stock_id=gtk.STOCK_PRINT,
keypresses=(gtk.keysyms.Print, NO_MODS_MASK),
diff --git a/grc/gui/BlockTreeWindow.py b/grc/gui/BlockTreeWindow.py
index 6b3ebf7807..8a29120102 100644
--- a/grc/gui/BlockTreeWindow.py
+++ b/grc/gui/BlockTreeWindow.py
@@ -30,12 +30,27 @@ KEY_INDEX = 1
DOC_INDEX = 2
DOC_MARKUP_TMPL = """\
-#if $doc
-#if len($doc) > 1000
-#set $doc = $doc[:1000] + '...'
+#set $docs = []
+#if $doc.get('')
+ #set $docs += $doc.pop('').splitlines() + ['']
#end if
-$encode($doc)#slurp
-#else
+#for b, d in $doc.iteritems()
+ #set $docs += ['--- {0} ---'.format(b)] + d.splitlines() + ['']
+#end for
+#set $len_out = 0
+#for $n, $line in $enumerate($docs[:-1])
+#if $n
+
+#end if
+$encode($line)#slurp
+#set $len_out += $len($line)
+#if $n > 10 or $len_out > 500
+
+...#slurp
+#break
+#end if
+#end for
+#if $len_out == 0
undocumented#slurp
#end if"""
@@ -129,8 +144,10 @@ class BlockTreeWindow(gtk.VBox):
category: the category list or path string
block: the block object or None
"""
- if treestore is None: treestore = self.treestore
- if categories is None: categories = self._categories
+ if treestore is None:
+ treestore = self.treestore
+ if categories is None:
+ categories = self._categories
if isinstance(category, (str, unicode)): category = category.split('/')
category = tuple(filter(lambda x: x, category)) # tuple is hashable
@@ -138,17 +155,18 @@ class BlockTreeWindow(gtk.VBox):
for i, cat_name in enumerate(category):
sub_category = category[:i+1]
if sub_category not in categories:
- iter = treestore.insert_before(categories[sub_category[:-1]], None)
- treestore.set_value(iter, NAME_INDEX, '[ %s ]'%cat_name)
- treestore.set_value(iter, KEY_INDEX, '')
- treestore.set_value(iter, DOC_INDEX, Utils.parse_template(CAT_MARKUP_TMPL, cat=cat_name))
- categories[sub_category] = iter
+ iter_ = treestore.insert_before(categories[sub_category[:-1]], None)
+ treestore.set_value(iter_, NAME_INDEX, cat_name)
+ treestore.set_value(iter_, KEY_INDEX, '')
+ treestore.set_value(iter_, DOC_INDEX, Utils.parse_template(CAT_MARKUP_TMPL, cat=cat_name))
+ categories[sub_category] = iter_
# add block
- if block is None: return
- iter = treestore.insert_before(categories[category], None)
- treestore.set_value(iter, NAME_INDEX, block.get_name())
- treestore.set_value(iter, KEY_INDEX, block.get_key())
- treestore.set_value(iter, DOC_INDEX, Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc()))
+ if block is None:
+ return
+ iter_ = treestore.insert_before(categories[category], None)
+ treestore.set_value(iter_, NAME_INDEX, block.get_name())
+ treestore.set_value(iter_, KEY_INDEX, block.get_key())
+ treestore.set_value(iter_, DOC_INDEX, Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc()))
def update_docs(self):
"""Update the documentation column of every block"""
diff --git a/grc/gui/Colors.py b/grc/gui/Colors.py
index 52c95e8edf..050b363cdd 100644
--- a/grc/gui/Colors.py
+++ b/grc/gui/Colors.py
@@ -33,8 +33,9 @@ try:
PARAM_ENTRY_TEXT_COLOR = get_color('black')
ENTRYENUM_CUSTOM_COLOR = get_color('#EEEEEE')
#flow graph color constants
- FLOWGRAPH_BACKGROUND_COLOR = get_color('#FFF9FF')
+ FLOWGRAPH_BACKGROUND_COLOR = get_color('#FFFFFF')
COMMENT_BACKGROUND_COLOR = get_color('#F3F3F3')
+ FLOWGRAPH_EDGE_COLOR = COMMENT_BACKGROUND_COLOR
#block color constants
BLOCK_ENABLED_COLOR = get_color('#F1ECFF')
BLOCK_DISABLED_COLOR = get_color('#CCCCCC')
diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py
index 4412129809..6a1df27a8c 100644
--- a/grc/gui/DrawingArea.py
+++ b/grc/gui/DrawingArea.py
@@ -20,7 +20,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import pygtk
pygtk.require('2.0')
import gtk
+
from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT, DND_TARGETS
+import Colors
+
class DrawingArea(gtk.DrawingArea):
"""
@@ -68,13 +71,21 @@ class DrawingArea(gtk.DrawingArea):
self.set_flags(gtk.CAN_FOCUS) # self.set_can_focus(True)
self.connect('focus-out-event', self._handle_focus_lost_event)
- def new_pixmap(self, width, height): return gtk.gdk.Pixmap(self.window, width, height, -1)
- def get_pixbuf(self):
- width, height = self._pixmap.get_size()
- pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 0, 8, width, height)
- pixbuf.get_from_drawable(self._pixmap, self._pixmap.get_colormap(), 0, 0, 0, 0, width, height)
+ def new_pixmap(self, width, height):
+ return gtk.gdk.Pixmap(self.window, width, height, -1)
+
+ def get_screenshot(self, transparent_bg=False):
+ pixmap = self._pixmap
+ W, H = pixmap.get_size()
+ pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 0, 8, W, H)
+ pixbuf.fill(0xFF + Colors.FLOWGRAPH_BACKGROUND_COLOR.pixel << 8)
+ pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, W-1, H-1)
+ if transparent_bg:
+ bgc = Colors.FLOWGRAPH_BACKGROUND_COLOR
+ pixbuf = pixbuf.add_alpha(True, bgc.red, bgc.green, bgc.blue)
return pixbuf
+
##########################################################################
## Handlers
##########################################################################
@@ -149,6 +160,12 @@ class DrawingArea(gtk.DrawingArea):
gc = self.window.new_gc()
self._flow_graph.draw(gc, self._pixmap)
self.window.draw_drawable(gc, self._pixmap, 0, 0, 0, 0, -1, -1)
+ # draw a light grey line on the bottom and right end of the canvas.
+ # this is useful when the theme uses the same panel bg color as the canvas
+ W, H = self._pixmap.get_size()
+ gc.set_foreground(Colors.FLOWGRAPH_EDGE_COLOR)
+ self.window.draw_line(gc, 0, H-1, W, H-1)
+ self.window.draw_line(gc, W-1, 0, W-1, H)
def _handle_focus_lost_event(self, widget, event):
# don't clear selection while context menu is active
diff --git a/grc/gui/FileDialogs.py b/grc/gui/FileDialogs.py
index 730ac6fba0..4b5770ad21 100644
--- a/grc/gui/FileDialogs.py
+++ b/grc/gui/FileDialogs.py
@@ -210,3 +210,18 @@ class SaveFlowGraphFileDialog(FileDialog): type = SAVE_FLOW_GRAPH
class OpenQSSFileDialog(FileDialog): type = OPEN_QSS_THEME
class SaveReportsFileDialog(FileDialog): type = SAVE_REPORTS
class SaveImageFileDialog(FileDialog): type = SAVE_IMAGE
+
+
+class SaveScreenShotDialog(SaveImageFileDialog):
+
+ def __init__(self, current_file_path=''):
+ SaveImageFileDialog.__init__(self, current_file_path)
+ self._button = button = gtk.CheckButton('_Background transparent')
+ self._button.set_active(Preferences.screen_shot_background_transparent())
+ self.set_extra_widget(button)
+
+ def run(self):
+ filename = SaveImageFileDialog.run(self)
+ bg_transparent = self._button.get_active()
+ Preferences.screen_shot_background_transparent(bg_transparent)
+ return filename, bg_transparent
diff --git a/grc/gui/Preferences.py b/grc/gui/Preferences.py
index 3ebee24345..ad2206ca29 100644
--- a/grc/gui/Preferences.py
+++ b/grc/gui/Preferences.py
@@ -150,3 +150,7 @@ def blocks_window_position(pos=None):
def xterm_missing(cmd=None):
return entry('xterm_missing', cmd, default='INVALID_XTERM_SETTING')
+
+
+def screen_shot_background_transparent(transparent=None):
+ return entry('screen_shot_background_transparent', transparent, default=False)
diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py
index bf7d31d391..7c66a77a54 100644
--- a/grc/gui/PropsDialog.py
+++ b/grc/gui/PropsDialog.py
@@ -97,7 +97,8 @@ class PropsDialog(gtk.Dialog):
self._params_boxes.append((tab, label, vbox))
# Docs for the block
- self._docs_text_display = SimpleTextDisplay()
+ 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)
@@ -200,10 +201,43 @@ class PropsDialog(gtk.Dialog):
messages = '\n\n'.join(self._block.get_error_messages())
self._error_messages_text_display.set_text(messages)
# update the docs box
- self._docs_text_display.set_text(self._block.get_doc())
+ 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()
+
+ docstrings = self._block.get_doc()
+ if not docstrings:
+ return
+
+ # show documentation string from block xml
+ 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')
+ else:
+ buffer.insert(pos, line + '\n')
+ if from_xml:
+ buffer.insert(pos, '\n')
+
+ # if given the current parameters an exact match can be made
+ block_constructor = self._block.get_make().rsplit('.', 2)[-1]
+ block_class = block_constructor.partition('(')[0].strip()
+ if block_class in docstrings:
+ 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')
+ pos.backward_chars(2)
+ buffer.delete(pos, buffer.get_end_iter())
+
def _update_generated_code_page(self):
if not self._code_text_display:
return # user disabled code preview
diff --git a/grc/python/Block.py b/grc/python/Block.py
index f5c994dc05..f43b006e5f 100644
--- a/grc/python/Block.py
+++ b/grc/python/Block.py
@@ -185,8 +185,11 @@ class Block(_Block, _GUIBlock):
def get_doc(self):
platform = self.get_parent().get_parent()
- extracted_docs = platform.block_docstrings.get(self._key, '')
- return (self._doc + '\n\n' + extracted_docs).strip()
+ documentation = platform.block_docstrings.get(self._key, {})
+ from_xml = self._doc.strip()
+ if from_xml:
+ documentation[''] = from_xml
+ return documentation
def get_category(self):
return _Block.get_category(self)
diff --git a/grc/python/Platform.py b/grc/python/Platform.py
index 1d932761d8..5932818c1e 100644
--- a/grc/python/Platform.py
+++ b/grc/python/Platform.py
@@ -38,8 +38,6 @@ from .Constants import (
PREFS_FILE, PREFS_FILE_OLD, CORE_TYPES
)
-COLORS = [(name, color) for name, key, sizeof, color in CORE_TYPES]
-
class Platform(_Platform, _GUIPlatform):
def __init__(self):
@@ -52,17 +50,11 @@ class Platform(_Platform, _GUIPlatform):
if not os.path.exists(os.path.dirname(PREFS_FILE)):
os.mkdir(os.path.dirname(PREFS_FILE))
- self.block_docstrings = block_docstrings = dict()
- self.block_docstrings_loaded_callback = lambda: None
-
- def setter(key, docs):
- block_docstrings[key] = '\n\n'.join(
- '--- {0} ---\n{1}\n'.format(b, d.replace('\n\n', '\n'))
- for b, d in docs.iteritems() if d is not None
- )
+ self.block_docstrings = {}
+ self.block_docstrings_loaded_callback = lambda: None # dummy to be replaced by BlockTreeWindow
self._docstring_extractor = extract_docs.SubprocessLoader(
- callback_query_result=setter,
+ callback_query_result=self._save_docstring_extraction_result,
callback_finished=lambda: self.block_docstrings_loaded_callback()
)
@@ -78,7 +70,7 @@ class Platform(_Platform, _GUIPlatform):
block_dtd=BLOCK_DTD,
default_flow_graph=DEFAULT_FLOW_GRAPH,
generator=Generator,
- colors=COLORS,
+ colors=[(name, color) for name, key, sizeof, color in CORE_TYPES],
)
self._move_old_pref_file()
_GUIPlatform.__init__(
@@ -87,6 +79,15 @@ class Platform(_Platform, _GUIPlatform):
)
self._auto_hier_block_generate_chain = set()
+ def _save_docstring_extraction_result(self, key, docstrings):
+ docs = {}
+ for match, docstring in docstrings.iteritems():
+ if not docstring or match.endswith('_sptr'):
+ continue
+ docstring = docstring.replace('\n\n', '\n').strip()
+ docs[match] = docstring
+ self.block_docstrings[key] = docs
+
@staticmethod
def _move_old_pref_file():
if PREFS_FILE == PREFS_FILE_OLD:
diff --git a/grc/python/extract_docs.py b/grc/python/extract_docs.py
index d8dc4f4e8f..7c149ce593 100644
--- a/grc/python/extract_docs.py
+++ b/grc/python/extract_docs.py
@@ -70,7 +70,7 @@ def docstring_guess_from_key(key):
)
for match in filter(pattern.match, dir(module)):
try:
- doc_strings[match] = getattr(module, match).__doc__.strip()
+ doc_strings[match] = getattr(module, match).__doc__
except AttributeError:
continue