Start work on Live CSS view

This commit is contained in:
Kovid Goyal 2014-05-17 22:15:50 +05:30
parent 06f3640ceb
commit 905e1b5e86
8 changed files with 133 additions and 1 deletions

View File

@ -228,6 +228,7 @@ class Boss(QObject):
for name in tuple(editors):
self.close_editor(name)
self.gui.preview.clear()
self.gui.live_css.clear()
self.container_count = -1
if self.tdir:
shutil.rmtree(self.tdir, ignore_errors=True)
@ -311,6 +312,7 @@ class Boss(QObject):
self.close_editor(name)
if not editors:
self.gui.preview.clear()
self.gui.live_css.clear()
if remove_names_from_toc(current_container(), spine_names + list(other_items)):
self.gui.toc_view.update_if_visible()
toc = find_existing_toc(current_container())
@ -1028,11 +1030,19 @@ class Boss(QObject):
if name is not None and getattr(ed, 'syntax', None) == 'html':
self.gui.preview.sync_to_editor(name, ed.current_line)
def sync_live_css_to_editor(self):
ed = self.gui.central.current_editor
if ed is not None:
name = editor_name(ed)
if name is not None and getattr(ed, 'syntax', None) == 'html':
self.gui.live_css.sync_to_editor(name)
def init_editor(self, name, editor, data=None, use_template=False):
editor.undo_redo_state_changed.connect(self.editor_undo_redo_state_changed)
editor.data_changed.connect(self.editor_data_changed)
editor.copy_available_state_changed.connect(self.editor_copy_available_state_changed)
editor.cursor_position_changed.connect(self.sync_preview_to_editor)
editor.cursor_position_changed.connect(self.sync_live_css_to_editor)
editor.cursor_position_changed.connect(self.update_cursor_position)
if hasattr(editor, 'word_ignored'):
editor.word_ignored.connect(self.word_ignored)
@ -1153,6 +1163,7 @@ class Boss(QObject):
# focused. This is not inefficient since multiple requests
# to sync are de-bounced with a 100 msec wait.
self.sync_preview_to_editor()
self.sync_live_css_to_editor()
if name is not None:
self.gui.file_list.mark_name_as_current(name)
if ed.has_line_numbers:
@ -1182,6 +1193,7 @@ class Boss(QObject):
editor.break_cycles()
if not editors or getattr(self.gui.central.current_editor, 'syntax', None) != 'html':
self.gui.preview.clear()
self.gui.live_css.clear()
def insert_character(self):
self.gui.insert_char.show()
@ -1251,6 +1263,7 @@ class Boss(QObject):
def shutdown(self):
self.gui.preview.stop_refresh_timer()
self.gui.live_css.stop_update_timer()
self.save_state()
[x.reject() for x in _diff_dialogs]
del _diff_dialogs[:]

View File

@ -20,3 +20,6 @@ class NullSmarts(object):
def verify_for_spellcheck(self, cursor, highlighter):
return False
def cursor_position_with_sourceline(self, cursor):
return None, None

View File

@ -312,3 +312,26 @@ class HTMLSmarts(NullSmarts):
return False
def cursor_position_with_sourceline(self, cursor):
''' Return the tag containing the current cursor as a source line
number and a list of tags defined on that line upto and including the
containing tag. '''
block = cursor.block()
offset = cursor.position() - block.position()
block, boundary = next_tag_boundary(block, offset, forward=False)
if block is None:
return None, None
if boundary.is_start:
# We are inside a tag, use this tag
start_block, start_offset = block, boundary.offset
else:
tag = find_closest_containing_tag(block, offset)
if tag is None:
return None, None
start_block, start_offset = tag.start_block, tag.start_offset
sourceline = start_block.blockNumber()
ud = start_block.userData()
if ud is None:
return None, None
all_tags = [t.name for t in ud.tags if (t.is_start and not t.closing and t.offset <= start_offset)]
return sourceline, all_tags

View File

@ -749,3 +749,6 @@ class TextEdit(PlainTextEdit):
if hasattr(self.smarts, 'rename_block_tag'):
self.smarts.rename_block_tag(self, new_name)
def current_tag(self):
return self.smarts.cursor_position_with_sourceline(self.textCursor())

View File

@ -112,6 +112,9 @@ class Editor(QMainWindow):
self.editor.go_to_line(val)
return property(fget=fget, fset=fset)
def current_tag(self):
return self.editor.current_tag()
@property
def number_of_lines(self):
return self.editor.blockCount()

View File

@ -0,0 +1,65 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
from PyQt4.Qt import (QWidget, QTimer)
from calibre.gui2.tweak_book import editors, actions
class LiveCSS(QWidget):
def __init__(self, preview, parent=None):
QWidget.__init__(self, parent)
self.preview = preview
preview.refreshed.connect(self.update_data)
self.update_timer = QTimer(self)
self.update_timer.timeout.connect(self.update_data)
self.update_timer.setSingleShot(True)
def clear(self):
pass # TODO: Implement this
def show_data(self, editor_name, sourceline, tags):
if sourceline is None:
self.clear()
else:
pass # TODO: Do update
@property
def current_name(self):
return self.preview.current_name
@property
def is_visible(self):
return self.isVisible()
def showEvent(self, ev):
self.update_timer.start()
actions['auto-reload-preview'].setEnabled(True)
return QWidget.showEvent(self, ev)
def sync_to_editor(self, name):
self.start_update_timer()
def update_data(self):
if not self.is_visible:
return
editor_name = self.current_name
ed = editors.get(editor_name, None)
if self.update_timer.isActive() or (ed is None and editor_name is not None):
return QTimer.singleShot(100, self.update_data)
if ed is not None:
sourceline, tags = ed.current_tag()
self.show_data(editor_name, sourceline, tags)
def start_update_timer(self):
if self.is_visible:
self.update_timer.start(1000)
def stop_update_timer(self):
self.update_timer.stop()

View File

@ -435,6 +435,7 @@ class Preview(QWidget):
split_requested = pyqtSignal(object, object, object)
split_start_requested = pyqtSignal()
link_clicked = pyqtSignal(object, object)
refreshed = pyqtSignal()
def __init__(self, parent=None):
QWidget.__init__(self, parent)
@ -558,6 +559,7 @@ class Preview(QWidget):
self.view.setUrl(current_url)
else:
self.view.refresh()
self.refreshed.emit()
def clear(self):
self.view.clear()
@ -567,14 +569,26 @@ class Preview(QWidget):
def is_visible(self):
return actions['preview-dock'].isChecked()
@property
def live_css_is_visible(self):
try:
return actions['live-css-dock'].isChecked()
except KeyError:
return False
def start_refresh_timer(self):
if self.is_visible and actions['auto-reload-preview'].isChecked():
if self.live_css_is_visible or (self.is_visible and actions['auto-reload-preview'].isChecked()):
self.refresh_timer.start(tprefs['preview_refresh_time'] * 1000)
def stop_refresh_timer(self):
self.refresh_timer.stop()
def auto_reload_toggled(self, checked):
if self.live_css_is_visible and not actions['auto-reload-preview'].isChecked():
actions['auto-reload-preview'].setChecked(True)
error_dialog(self, _('Cannot disable'), _(
'Auto reloading of the preview panel cannot be disabled while the'
' Live CSS panel is open.'), show=True)
actions['auto-reload-preview'].setToolTip(_(
'Auto reload preview when text changes in editor') if not checked else _(
'Disable auto reload of preview'))

View File

@ -33,6 +33,7 @@ from calibre.gui2.tweak_book.spell import SpellCheck
from calibre.gui2.tweak_book.search import SavedSearches
from calibre.gui2.tweak_book.toc import TOCViewer
from calibre.gui2.tweak_book.char_select import CharSelect
from calibre.gui2.tweak_book.live_css import LiveCSS
from calibre.gui2.tweak_book.editor.widget import register_text_editor_actions
from calibre.gui2.tweak_book.editor.insert_resource import InsertImage
from calibre.utils.icu import character_name
@ -595,6 +596,13 @@ class Main(MainWindow):
d.setWidget(self.preview)
self.addDockWidget(Qt.RightDockWidgetArea, d)
d = create(_('Live CSS'), 'live-css')
d.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea | Qt.BottomDockWidgetArea | Qt.TopDockWidgetArea)
self.live_css = LiveCSS(self.preview, parent=d)
d.setWidget(self.live_css)
self.addDockWidget(Qt.RightDockWidgetArea, d)
d.close() # Hidden by default
d = create(_('Check Book'), 'check-book')
d.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea | Qt.BottomDockWidgetArea | Qt.TopDockWidgetArea)
d.setWidget(self.check_book)