"""
FtpCube
Copyright (C) Michael Gilfix
This file is part of FtpCube.
You should have received a file COPYING containing license terms
along with this program; if not, write to Michael Gilfix
(mgilfix@eecs.tufts.edu) for a copy.
This version of FtpCube is open source; you can redistribute it and/or
modify it under the terms listed in the file COPYING.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
"""
import wx
import formatter
class StaticWrapText(wx.StaticText):
"""Extension class to the static text widget that automatically wraps text to fit the
set fixed width.
The wrapping width is set via an external widget. This prevents the text box from being
expanded by sizers to accomodate all the text instead of wrapping. This widget supports
wx alignment settings for text boxes and overrides the 'SetLabel' method to provide
the wrapping capability."""
DEFAULT_WRAP_WIDTH = 36
def __init__(self, parent, id, label, style=0):
"""Creates a new static wrap text.
The style parameter is not based to the pass class, but is handled internally."""
wx.StaticText.__init__(self, parent, id, label)
# Extract the style cleanly
if style & wx.ALIGN_LEFT:
self.align = wx.ALIGN_LEFT
elif style & wx.ALIGN_CENTER:
self.align = wx.ALIGN_CENTER
elif style & wx.ALIGN_RIGHT:
self.align = wx.ALIGN_RIGHT
else:
self.align = wx.ALIGN_LEFT # Default
self.wrap_width = self.DEFAULT_WRAP_WIDTH
def SetLabel(self, string):
"""Sets the context of the wrapped label.
This formats the label text according to the fixed width."""
text = self.formatText(string)
wx.StaticText.SetLabel(self, text)
def formatText(self, text):
"""Formats the text to contain newlines so as to create wrapping of the text to fit
the maximum label width."""
max_width = self.getWrapTextWidth()
writer = StringWriter(max_width)
writer.new_alignment(self.align)
myformatter = formatter.AbstractFormatter(writer)
for data in text.split('\n'):
myformatter.add_flowing_data(data)
myformatter.end_paragraph(0)
return writer.get_text()
def getWrapTextWidth(self):
"""Returns the wrap width for the label."""
return self.wrap_width
def setWrapTextWidth(self, width):
"""Sets the wrap width for the label."""
self.wrap_width = width
class StringWriter(formatter.NullWriter):
"""Custom string wrapper class that wraps formatting text to fix the specified maximum
width."""
HORIZONTAL_RULE_CHAR = '-'
def __init__(self, max_width):
"""Creates a new string writer and sets the wrapped width to 'max_width'."""
formatter.NullWriter.__init__(self)
self.text = [ ] # The text written so far
self.line = [ ] # The current line to operate on
self.alignment = wx.ALIGN_LEFT
self.max_width = max_width
self.horiz_char = self.HORIZONTAL_RULE_CHAR
self.reset_pos()
def new_alignment(self, align):
"""Sets the text alignment to a wx alignment constant."""
if align not in [ wx.ALIGN_LEFT, wx.ALIGN_CENTER, wx.ALIGN_RIGHT ]:
raise ValueError, align
self.alignment = align
def get_horiz_char(self):
"""Returns the horizontal rule character."""
return self.horiz_char
def set_horiz_char(self, char):
"""Sets the horizontal rule character."""
self.horiz_char = char
def reset_pos(self, pos=0, word_break=False):
"""Resets the position in the wrapped line."""
self.pos = pos
self.word_break = word_break
def reset_line(self):
"""Resets the wrapped line contents."""
self.line = [ ]
self.reset_pos()
def send_paragraph(self, blankline):
"""Produce a paragraph separation of at least 'blankline' blanklines."""
self.text.append(self.collapse_line())
self.text.extend([ ' ' for i in range(blankline) ])
self.reset_line()
def send_line_break(self):
"""Break the current line."""
self.text.append(self.collapse_line())
self.reset_line()
def send_hor_rule(self, *args, **kwargs):
"""Display a horizontal rule on the output device."""
self.text.append(self.collapse_line())
self.text.append(self.horiz_char * self.max_width)
self.reset_line()
def send_flowing_data(self, data):
"""Output character data which may be word wrapped as needed."""
if not data:
return
self.reset_pos(self.pos, self.word_break or data[0] in ' ')
for word in data.split():
if self.word_break:
if self.pos + len(word) >= self.max_width:
self.text.append(self.collapse_line())
self.reset_line()
else:
self.line.append(' ')
self.reset_pos(self.pos + 1)
self.line.append(word)
self.reset_pos(self.pos + len(word), True)
# Set the state of the final word
self.reset_pos(self.pos, data[-1].isspace())
def send_literal_data(self, data):
"""Output characters that have alrady been formatted for display."""
self.line.append(data)
index = data.rfind('\n')
if index != -1:
self.pos = 0
data = data[index + 1:]
data.expandtabs(4)
self.reset_pos(self.pos + len(data))
def collapse_line(self):
"""Collapses the list of words in a line together and performs alignment
adjustment."""
txt = ''.join(self.line)
if self.alignment == wx.ALIGN_LEFT:
txt = txt.ljust(self.max_width)
elif self.alignment == wx.ALIGN_CENTER:
txt = txt.center(self.max_width)
else:
txt = txt.rjust(self.max_width)
return txt
def get_text(self):
"""Returns the wrapped text."""
return '\n'.join(self.text)
|