mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-08-11 09:13:57 -04:00
Start work on Live CSS view
This commit is contained in:
parent
06f3640ceb
commit
905e1b5e86
@ -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[:]
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
||||
|
@ -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()
|
||||
|
65
src/calibre/gui2/tweak_book/live_css.py
Normal file
65
src/calibre/gui2/tweak_book/live_css.py
Normal 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()
|
||||
|
@ -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'))
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user