Sun, 08 Jan 2017 18:52:16 +0100
Continued implementing a format button bar and provider classes for various markup languages.
--- a/QScintilla/EditorButtonsWidget.py Sun Jan 08 18:51:55 2017 +0100 +++ b/QScintilla/EditorButtonsWidget.py Sun Jan 08 18:52:16 2017 +0100 @@ -35,9 +35,10 @@ super(EditorButtonsWidget, self).__init__(parent) margin = 2 + spacing = 3 self.__layout = QVBoxLayout(self) self.__layout.setContentsMargins(margin, margin, margin, margin) - self.__layout.setSpacing(2) + self.__layout.setSpacing(spacing) self.__provider = None @@ -63,26 +64,46 @@ self.__separators = [] self.__headerMenu = QMenu() - self.__addButton("bold", "formatTextBold.png") - self.__addButton("italic", "formatTextItalic.png") - self.__addButton("strikethrough", "formatTextStrikethrough.png") + self.__addButton("bold", "formatTextBold.png", + self.tr("Bold")) + self.__addButton("italic", "formatTextItalic.png", + self.tr("Italic")) + self.__addButton("strikethrough", "formatTextStrikethrough.png", + self.tr("Strike Through")) self.__addSeparator() - self.__addButton("header1", "formatTextHeader1.png") - self.__addButton("header2", "formatTextHeader2.png") - self.__addButton("header3", "formatTextHeader3.png") - button = self.__addButton("header", "formatTextHeader.png") + self.__addButton("header1", "formatTextHeader1.png", + self.tr("Header 1")) + self.__addButton("header2", "formatTextHeader2.png", + self.tr("Header 2")) + self.__addButton("header3", "formatTextHeader3.png", + self.tr("Header 3")) + button = self.__addButton("header", "formatTextHeader.png", + self.tr("Header")) button.setPopupMode(QToolButton.InstantPopup) button.setMenu(self.__headerMenu) self.__addSeparator() - self.__addButton("code", "formatTextInlineCode.png") - self.__addButton("codeBlock", "formatTextCodeBlock.png") + self.__addButton("code", "formatTextInlineCode.png", + self.tr("Inline Code")) + self.__addButton("codeBlock", "formatTextCodeBlock.png", + self.tr("Code Block")) + self.__addButton("quote", "formatTextQuote.png", + self.tr("Quote")) self.__addSeparator() - self.__addButton("hyperlink", "formatTextHyperlink.png") - self.__addButton("line", "formatTextHorizontalLine.png") + self.__addButton("hyperlink", "formatTextHyperlink.png", + self.tr("Add Hyperlink")) + self.__addButton("line", "formatTextHorizontalLine.png", + self.tr("Add Horizontal Line")) + self.__addButton("image", "formatTextImage.png", + self.tr("Add Image")) + self.__addSeparator() + self.__addButton("bulletedList", "formatTextBulletedList.png", + self.tr("Add Bulleted List")) + self.__addButton("numberedList", "formatTextNumberedList.png", + self.tr("Add Numbered List")) self.__headerMenu.triggered.connect(self.__headerMenuTriggered) - def __addButton(self, format, iconName): + def __addButton(self, format, iconName, toolTip): """ Private method to add a format button. @@ -90,11 +111,14 @@ @type str @param iconName name of the icon for the button @type str + @param toolTip text for the tool tip + @type str @return generated button @rtype QToolButton """ button = QToolButton(self) button.setIcon(UI.PixmapCache.getIcon(iconName)) + button.setToolTip(toolTip) button.clicked.connect(lambda: self.__formatClicked(format)) self.__layout.addWidget(button) self.__buttons[format] = button @@ -174,10 +198,14 @@ self.__provider.code(self.__editor) elif format == "codeBlock": self.__provider.codeBlock(self.__editor) + elif format == "quote": + self.__provider.quote(self.__editor) elif format == "hyperlink": self.__provider.hyperlink(self.__editor) elif format == "line": self.__provider.line(self.__editor) + elif format == "image": + self.__provider.image(self.__editor) def __headerMenuTriggered(self, act): """ @@ -195,7 +223,12 @@ """ hasSelection = self.__editor.hasSelectedText() if self.__provider: + self.__buttons["quote"].setEnabled( + self.__provider.hasQuote() and ( + self.__provider.kind() == "html" or hasSelection)) self.__buttons["hyperlink"].setEnabled( self.__provider.hasHyperlink() and not hasSelection) self.__buttons["line"].setEnabled( self.__provider.hasLine() and not hasSelection) + self.__buttons["image"].setEnabled( + self.__provider.hasImage() and not hasSelection)
--- a/QScintilla/MarkupProviders/HtmlProvider.py Sun Jan 08 18:51:55 2017 +0100 +++ b/QScintilla/MarkupProviders/HtmlProvider.py Sun Jan 08 18:52:16 2017 +0100 @@ -158,7 +158,7 @@ editor.setCursorPosition(cline + 1, 0) editor.endUndoAction() - def __insertMarkup(self, markup, editor): + def __insertMarkup(self, markup, editor, addEol=False): """ Private method to insert the specified markup. @@ -170,18 +170,28 @@ @type str @param editor reference to the editor to work on @type Editor + @param addEol flag indicating to add an eol string after the tag + @type bool """ if editor is None: return + if addEol: + lineSeparator = editor.getLineSeparator() + else: + lineSeparator = "" editor.beginUndoAction() if editor.hasSelectedText(): - newText = "<{0}>{1}</{0}>".format(markup, editor.selectedText()) + newText = "<{0}>{2}{1}</{0}>{2}".format( + markup, editor.selectedText(), lineSeparator) editor.replaceSelectedText(newText) else: - editor.insert("<{0}></{0}>".format(markup)) + editor.insert("<{0}>{1}{1}</{0}>{1}".format(markup, lineSeparator)) cline, cindex = editor.getCursorPosition() - editor.setCursorPosition(cline, cindex + len(markup) + 2) + if addEol: + editor.setCursorPosition(cline + 1, 0) + else: + editor.setCursorPosition(cline, cindex + len(markup) + 2) editor.endUndoAction() def hasHyperlink(self): @@ -200,6 +210,9 @@ @param editor reference to the editor to work on @type Editor """ + if editor is None: + return + from .HyperlinkMarkupDialog import HyperlinkMarkupDialog dlg = HyperlinkMarkupDialog(True, False) if dlg.exec_() == QDialog.Accepted: @@ -244,3 +257,62 @@ cline, cindex = editor.getCursorPosition() editor.setCursorPosition(cline, cindex + len(markup)) editor.endUndoAction() + + def hasQuote(self): + """ + Public method to indicate the availability of block quote markup. + + @return flag indicating the availability of block quote markup + @rtype bool + """ + return True + + def quote(self, editor): + """ + Public method to generate block quote text. + + @param editor reference to the editor to work on + @type Editor + """ + self.__insertMarkup("blockquote", editor, True) + + def hasImage(self): + """ + Public method to indicate the availability of image markup. + + @return flag indicating the availability of image markup + @rtype bool + """ + return True + + def image(self, editor): + """ + Public method to generate image text. + + @param editor reference to the editor to work on + @type Editor + """ + if editor is None: + return + + from .ImageMarkupDialog import ImageMarkupDialog + dlg = ImageMarkupDialog(ImageMarkupDialog.HtmlMode) + if dlg.exec_() == QDialog.Accepted: + address, altText, title, originalSize, width, height = \ + dlg.getData() + + markup = '<img src="{0}"'.format(address) + if altText: + markup = '{0} alt="{1}"'.format(markup, altText) + if title: + markup = '{0} title="{1}"'.format(markup, title) + if not originalSize: + markup = '{0} width="{1}" height="{2}"'.format( + markup, width, height) + markup = '{0} />'.format(markup) + + editor.beginUndoAction() + editor.insert(markup) + cline, cindex = editor.getCursorPosition() + editor.setCursorPosition(cline, cindex + len(markup)) + editor.endUndoAction()
--- a/QScintilla/MarkupProviders/HyperlinkMarkupDialog.py Sun Jan 08 18:51:55 2017 +0100 +++ b/QScintilla/MarkupProviders/HyperlinkMarkupDialog.py Sun Jan 08 18:52:16 2017 +0100 @@ -42,6 +42,9 @@ self.titelEdit.setEnabled(not noTitle) self.__updateOkButton() + + msh = self.minimumSizeHint() + self.resize(max(self.width(), msh.width()), msh.height()) def __updateOkButton(self): """
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QScintilla/MarkupProviders/ImageMarkupDialog.py Sun Jan 08 18:52:16 2017 +0100 @@ -0,0 +1,218 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2017 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to enter data for an image markup. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSlot, QSize +from PyQt5.QtGui import QImage, QImageReader +from PyQt5.QtWidgets import QDialog, QDialogButtonBox + +from E5Gui.E5PathPicker import E5PathPickerModes + +from .Ui_ImageMarkupDialog import Ui_ImageMarkupDialog + + +class ImageMarkupDialog(QDialog, Ui_ImageMarkupDialog): + """ + Class implementing a dialog to enter data for an image markup. + """ + HtmlMode = 0 + MarkDownMode = 1 + RestMode = 2 + + def __init__(self, mode, parent=None): + """ + Constructor + + @param parent reference to the parent widget + @type QWidget + """ + super(ImageMarkupDialog, self).__init__(parent) + self.setupUi(self) + + if mode == ImageMarkupDialog.MarkDownMode: + self.sizeCheckBox.setEnabled(False) + self.aspectRatioCheckBox.setEnabled(False) + self.widthSpinBox.setEnabled(False) + self.heightSpinBox.setEnabled(False) + elif mode == ImageMarkupDialog.RestMode: + self.titleEdit.setEnabled(False) + + self.__mode = mode + self.__originalImageSize = QSize() + + filters = { + 'bmp': self.tr("Windows Bitmap File (*.bmp)"), + 'cur': self.tr("Windows Cursor File (*.cur)"), + 'dds': self.tr("DirectDraw-Surface File (*.dds)"), + 'gif': self.tr("Graphic Interchange Format File (*.gif)"), + 'icns': self.tr("Apple Icon File (*.icns)"), + 'ico': self.tr("Windows Icon File (*.ico)"), + 'jp2': self.tr("JPEG2000 File (*.jp2)"), + 'jpg': self.tr("JPEG File (*.jpg)"), + 'jpeg': self.tr("JPEG File (*.jpeg)"), + 'mng': self.tr("Multiple-Image Network Graphics File (*.mng)"), + 'pbm': self.tr("Portable Bitmap File (*.pbm)"), + 'pcx': self.tr("Paintbrush Bitmap File (*.pcx)"), + 'pgm': self.tr("Portable Graymap File (*.pgm)"), + 'png': self.tr("Portable Network Graphics File (*.png)"), + 'ppm': self.tr("Portable Pixmap File (*.ppm)"), + 'sgi': self.tr("Silicon Graphics Image File (*.sgi)"), + 'svg': self.tr("Scalable Vector Graphics File (*.svg)"), + 'svgz': self.tr("Compressed Scalable Vector Graphics File" + " (*.svgz)"), + 'tga': self.tr("Targa Graphic File (*.tga)"), + 'tif': self.tr("TIFF File (*.tif)"), + 'tiff': self.tr("TIFF File (*.tiff)"), + 'wbmp': self.tr("WAP Bitmap File (*.wbmp)"), + 'webp': self.tr("WebP Image File (*.webp)"), + 'xbm': self.tr("X11 Bitmap File (*.xbm)"), + 'xpm': self.tr("X11 Pixmap File (*.xpm)"), + } + + inputFormats = [] + readFormats = QImageReader.supportedImageFormats() + for readFormat in readFormats: + try: + inputFormats.append(filters[bytes(readFormat).decode()]) + except KeyError: + pass + inputFormats.sort() + inputFormats.append(self.tr("All Files (*)")) + if filters["png"] in inputFormats: + inputFormats.remove(filters["png"]) + inputFormats.insert(0, filters["png"]) + self.imagePicker.setFilters(';;'.join(inputFormats)) + self.imagePicker.setMode(E5PathPickerModes.OpenFileMode) + + self.sizeCheckBox.setChecked(True) + self.aspectRatioCheckBox.setChecked(True) + + msh = self.minimumSizeHint() + self.resize(max(self.width(), msh.width()), msh.height()) + + self.__updateOkButton() + + def __updateOkButton(self): + """ + Private slot to set the state of the OK button. + """ + enable = bool(self.imagePicker.text()) + if self.__mode == ImageMarkupDialog.MarkDownMode: + enable = enable and bool(self.altTextEdit.text()) + + self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enable) + + @pyqtSlot(str) + def on_imagePicker_textChanged(self, address): + """ + Private slot handling changes of the image path. + + @param address image address (URL or local path) + @type str + """ + if address and "://" not in address: + image = QImage(address) + # load the file to set the size spin boxes + if image.isNull(): + self.widthSpinBox.setValue(0) + self.heightSpinBox.setValue(0) + self.__originalImageSize = QSize() + self.__aspectRatio = 1 + else: + self.widthSpinBox.setValue(image.width()) + self.heightSpinBox.setValue(image.height()) + self.__originalImageSize = image.size() + self.__aspectRatio = \ + float(self.__originalImageSize.height()) / \ + self.__originalImageSize.width() + else: + self.widthSpinBox.setValue(0) + self.heightSpinBox.setValue(0) + self.__originalImageSize = QSize() + self.__aspectRatio = 1 + + self.__updateOkButton() + + @pyqtSlot(str) + def on_altTextEdit_textChanged(self, txt): + """ + Private slot handling changes of the alternative text. + + @param txt alternative text + @type str + """ + self.__updateOkButton() + + @pyqtSlot(bool) + def on_sizeCheckBox_toggled(self, checked): + """ + Public slot to reset the width and height spin boxes. + + @param checked flag indicating the state of the check box + @type bool + """ + if checked: + self.widthSpinBox.setValue(self.__originalImageSize.width()) + self.heightSpinBox.setValue(self.__originalImageSize.height()) + + @pyqtSlot(bool) + def on_aspectRatioCheckBox_toggled(self, checked): + """ + Public slot to adjust the height to match the original aspect ratio. + + @param checked flag indicating the state of the check box + @type bool + """ + if checked and self.__originalImageSize.isValid(): + height = self.widthSpinBox.value() * self.__aspectRatio + self.heightSpinBox.setValue(height) + + @pyqtSlot(int) + def on_widthSpinBox_valueChanged(self, width): + """ + Private slot to adjust the height spin box. + + @param width width for the image + @type int + """ + if self.aspectRatioCheckBox.isChecked() and \ + self.widthSpinBox.hasFocus(): + height = width * self.__aspectRatio + self.heightSpinBox.setValue(height) + + @pyqtSlot(int) + def on_heightSpinBox_valueChanged(self, height): + """ + Private slot to adjust the width spin box. + + @param height height for the image + @type int + """ + if self.aspectRatioCheckBox.isChecked() and \ + self.heightSpinBox.hasFocus(): + width = height / self.__aspectRatio + self.widthSpinBox.setValue(width) + + def getData(self): + """ + Public method to get the entered data. + + @return tuple containing the image address, alternative text, + title text, flag to keep the original size, width and height + @rtype tuple of (str, str, str, bool, int, int) + """ + return ( + self.imagePicker.text(), + self.altTextEdit.text(), + self.titleEdit.text(), + self.sizeCheckBox.isChecked(), + self.widthSpinBox.value(), + self.heightSpinBox.value(), + )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QScintilla/MarkupProviders/ImageMarkupDialog.ui Sun Jan 08 18:52:16 2017 +0100 @@ -0,0 +1,253 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ImageMarkupDialog</class> + <widget class="QDialog" name="ImageMarkupDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>231</height> + </rect> + </property> + <property name="windowTitle"> + <string>Add Image</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Image Address:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="E5PathPicker" name="imagePicker" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string>Enter the image path or URL</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Title:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="titleEdit"/> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Alternative Text:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="altTextEdit"/> + </item> + </layout> + </item> + <item> + <widget class="QCheckBox" name="sizeCheckBox"> + <property name="toolTip"> + <string/> + </property> + <property name="text"> + <string>Keep Original Size</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="aspectRatioCheckBox"> + <property name="text"> + <string>Keep Aspect Ratio</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Width:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="widthSpinBox"> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="suffix"> + <string> px</string> + </property> + <property name="maximum"> + <number>9999</number> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Height:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="heightSpinBox"> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="suffix"> + <string> px</string> + </property> + <property name="maximum"> + <number>9999</number> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>E5PathPicker</class> + <extends>QWidget</extends> + <header>E5Gui/E5PathPicker.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>imagePicker</tabstop> + <tabstop>titleEdit</tabstop> + <tabstop>altTextEdit</tabstop> + <tabstop>sizeCheckBox</tabstop> + <tabstop>aspectRatioCheckBox</tabstop> + <tabstop>widthSpinBox</tabstop> + <tabstop>heightSpinBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ImageMarkupDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>228</x> + <y>179</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>200</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ImageMarkupDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>296</x> + <y>185</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>200</y> + </hint> + </hints> + </connection> + <connection> + <sender>sizeCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>aspectRatioCheckBox</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>62</x> + <y>51</y> + </hint> + <hint type="destinationlabel"> + <x>63</x> + <y>76</y> + </hint> + </hints> + </connection> + <connection> + <sender>sizeCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>widthSpinBox</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>108</x> + <y>51</y> + </hint> + <hint type="destinationlabel"> + <x>105</x> + <y>103</y> + </hint> + </hints> + </connection> + <connection> + <sender>sizeCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>heightSpinBox</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>221</x> + <y>53</y> + </hint> + <hint type="destinationlabel"> + <x>223</x> + <y>103</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- a/QScintilla/MarkupProviders/MarkdownProvider.py Sun Jan 08 18:51:55 2017 +0100 +++ b/QScintilla/MarkupProviders/MarkdownProvider.py Sun Jan 08 18:52:16 2017 +0100 @@ -205,10 +205,13 @@ @param editor reference to the editor to work on @type Editor """ + if editor is None: + return + from .HyperlinkMarkupDialog import HyperlinkMarkupDialog dlg = HyperlinkMarkupDialog(False, True) if dlg.exec_() == QDialog.Accepted: - text, target, title = dlg.getData() + text, target, title = dlg.getData() link = "[{0}]".format(text) if target and title: @@ -250,3 +253,65 @@ cline, cindex = editor.getCursorPosition() editor.setCursorPosition(cline + 3, 0) editor.endUndoAction() + + def hasQuote(self): + """ + Public method to indicate the availability of block quote markup. + + @return flag indicating the availability of block quote markup + @rtype bool + """ + return True + + def quote(self, editor): + """ + Public method to generate block quote text. + + @param editor reference to the editor to work on + @type Editor + """ + if editor is None: + return + + editor.beginUndoAction() + markup = "> " + sline, sindex, eline, eindex = editor.getSelection() + for line in range(sline, eline + 1 if eindex > 0 else eline): + editor.insertAt(markup, line, 0) + editor.endUndoAction() + + def hasImage(self): + """ + Public method to indicate the availability of image markup. + + @return flag indicating the availability of image markup + @rtype bool + """ + return True + + def image(self, editor): + """ + Public method to generate image text. + + @param editor reference to the editor to work on + @type Editor + """ + if editor is None: + return + + from .ImageMarkupDialog import ImageMarkupDialog + dlg = ImageMarkupDialog(ImageMarkupDialog.MarkDownMode) + if dlg.exec_() == QDialog.Accepted: + address, altText, title, originalSize, width, height = \ + dlg.getData() + + if title: + markup = ''.format(altText, address, title) + else: + markup = ''.format(altText, address) + + editor.beginUndoAction() + editor.insert(markup) + cline, cindex = editor.getCursorPosition() + editor.setCursorPosition(cline, cindex + len(markup)) + editor.endUndoAction()
--- a/QScintilla/MarkupProviders/MarkupBase.py Sun Jan 08 18:51:55 2017 +0100 +++ b/QScintilla/MarkupProviders/MarkupBase.py Sun Jan 08 18:52:16 2017 +0100 @@ -178,4 +178,39 @@ @type Editor """ pass - + + def hasQuote(self): + """ + Public method to indicate the availability of block quote markup. + + @return flag indicating the availability of block quote markup + @rtype bool + """ + return False + + def quote(self, editor): + """ + Public method to generate block quote text. + + @param editor reference to the editor to work on + @type Editor + """ + pass + + def hasImage(self): + """ + Public method to indicate the availability of image markup. + + @return flag indicating the availability of image markup + @rtype bool + """ + return False + + def image(self, editor): + """ + Public method to generate image text. + + @param editor reference to the editor to work on + @type Editor + """ + pass
--- a/QScintilla/MarkupProviders/RestructuredTextProvider.py Sun Jan 08 18:51:55 2017 +0100 +++ b/QScintilla/MarkupProviders/RestructuredTextProvider.py Sun Jan 08 18:52:16 2017 +0100 @@ -94,6 +94,8 @@ editor.beginUndoAction() cline, cindex = editor.getCursorPosition() + if editor.hasSelection() and cindex == 0: + cline -= 1 lineSeparator = editor.getLineSeparator() if not editor.text(cline).endswith(lineSeparator): editor.insertAt(lineSeparator, cline, len(editor.text(cline))) @@ -200,6 +202,9 @@ @param editor reference to the editor to work on @type Editor """ + if editor is None: + return + from .HyperlinkMarkupDialog import HyperlinkMarkupDialog dlg = HyperlinkMarkupDialog(False, True, noTitle=True) if dlg.exec_() == QDialog.Accepted: @@ -268,3 +273,74 @@ cline, cindex = editor.getCursorPosition() editor.setCursorPosition(cline + 3, 0) editor.endUndoAction() + + def hasQuote(self): + """ + Public method to indicate the availability of block quote markup. + + @return flag indicating the availability of block quote markup + @rtype bool + """ + return True + + def quote(self, editor): + """ + Public method to generate block quote text. + + @param editor reference to the editor to work on + @type Editor + """ + if editor is None: + return + + lineSeparator = editor.getLineSeparator() + editor.beginUndoAction() + markup = "> " + sline, sindex, eline, eindex = editor.getSelection() + for line in range(sline, eline + 1 if eindex > 0 else eline): + editor.insertAt(markup, line, 0) + editor.insertAt("::{0}{0}".format(lineSeparator), sline, 0) + editor.setCursorPosition(eline + 2, eindex) + editor.endUndoAction() + + def hasImage(self): + """ + Public method to indicate the availability of image markup. + + @return flag indicating the availability of image markup + @rtype bool + """ + return True + + def image(self, editor): + """ + Public method to generate image text. + + @param editor reference to the editor to work on + @type Editor + """ + if editor is None: + return + + from .ImageMarkupDialog import ImageMarkupDialog + dlg = ImageMarkupDialog(ImageMarkupDialog.RestMode) + if dlg.exec_() == QDialog.Accepted: + address, altText, title, originalSize, width, height = \ + dlg.getData() + + lineSeparator = editor.getLineSeparator() + markup = ".. image:: {0}{1}".format(address, lineSeparator) + lines = 1 + if altText: + markup += " :alt: {0}{1}".format(altText, lineSeparator) + lines += 1 + if not originalSize: + markup += " :height: {0}px{1}".format(height, lineSeparator) + markup += " :width: {0}px{1}".format(width, lineSeparator) + lines += 2 + + editor.beginUndoAction() + editor.insert(markup) + cline, cindex = editor.getCursorPosition() + editor.setCursorPosition(cline + lines, 0) + editor.endUndoAction()
--- a/eric6.e4p Sun Jan 08 18:51:55 2017 +0100 +++ b/eric6.e4p Sun Jan 08 18:52:16 2017 +0100 @@ -884,6 +884,7 @@ <Source>QScintilla/Lexers/__init__.py</Source> <Source>QScintilla/MarkupProviders/HtmlProvider.py</Source> <Source>QScintilla/MarkupProviders/HyperlinkMarkupDialog.py</Source> + <Source>QScintilla/MarkupProviders/ImageMarkupDialog.py</Source> <Source>QScintilla/MarkupProviders/MarkdownProvider.py</Source> <Source>QScintilla/MarkupProviders/MarkupBase.py</Source> <Source>QScintilla/MarkupProviders/RestructuredTextProvider.py</Source> @@ -1827,6 +1828,7 @@ <Form>PyUnit/UnittestStacktraceDialog.ui</Form> <Form>QScintilla/GotoDialog.ui</Form> <Form>QScintilla/MarkupProviders/HyperlinkMarkupDialog.ui</Form> + <Form>QScintilla/MarkupProviders/ImageMarkupDialog.ui</Form> <Form>QScintilla/ReplaceWidget.ui</Form> <Form>QScintilla/SearchWidget.ui</Form> <Form>QScintilla/ShellHistoryDialog.ui</Form>