diff --git a/src/libprs500/gui2/lrf_renderer/document.py b/src/libprs500/gui2/lrf_renderer/document.py
index c369176132..2fe4533d20 100644
--- a/src/libprs500/gui2/lrf_renderer/document.py
+++ b/src/libprs500/gui2/lrf_renderer/document.py
@@ -14,7 +14,7 @@
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
''''''
-import collections
+import collections, itertools
from PyQt4.QtCore import Qt, QByteArray, SIGNAL
from PyQt4.QtGui import QGraphicsRectItem, QGraphicsScene, QPen, \
@@ -127,7 +127,7 @@ class _Canvas(QGraphicsRectItem):
if isinstance(line, QGraphicsItem):
line.setParentItem(self)
line.setPos(x + line.getx(textwidth), y)
- y += line.height
+ y += line.height + line.line_space
else:
y += line.height
if not block.has_content:
@@ -165,6 +165,18 @@ class _Canvas(QGraphicsRectItem):
self.is_full = y > self.max_y-5
ib.has_content = False
+ def search(self, phrase):
+ matches = []
+ for child in self.children():
+ if hasattr(child, 'search'):
+ res = child.search(phrase)
+ if res:
+ if isinstance(res, list):
+ matches += res
+ else:
+ matches.append(res)
+ return matches
+
class Canvas(_Canvas, ContentObject):
@@ -273,6 +285,7 @@ class Page(_Canvas):
def add_block(self, block):
self.layout_block(block, 0, self.current_y)
+
class Chapter(object):
@@ -291,6 +304,15 @@ class Chapter(object):
def screen(self, odd):
return self.oddscreen if odd else self.evenscreen
+
+ def search(self, phrase):
+ pages = []
+ for i in range(len(self.pages)):
+ matches = self.pages[i].search(phrase)
+ if matches:
+ pages.append([i, matches])
+ return pages
+
class History(collections.deque):
@@ -331,6 +353,9 @@ class Document(QGraphicsScene):
self.link_map = {}
self.chapter_map = {}
self.history = History()
+ self.last_search = iter([])
+ if not opts.white_background:
+ self.setBackgroundBrush(QBrush(QColor(0xee, 0xee, 0xee)))
def page_of(self, oid):
for chapter in self.chapters:
@@ -492,3 +517,22 @@ class Document(QGraphicsScene):
def show_page_at_percent(self, p):
num = self.num_of_pages*(p/100.)
self.show_page(num)
+
+ def search(self, phrase):
+ if not phrase:
+ return
+ matches = []
+ for i in range(len(self.chapters)):
+ cmatches = self.chapters[i].search(phrase)
+ for match in cmatches:
+ match[0] += sum(self.chapter_layout[:i])+1
+ matches += cmatches
+ self.last_search = itertools.cycle(matches)
+ self.next_match()
+
+ def next_match(self):
+ page_num = self.last_search.next()[0]
+ if self.current_page == page_num:
+ self.update()
+ self.show_page(page_num)
+
\ No newline at end of file
diff --git a/src/libprs500/gui2/lrf_renderer/main.py b/src/libprs500/gui2/lrf_renderer/main.py
index 3642148013..fc84bad006 100644
--- a/src/libprs500/gui2/lrf_renderer/main.py
+++ b/src/libprs500/gui2/lrf_renderer/main.py
@@ -22,7 +22,7 @@ from PyQt4.QtCore import Qt, QObject, SIGNAL, QCoreApplication, QThread
from libprs500 import __appname__, __version__, __author__, setup_cli_handlers, islinux
from libprs500.ebooks.lrf.parser import LRFDocument
-from libprs500.gui2 import ORG_NAME, APP_UID
+from libprs500.gui2 import ORG_NAME, APP_UID, error_dialog
from libprs500.gui2.dialogs.conversion_error import ConversionErrorDialog
from libprs500.gui2.lrf_renderer.main_ui import Ui_MainWindow
from libprs500.gui2.main_window import MainWindow
@@ -65,6 +65,8 @@ class Main(QObject, Ui_MainWindow, MainWindow):
self.search.help_text = 'Search'
self.search.clear_to_help()
+ QObject.connect(self.search, SIGNAL('search(PyQt_PyObject, PyQt_PyObject)'), self.find)
+ self.last_search = None
self.action_next_page.setShortcuts(QKeySequence.MoveToNextPage)
self.action_previous_page.setShortcuts(QKeySequence.MoveToPreviousPage)
@@ -91,6 +93,12 @@ class Main(QObject, Ui_MainWindow, MainWindow):
self.stack.setCurrentIndex(1)
self.renderer.start()
+ def find(self, search, refinement):
+ self.last_search = search
+ try:
+ self.document.search(search)
+ except StopIteration:
+ error_dialog(self.window, 'No matches found', 'No matches for the search phrase %s were found.'%(search,)).exec_()
def parsed(self, *args):
if self.renderer.lrf is not None:
@@ -100,13 +108,13 @@ class Main(QObject, Ui_MainWindow, MainWindow):
self.document_title = self.renderer.lrf.metadata.title
if self.opts.profile:
import cProfile
- render, lrf = self.document.render, self.renderer.lrf
- cProfile.runctx('render(lrf)', globals(), locals(), lrf.metadata.title+'.stats')
+ lrf = self.renderer.lrf
+ cProfile.runctx('self.document.render(lrf)', globals(), locals(), lrf.metadata.title+'.stats')
print 'Stats written to', self.renderer.lrf.metadata.title+'.stats'
else:
start = time.time()
self.document.render(self.renderer.lrf)
- print 'Rendering time:', time.time()-start, 'seconds'
+ print 'Layout time:', time.time()-start, 'seconds'
self.renderer.lrf = None
self.graphics_view.setScene(self.document)
self.graphics_view.show()
@@ -132,7 +140,7 @@ class Main(QObject, Ui_MainWindow, MainWindow):
self.progress_bar.setMinimum(0)
self.progress_bar.setMaximum(num)
self.progress_bar.setValue(0)
- self.progress_label.setText('Rendering '+ self.document_title)
+ self.progress_label.setText('Laying out '+ self.document_title)
else:
self.progress_bar.setValue(self.progress_bar.value()+1)
QCoreApplication.processEvents()
@@ -171,6 +179,8 @@ def option_parser():
default=False, action='store_true', dest='visual_debug')
parser.add_option('--disable-hyphenation', dest='hyphenate', default=True, action='store_false',
help='Disable hyphenation. Should significantly speed up rendering.')
+ parser.add_option('--white-background', dest='white_background', default=False, action='store_true',
+ help='By default the background is off white as I find this easier on the eyes. Use this option to make the background pure white.')
parser.add_option('--profile', dest='profile', default=False, action='store_true',
help='Profile the LRF renderer')
return parser
diff --git a/src/libprs500/gui2/lrf_renderer/text.py b/src/libprs500/gui2/lrf_renderer/text.py
index cd022b7aac..14f64d2dfb 100644
--- a/src/libprs500/gui2/lrf_renderer/text.py
+++ b/src/libprs500/gui2/lrf_renderer/text.py
@@ -317,23 +317,25 @@ class TextBlock(object):
return s
class Link(QGraphicsRectItem):
- inactive_brush = QBrush(QColor(0x00, 0x00, 0x00, 0x09))
+ inactive_brush = QBrush(QColor(0xff, 0xff, 0xff, 0xff))
active_brush = QBrush(QColor(0x00, 0x00, 0x00, 0x59))
def __init__(self, parent, start, stop, refobj, slot):
QGraphicsRectItem.__init__(self, start, 0, stop-start, parent.height, parent)
self.refobj = refobj
self.slot = slot
- self.setBrush(self.__class__.inactive_brush)
+ self.brush = self.__class__.inactive_brush
self.setPen(QPen(Qt.NoPen))
self.setCursor(Qt.PointingHandCursor)
self.setAcceptsHoverEvents(True)
def hoverEnterEvent(self, event):
- self.setBrush(self.__class__.active_brush)
+ self.brush = self.__class__.active_brush
+ self.parentItem().update()
def hoverLeaveEvent(self, event):
- self.setBrush(self.__class__.inactive_brush)
+ self.brush = self.__class__.inactive_brush
+ self.parentItem().update()
def mousePressEvent(self, event):
self.hoverLeaveEvent(None)
@@ -371,6 +373,7 @@ class Line(QGraphicsItem):
self.tokens.append(plot)
self.current_width += plot.width
self.height = max(self.height, plot.height)
+ self.add_space(6)
def populate(self, phrase, ts, process_space=True):
phrase_pos = 0
@@ -446,7 +449,6 @@ class Line(QGraphicsItem):
self.width = float(self.current_width)
if self.height == 0:
self.height = baselineskip
- self.height += linespace
self.height = float(self.height)
self.vdebug = vdebug
@@ -470,12 +472,24 @@ class Line(QGraphicsItem):
painter.drawRect(self.boundingRect())
painter.restore()
painter.save()
+ painter.setPen(QPen(Qt.NoPen))
+ for c in self.children():
+ painter.setBrush(c.brush)
+ painter.drawRect(c.boundingRect())
+ painter.restore()
+ painter.save()
for tok in self.tokens:
if isinstance(tok, (int, float)):
x += tok
elif isinstance(tok, Word):
painter.setFont(tok.font)
p = painter.pen()
+ if tok.highlight:
+ painter.save()
+ painter.setPen(QPen(Qt.NoPen))
+ painter.setBrush(QBrush(Qt.yellow))
+ painter.drawRect(x, 0, tok.width, tok.height)
+ painter.restore()
painter.setPen(QPen(tok.text_color))
painter.drawText(x, y, tok.string)
painter.setPen(p)
@@ -485,6 +499,30 @@ class Line(QGraphicsItem):
x += tok.width
painter.restore()
+ def search(self, phrase):
+ tokens = phrase.lower().split()
+ if len(tokens) < 1: return None
+ for i in range(len(self.tokens)):
+ if not isinstance(self.tokens[i], Word):
+ continue
+ src = qstring_to_unicode(self.tokens[i].string).lower()
+ self.tokens[i].highlight = False
+ if tokens[0] in src:
+ if len(tokens) == 1:
+ self.tokens[i].highlight = True
+ return self
+ else:
+ match = True
+ for j in range(len(tokens)):
+ if i+j >= len(self.tokens) or tokens[j].lower() != qstring_to_unicode(self.tokens[i+j].string).lower():
+ match = False
+ break
+ self.tokens[i+j].highlight = True
+ if match:
+ return self
+ return None
+
+
def getx(self, textwidth):
if self.align == 'head':
return self.offset
@@ -497,7 +535,7 @@ class Line(QGraphicsItem):
s = u''
for tok in self.tokens:
if isinstance(tok, (int, float)):
- s += ' :%.1f: '%(tok,)
+ s += ' '
elif isinstance(tok, Word):
s += qstring_to_unicode(tok.string)
return s
@@ -512,6 +550,7 @@ class Word(object):
self.string, self.width, self.height = QString(string), width, height
self.font = font
self.text_color = ts.textcolor
+ self.highlight = False
def main(args=sys.argv):
return 0