mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Edit Book: When inserting hyperlinks, allow specifying the text for the hyperlink in the insert hyperlink dialog
This commit is contained in:
parent
b5dba545cd
commit
82e1000626
@ -643,9 +643,9 @@ class Boss(QObject):
|
|||||||
ed.insert_image(href)
|
ed.insert_image(href)
|
||||||
elif action[0] == 'insert_hyperlink':
|
elif action[0] == 'insert_hyperlink':
|
||||||
self.commit_all_editors_to_container()
|
self.commit_all_editors_to_container()
|
||||||
d = InsertLink(current_container(), edname, parent=self.gui)
|
d = InsertLink(current_container(), edname, initial_text=ed.get_smart_selection(), parent=self.gui)
|
||||||
if d.exec_() == d.Accepted:
|
if d.exec_() == d.Accepted:
|
||||||
ed.insert_hyperlink(d.href)
|
ed.insert_hyperlink(d.href, d.text)
|
||||||
else:
|
else:
|
||||||
ed.action_triggered(action)
|
ed.action_triggered(action)
|
||||||
|
|
||||||
|
@ -14,3 +14,6 @@ class NullSmarts(object):
|
|||||||
def get_extra_selections(self, editor):
|
def get_extra_selections(self, editor):
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
def get_smart_selection(self, editor, update=True):
|
||||||
|
return editor.selected_text
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ def rename_tag(cursor, opening_tag, closing_tag, new_name, insert=False):
|
|||||||
cursor.insertText(text)
|
cursor.insertText(text)
|
||||||
cursor.endEditBlock()
|
cursor.endEditBlock()
|
||||||
|
|
||||||
def ensure_not_within_tag_definition(cursor):
|
def ensure_not_within_tag_definition(cursor, forward=True):
|
||||||
''' Ensure the cursor is not inside a tag definition <>. Returns True iff the cursor was moved. '''
|
''' Ensure the cursor is not inside a tag definition <>. Returns True iff the cursor was moved. '''
|
||||||
block, offset = cursor.block(), cursor.positionInBlock()
|
block, offset = cursor.block(), cursor.positionInBlock()
|
||||||
b, boundary = next_tag_boundary(block, offset, forward=False)
|
b, boundary = next_tag_boundary(block, offset, forward=False)
|
||||||
@ -137,10 +137,15 @@ def ensure_not_within_tag_definition(cursor):
|
|||||||
return False
|
return False
|
||||||
if boundary.is_start:
|
if boundary.is_start:
|
||||||
# We are inside a tag
|
# We are inside a tag
|
||||||
block, boundary = next_tag_boundary(block, offset)
|
if forward:
|
||||||
if block is not None:
|
block, boundary = next_tag_boundary(block, offset)
|
||||||
cursor.setPosition(block.position() + boundary.offset + 1)
|
if block is not None:
|
||||||
|
cursor.setPosition(block.position() + boundary.offset + 1)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
cursor.setPosition(b.position() + boundary.offset)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
class HTMLSmarts(NullSmarts):
|
class HTMLSmarts(NullSmarts):
|
||||||
@ -195,7 +200,27 @@ class HTMLSmarts(NullSmarts):
|
|||||||
return error_dialog(editor, _('No found'), _(
|
return error_dialog(editor, _('No found'), _(
|
||||||
'No suitable block level tag was found to rename'), show=True)
|
'No suitable block level tag was found to rename'), show=True)
|
||||||
|
|
||||||
def insert_hyperlink(self, editor, target):
|
def get_smart_selection(self, editor, update=True):
|
||||||
|
cursor = editor.textCursor()
|
||||||
|
if not cursor.hasSelection():
|
||||||
|
return ''
|
||||||
|
left = min(cursor.anchor(), cursor.position())
|
||||||
|
right = max(cursor.anchor(), cursor.position())
|
||||||
|
|
||||||
|
cursor.setPosition(left)
|
||||||
|
ensure_not_within_tag_definition(cursor)
|
||||||
|
left = cursor.position()
|
||||||
|
|
||||||
|
cursor.setPosition(right)
|
||||||
|
ensure_not_within_tag_definition(cursor, forward=False)
|
||||||
|
right = cursor.position()
|
||||||
|
|
||||||
|
cursor.setPosition(left), cursor.setPosition(right, cursor.KeepAnchor)
|
||||||
|
if update:
|
||||||
|
editor.setTextCursor(cursor)
|
||||||
|
return editor.selected_text_from_cursor(cursor)
|
||||||
|
|
||||||
|
def insert_hyperlink(self, editor, target, text):
|
||||||
c = editor.textCursor()
|
c = editor.textCursor()
|
||||||
if c.hasSelection():
|
if c.hasSelection():
|
||||||
c.insertText('') # delete any existing selected text
|
c.insertText('') # delete any existing selected text
|
||||||
@ -204,4 +229,6 @@ class HTMLSmarts(NullSmarts):
|
|||||||
p = c.position()
|
p = c.position()
|
||||||
c.insertText('</a>')
|
c.insertText('</a>')
|
||||||
c.setPosition(p) # ensure cursor is positioned inside the newly created tag
|
c.setPosition(p) # ensure cursor is positioned inside the newly created tag
|
||||||
|
if text:
|
||||||
|
c.insertText(text)
|
||||||
editor.setTextCursor(c)
|
editor.setTextCursor(c)
|
||||||
|
@ -101,9 +101,12 @@ class PlainTextEdit(QPlainTextEdit):
|
|||||||
self.copy()
|
self.copy()
|
||||||
self.textCursor().removeSelectedText()
|
self.textCursor().removeSelectedText()
|
||||||
|
|
||||||
|
def selected_text_from_cursor(self, cursor):
|
||||||
|
return unicodedata.normalize('NFC', unicode(cursor.selectedText()).replace(PARAGRAPH_SEPARATOR, '\n').rstrip('\0'))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def selected_text(self):
|
def selected_text(self):
|
||||||
return unicodedata.normalize('NFC', unicode(self.textCursor().selectedText()).replace(PARAGRAPH_SEPARATOR, '\n').rstrip('\0'))
|
return self.selected_text_from_cursor(self.textCursor())
|
||||||
|
|
||||||
def selection_changed(self):
|
def selection_changed(self):
|
||||||
# Workaround Qt replacing nbsp with normal spaces on copy
|
# Workaround Qt replacing nbsp with normal spaces on copy
|
||||||
@ -602,9 +605,9 @@ class TextEdit(PlainTextEdit):
|
|||||||
c.setPosition(left + len(text), c.KeepAnchor)
|
c.setPosition(left + len(text), c.KeepAnchor)
|
||||||
self.setTextCursor(c)
|
self.setTextCursor(c)
|
||||||
|
|
||||||
def insert_hyperlink(self, target):
|
def insert_hyperlink(self, target, text):
|
||||||
if hasattr(self.smarts, 'insert_hyperlink'):
|
if hasattr(self.smarts, 'insert_hyperlink'):
|
||||||
self.smarts.insert_hyperlink(self, target)
|
self.smarts.insert_hyperlink(self, target, text)
|
||||||
|
|
||||||
def keyPressEvent(self, ev):
|
def keyPressEvent(self, ev):
|
||||||
if ev.key() == Qt.Key_X and ev.modifiers() == Qt.AltModifier:
|
if ev.key() == Qt.Key_X and ev.modifiers() == Qt.AltModifier:
|
||||||
|
@ -144,8 +144,8 @@ class Editor(QMainWindow):
|
|||||||
def insert_image(self, href):
|
def insert_image(self, href):
|
||||||
self.editor.insert_image(href)
|
self.editor.insert_image(href)
|
||||||
|
|
||||||
def insert_hyperlink(self, href):
|
def insert_hyperlink(self, href, text):
|
||||||
self.editor.insert_hyperlink(href)
|
self.editor.insert_hyperlink(href, text)
|
||||||
|
|
||||||
def undo(self):
|
def undo(self):
|
||||||
self.editor.undo()
|
self.editor.undo()
|
||||||
@ -157,6 +157,9 @@ class Editor(QMainWindow):
|
|||||||
def selected_text(self):
|
def selected_text(self):
|
||||||
return self.editor.selected_text
|
return self.editor.selected_text
|
||||||
|
|
||||||
|
def get_smart_selection(self, update=True):
|
||||||
|
return self.editor.smarts.get_smart_selection(self.editor, update=update)
|
||||||
|
|
||||||
# Search and replace {{{
|
# Search and replace {{{
|
||||||
def mark_selected_text(self):
|
def mark_selected_text(self):
|
||||||
self.editor.mark_selected_text()
|
self.editor.mark_selected_text()
|
||||||
|
@ -537,9 +537,10 @@ def create_filterable_names_list(names, filter_text=None, parent=None):
|
|||||||
# Insert Link {{{
|
# Insert Link {{{
|
||||||
class InsertLink(Dialog):
|
class InsertLink(Dialog):
|
||||||
|
|
||||||
def __init__(self, container, source_name, parent=None):
|
def __init__(self, container, source_name, initial_text=None, parent=None):
|
||||||
self.container = container
|
self.container = container
|
||||||
self.source_name = source_name
|
self.source_name = source_name
|
||||||
|
self.initial_text = initial_text
|
||||||
Dialog.__init__(self, _('Insert Hyperlink'), 'insert-hyperlink', parent=parent)
|
Dialog.__init__(self, _('Insert Hyperlink'), 'insert-hyperlink', parent=parent)
|
||||||
self.anchor_cache = {}
|
self.anchor_cache = {}
|
||||||
|
|
||||||
@ -573,14 +574,18 @@ class InsertLink(Dialog):
|
|||||||
fnl.addWidget(la), fnl.addWidget(f), fnl.addWidget(fn)
|
fnl.addWidget(la), fnl.addWidget(f), fnl.addWidget(fn)
|
||||||
h.addLayout(fnl), h.setStretch(1, 1)
|
h.addLayout(fnl), h.setStretch(1, 1)
|
||||||
|
|
||||||
self.tl = tl = QHBoxLayout()
|
self.tl = tl = QFormLayout()
|
||||||
self.la3 = la = QLabel(_('&Target:'))
|
|
||||||
tl.addWidget(la)
|
|
||||||
self.target = t = QLineEdit(self)
|
self.target = t = QLineEdit(self)
|
||||||
la.setBuddy(t)
|
t.setPlaceholderText(_('The destination (href) for the link'))
|
||||||
tl.addWidget(t)
|
tl.addRow(_('&Target:'), t)
|
||||||
l.addLayout(tl)
|
l.addLayout(tl)
|
||||||
|
|
||||||
|
self.text_edit = t = QLineEdit(self)
|
||||||
|
la.setBuddy(t)
|
||||||
|
tl.addRow(_('Te&xt:'), t)
|
||||||
|
t.setText(self.initial_text or '')
|
||||||
|
t.setPlaceholderText(_('The (optional) text for the link'))
|
||||||
|
|
||||||
l.addWidget(self.bb)
|
l.addWidget(self.bb)
|
||||||
|
|
||||||
def selected_file_changed(self, *args):
|
def selected_file_changed(self, *args):
|
||||||
@ -622,6 +627,10 @@ class InsertLink(Dialog):
|
|||||||
def href(self):
|
def href(self):
|
||||||
return unicode(self.target.text()).strip()
|
return unicode(self.target.text()).strip()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self):
|
||||||
|
return unicode(self.text_edit.text()).strip()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def test(cls):
|
def test(cls):
|
||||||
import sys
|
import sys
|
||||||
@ -629,7 +638,7 @@ class InsertLink(Dialog):
|
|||||||
c = get_container(sys.argv[-1], tweak_mode=True)
|
c = get_container(sys.argv[-1], tweak_mode=True)
|
||||||
d = cls(c, next(c.spine_names)[0])
|
d = cls(c, next(c.spine_names)[0])
|
||||||
if d.exec_() == d.Accepted:
|
if d.exec_() == d.Accepted:
|
||||||
print (d.href)
|
print (d.href, d.text)
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user